summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Carey <jcarey@argv.me>2015-09-14 16:19:11 -0400
committerJason Carey <jcarey@argv.me>2015-09-17 20:13:11 -0400
commit041e4fe737342bf40a6aedb7a04d8d99ba20e213 (patch)
tree148c21a538fd93bddf8a1982d463400d73984060
parent8291bbb3a6ec192d177076b1fb0cd28995e48440 (diff)
downloadmongo-041e4fe737342bf40a6aedb7a04d8d99ba20e213.tar.gz
SERVER-20375 Constrain JS method thisv
This constrains universal access to wraptype methods by providing a JS_ATTACH_JS_CONSTRAINED_METHOD() macro which allows for a list of types that are allowed to call said method. In this way we can lock down all methods without having to add uasserts to each individual method body.
-rw-r--r--jstests/core/type5.js22
-rw-r--r--src/mongo/scripting/mozjs/bindata.cpp25
-rw-r--r--src/mongo/scripting/mozjs/bindata.h12
-rw-r--r--src/mongo/scripting/mozjs/bson.cpp4
-rw-r--r--src/mongo/scripting/mozjs/bson.h2
-rw-r--r--src/mongo/scripting/mozjs/countdownlatch.cpp8
-rw-r--r--src/mongo/scripting/mozjs/countdownlatch.h8
-rw-r--r--src/mongo/scripting/mozjs/cursor.cpp17
-rw-r--r--src/mongo/scripting/mozjs/cursor.h8
-rw-r--r--src/mongo/scripting/mozjs/cursor_handle.cpp5
-rw-r--r--src/mongo/scripting/mozjs/cursor_handle.h2
-rw-r--r--src/mongo/scripting/mozjs/db.cpp4
-rw-r--r--src/mongo/scripting/mozjs/dbcollection.cpp2
-rw-r--r--src/mongo/scripting/mozjs/dbpointer.cpp4
-rw-r--r--src/mongo/scripting/mozjs/dbquery.cpp2
-rw-r--r--src/mongo/scripting/mozjs/dbref.cpp2
-rw-r--r--src/mongo/scripting/mozjs/exception.cpp2
-rw-r--r--src/mongo/scripting/mozjs/global.cpp6
-rw-r--r--src/mongo/scripting/mozjs/global.h6
-rw-r--r--src/mongo/scripting/mozjs/implscope.h82
-rw-r--r--src/mongo/scripting/mozjs/jsthread.cpp25
-rw-r--r--src/mongo/scripting/mozjs/jsthread.h14
-rw-r--r--src/mongo/scripting/mozjs/maxkey.cpp11
-rw-r--r--src/mongo/scripting/mozjs/maxkey.h2
-rw-r--r--src/mongo/scripting/mozjs/minkey.cpp11
-rw-r--r--src/mongo/scripting/mozjs/minkey.h2
-rw-r--r--src/mongo/scripting/mozjs/mongo.cpp85
-rw-r--r--src/mongo/scripting/mozjs/mongo.h34
-rw-r--r--src/mongo/scripting/mozjs/mongohelpers.cpp2
-rw-r--r--src/mongo/scripting/mozjs/nativefunction.cpp9
-rw-r--r--src/mongo/scripting/mozjs/nativefunction.h2
-rw-r--r--src/mongo/scripting/mozjs/numberdecimal.cpp9
-rw-r--r--src/mongo/scripting/mozjs/numberdecimal.h2
-rw-r--r--src/mongo/scripting/mozjs/numberint.cpp17
-rw-r--r--src/mongo/scripting/mozjs/numberint.h6
-rw-r--r--src/mongo/scripting/mozjs/numberlong.cpp21
-rw-r--r--src/mongo/scripting/mozjs/numberlong.h8
-rw-r--r--src/mongo/scripting/mozjs/object.cpp4
-rw-r--r--src/mongo/scripting/mozjs/object.h4
-rw-r--r--src/mongo/scripting/mozjs/objectwrapper.cpp14
-rw-r--r--src/mongo/scripting/mozjs/objectwrapper.h2
-rw-r--r--src/mongo/scripting/mozjs/oid.cpp7
-rw-r--r--src/mongo/scripting/mozjs/oid.h2
-rw-r--r--src/mongo/scripting/mozjs/timestamp.cpp2
-rw-r--r--src/mongo/scripting/mozjs/valuereader.cpp24
-rw-r--r--src/mongo/scripting/mozjs/valuewriter.cpp59
-rw-r--r--src/mongo/scripting/mozjs/valuewriter.h5
-rw-r--r--src/mongo/scripting/mozjs/wrapconstrainedmethod.h123
-rw-r--r--src/mongo/scripting/mozjs/wraptype.h75
49 files changed, 534 insertions, 270 deletions
diff --git a/jstests/core/type5.js b/jstests/core/type5.js
new file mode 100644
index 00000000000..414af2be7eb
--- /dev/null
+++ b/jstests/core/type5.js
@@ -0,0 +1,22 @@
+(function(){
+ "use strict";
+
+ // This checks SERVER-20375 - Constrain JS method thisv
+ //
+ // Check to make sure we can't invoke methods on incorrect types, or on
+ // prototypes of objects that aren't intended to have methods invoked on
+ // them.
+
+ assert.throws(function(){
+ HexData(0, "aaaa").hex.apply({});
+ }, [], "invoke method on object of incorrect type");
+ assert.throws(function(){
+ var x = HexData(0, "aaaa");
+ x.hex.apply(10);
+ }, [], "invoke method on incorrect type");
+ assert.throws(function(){
+ var x = HexData(0, "aaaa");
+ x.hex.apply(x.__proto__);
+ }, [], "invoke method on prototype of correct type");
+
+})();
diff --git a/src/mongo/scripting/mozjs/bindata.cpp b/src/mongo/scripting/mozjs/bindata.cpp
index 42ae6c1b491..e9f10cae125 100644
--- a/src/mongo/scripting/mozjs/bindata.cpp
+++ b/src/mongo/scripting/mozjs/bindata.cpp
@@ -37,6 +37,7 @@
#include "mongo/scripting/mozjs/objectwrapper.h"
#include "mongo/scripting/mozjs/valuereader.h"
#include "mongo/scripting/mozjs/valuewriter.h"
+#include "mongo/scripting/mozjs/wrapconstrainedmethod.h"
#include "mongo/util/base64.h"
#include "mongo/util/hex.h"
#include "mongo/util/mongoutils/str.h"
@@ -45,9 +46,9 @@ namespace mongo {
namespace mozjs {
const JSFunctionSpec BinDataInfo::methods[4] = {
- MONGO_ATTACH_JS_FUNCTION(base64),
- MONGO_ATTACH_JS_FUNCTION(hex),
- MONGO_ATTACH_JS_FUNCTION(toString),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(base64, BinDataInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(hex, BinDataInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(toString, BinDataInfo),
JS_FS_END,
};
@@ -89,7 +90,7 @@ void hexToBinData(JSContext* cx,
args[0].setInt32(type);
ValueReader(cx, args[1]).fromStringData(encoded);
- return scope->getBinDataProto().newInstance(args, out);
+ return scope->getProto<BinDataInfo>().newInstance(args, out);
}
std::string* getEncoded(JS::HandleValue thisv) {
@@ -110,7 +111,7 @@ void BinDataInfo::finalize(JSFreeOp* fop, JSObject* obj) {
}
}
-void BinDataInfo::Functions::UUID(JSContext* cx, JS::CallArgs args) {
+void BinDataInfo::Functions::UUID::call(JSContext* cx, JS::CallArgs args) {
if (args.length() != 1)
uasserted(ErrorCodes::BadValue, "UUID needs 1 argument");
@@ -123,7 +124,7 @@ void BinDataInfo::Functions::UUID(JSContext* cx, JS::CallArgs args) {
hexToBinData(cx, bdtUUID, arg, args.rval());
}
-void BinDataInfo::Functions::MD5(JSContext* cx, JS::CallArgs args) {
+void BinDataInfo::Functions::MD5::call(JSContext* cx, JS::CallArgs args) {
if (args.length() != 1)
uasserted(ErrorCodes::BadValue, "MD5 needs 1 argument");
@@ -136,7 +137,7 @@ void BinDataInfo::Functions::MD5(JSContext* cx, JS::CallArgs args) {
hexToBinData(cx, MD5Type, arg, args.rval());
}
-void BinDataInfo::Functions::HexData(JSContext* cx, JS::CallArgs args) {
+void BinDataInfo::Functions::HexData::call(JSContext* cx, JS::CallArgs args) {
if (args.length() != 2)
uasserted(ErrorCodes::BadValue, "HexData needs 2 arguments");
@@ -149,7 +150,7 @@ void BinDataInfo::Functions::HexData(JSContext* cx, JS::CallArgs args) {
hexToBinData(cx, type.toInt32(), args.get(1), args.rval());
}
-void BinDataInfo::Functions::toString(JSContext* cx, JS::CallArgs args) {
+void BinDataInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args) {
ObjectWrapper o(cx, args.thisv());
auto str = getEncoded(args.thisv());
@@ -161,16 +162,16 @@ void BinDataInfo::Functions::toString(JSContext* cx, JS::CallArgs args) {
ValueReader(cx, args.rval()).fromStringData(ss.operator std::string());
}
-void BinDataInfo::Functions::base64(JSContext* cx, JS::CallArgs args) {
+void BinDataInfo::Functions::base64::call(JSContext* cx, JS::CallArgs args) {
auto str = getEncoded(args.thisv());
ValueReader(cx, args.rval()).fromStringData(*str);
}
-void BinDataInfo::Functions::hex(JSContext* cx, JS::CallArgs args) {
+void BinDataInfo::Functions::hex::call(JSContext* cx, JS::CallArgs args) {
auto str = getEncoded(args.thisv());
- std::string data = base64::decode(*str);
+ std::string data = mongo::base64::decode(*str);
std::stringstream ss;
ss.setf(std::ios_base::hex, std::ios_base::basefield);
ss.fill('0');
@@ -208,7 +209,7 @@ void BinDataInfo::construct(JSContext* cx, JS::CallArgs args) {
auto tmpBase64 = base64::decode(str);
JS::RootedObject thisv(cx);
- scope->getBinDataProto().newObject(&thisv);
+ scope->getProto<BinDataInfo>().newObject(&thisv);
ObjectWrapper o(cx, thisv);
JS::RootedValue len(cx);
diff --git a/src/mongo/scripting/mozjs/bindata.h b/src/mongo/scripting/mozjs/bindata.h
index 85b504230ff..57a4f158949 100644
--- a/src/mongo/scripting/mozjs/bindata.h
+++ b/src/mongo/scripting/mozjs/bindata.h
@@ -43,13 +43,13 @@ struct BinDataInfo : public BaseInfo {
static void finalize(JSFreeOp* fop, JSObject* obj);
struct Functions {
- MONGO_DEFINE_JS_FUNCTION(base64);
- MONGO_DEFINE_JS_FUNCTION(hex);
- MONGO_DEFINE_JS_FUNCTION(toString);
+ MONGO_DECLARE_JS_FUNCTION(base64);
+ MONGO_DECLARE_JS_FUNCTION(hex);
+ MONGO_DECLARE_JS_FUNCTION(toString);
- MONGO_DEFINE_JS_FUNCTION(HexData);
- MONGO_DEFINE_JS_FUNCTION(MD5);
- MONGO_DEFINE_JS_FUNCTION(UUID);
+ MONGO_DECLARE_JS_FUNCTION(HexData);
+ MONGO_DECLARE_JS_FUNCTION(MD5);
+ MONGO_DECLARE_JS_FUNCTION(UUID);
};
static const JSFunctionSpec methods[4];
diff --git a/src/mongo/scripting/mozjs/bson.cpp b/src/mongo/scripting/mozjs/bson.cpp
index 9c972a6b3fc..2dd1d717dc3 100644
--- a/src/mongo/scripting/mozjs/bson.cpp
+++ b/src/mongo/scripting/mozjs/bson.cpp
@@ -75,7 +75,7 @@ BSONHolder* getHolder(JSObject* obj) {
void BSONInfo::make(JSContext* cx, JS::MutableHandleObject obj, BSONObj bson, bool ro) {
auto scope = getScope(cx);
- scope->getBsonProto().newObject(obj);
+ scope->getProto<BSONInfo>().newObject(obj);
JS_SetPrivate(obj, new BSONHolder(bson, ro));
}
@@ -202,7 +202,7 @@ std::tuple<BSONObj*, bool> BSONInfo::originalBSON(JSContext* cx, JS::HandleObjec
return out;
}
-void BSONInfo::Functions::bsonWoCompare(JSContext* cx, JS::CallArgs args) {
+void BSONInfo::Functions::bsonWoCompare::call(JSContext* cx, JS::CallArgs args) {
if (args.length() != 2)
uasserted(ErrorCodes::BadValue, "bsonWoCompare needs 2 argument");
diff --git a/src/mongo/scripting/mozjs/bson.h b/src/mongo/scripting/mozjs/bson.h
index 3b150801793..82e1e5d0cdb 100644
--- a/src/mongo/scripting/mozjs/bson.h
+++ b/src/mongo/scripting/mozjs/bson.h
@@ -63,7 +63,7 @@ struct BSONInfo : public BaseInfo {
static void postInstall(JSContext* cx, JS::HandleObject global, JS::HandleObject proto);
struct Functions {
- MONGO_DEFINE_JS_FUNCTION(bsonWoCompare);
+ MONGO_DECLARE_JS_FUNCTION(bsonWoCompare);
};
static const JSFunctionSpec freeFunctions[2];
diff --git a/src/mongo/scripting/mozjs/countdownlatch.cpp b/src/mongo/scripting/mozjs/countdownlatch.cpp
index bf7ae4ff551..9ca93be7618 100644
--- a/src/mongo/scripting/mozjs/countdownlatch.cpp
+++ b/src/mongo/scripting/mozjs/countdownlatch.cpp
@@ -130,7 +130,7 @@ namespace {
CountDownLatchHolder globalCountDownLatchHolder;
} // namespace
-void CountDownLatchInfo::Functions::_new(JSContext* cx, JS::CallArgs args) {
+void CountDownLatchInfo::Functions::_new::call(JSContext* cx, JS::CallArgs args) {
uassert(ErrorCodes::JSInterpreterFailure, "need exactly one argument", args.length() == 1);
uassert(
ErrorCodes::JSInterpreterFailure, "argument must be an integer", args.get(0).isNumber());
@@ -138,7 +138,7 @@ void CountDownLatchInfo::Functions::_new(JSContext* cx, JS::CallArgs args) {
args.rval().setInt32(globalCountDownLatchHolder.make(args.get(0).toNumber()));
}
-void CountDownLatchInfo::Functions::_await(JSContext* cx, JS::CallArgs args) {
+void CountDownLatchInfo::Functions::_await::call(JSContext* cx, JS::CallArgs args) {
uassert(ErrorCodes::JSInterpreterFailure, "need exactly one argument", args.length() == 1);
uassert(
ErrorCodes::JSInterpreterFailure, "argument must be an integer", args.get(0).isNumber());
@@ -148,7 +148,7 @@ void CountDownLatchInfo::Functions::_await(JSContext* cx, JS::CallArgs args) {
args.rval().setUndefined();
}
-void CountDownLatchInfo::Functions::_countDown(JSContext* cx, JS::CallArgs args) {
+void CountDownLatchInfo::Functions::_countDown::call(JSContext* cx, JS::CallArgs args) {
uassert(ErrorCodes::JSInterpreterFailure, "need exactly one argument", args.length() == 1);
uassert(
ErrorCodes::JSInterpreterFailure, "argument must be an integer", args.get(0).isNumber());
@@ -158,7 +158,7 @@ void CountDownLatchInfo::Functions::_countDown(JSContext* cx, JS::CallArgs args)
args.rval().setUndefined();
}
-void CountDownLatchInfo::Functions::_getCount(JSContext* cx, JS::CallArgs args) {
+void CountDownLatchInfo::Functions::_getCount::call(JSContext* cx, JS::CallArgs args) {
uassert(ErrorCodes::JSInterpreterFailure, "need exactly one argument", args.length() == 1);
uassert(
ErrorCodes::JSInterpreterFailure, "argument must be an integer", args.get(0).isNumber());
diff --git a/src/mongo/scripting/mozjs/countdownlatch.h b/src/mongo/scripting/mozjs/countdownlatch.h
index 07001ebf473..b13f26d69eb 100644
--- a/src/mongo/scripting/mozjs/countdownlatch.h
+++ b/src/mongo/scripting/mozjs/countdownlatch.h
@@ -43,10 +43,10 @@ namespace mozjs {
*/
struct CountDownLatchInfo : public BaseInfo {
struct Functions {
- MONGO_DEFINE_JS_FUNCTION(_new);
- MONGO_DEFINE_JS_FUNCTION(_await);
- MONGO_DEFINE_JS_FUNCTION(_countDown);
- MONGO_DEFINE_JS_FUNCTION(_getCount);
+ MONGO_DECLARE_JS_FUNCTION(_new);
+ MONGO_DECLARE_JS_FUNCTION(_await);
+ MONGO_DECLARE_JS_FUNCTION(_countDown);
+ MONGO_DECLARE_JS_FUNCTION(_getCount);
};
static const JSFunctionSpec methods[5];
diff --git a/src/mongo/scripting/mozjs/cursor.cpp b/src/mongo/scripting/mozjs/cursor.cpp
index 8660287a13a..7968480f4ff 100644
--- a/src/mongo/scripting/mozjs/cursor.cpp
+++ b/src/mongo/scripting/mozjs/cursor.cpp
@@ -34,15 +34,16 @@
#include "mongo/scripting/mozjs/implscope.h"
#include "mongo/scripting/mozjs/objectwrapper.h"
#include "mongo/scripting/mozjs/valuereader.h"
+#include "mongo/scripting/mozjs/wrapconstrainedmethod.h"
namespace mongo {
namespace mozjs {
const JSFunctionSpec CursorInfo::methods[5] = {
- MONGO_ATTACH_JS_FUNCTION(hasNext),
- MONGO_ATTACH_JS_FUNCTION(next),
- MONGO_ATTACH_JS_FUNCTION(objsLeftInBatch),
- MONGO_ATTACH_JS_FUNCTION(readOnly),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(hasNext, CursorInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(next, CursorInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(objsLeftInBatch, CursorInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(readOnly, CursorInfo),
JS_FS_END,
};
@@ -68,7 +69,7 @@ void CursorInfo::finalize(JSFreeOp* fop, JSObject* obj) {
}
}
-void CursorInfo::Functions::next(JSContext* cx, JS::CallArgs args) {
+void CursorInfo::Functions::next::call(JSContext* cx, JS::CallArgs args) {
auto cursor = getCursor(args);
if (!cursor) {
@@ -84,7 +85,7 @@ void CursorInfo::Functions::next(JSContext* cx, JS::CallArgs args) {
ValueReader(cx, args.rval()).fromBSON(bson, ro);
}
-void CursorInfo::Functions::hasNext(JSContext* cx, JS::CallArgs args) {
+void CursorInfo::Functions::hasNext::call(JSContext* cx, JS::CallArgs args) {
auto cursor = getCursor(args);
if (!cursor) {
@@ -95,7 +96,7 @@ void CursorInfo::Functions::hasNext(JSContext* cx, JS::CallArgs args) {
args.rval().setBoolean(cursor->more());
}
-void CursorInfo::Functions::objsLeftInBatch(JSContext* cx, JS::CallArgs args) {
+void CursorInfo::Functions::objsLeftInBatch::call(JSContext* cx, JS::CallArgs args) {
auto cursor = getCursor(args);
if (!cursor) {
@@ -106,7 +107,7 @@ void CursorInfo::Functions::objsLeftInBatch(JSContext* cx, JS::CallArgs args) {
args.rval().setInt32(cursor->objsLeftInBatch());
}
-void CursorInfo::Functions::readOnly(JSContext* cx, JS::CallArgs args) {
+void CursorInfo::Functions::readOnly::call(JSContext* cx, JS::CallArgs args) {
ObjectWrapper(cx, args.thisv()).setBoolean("_ro", true);
args.rval().set(args.thisv());
diff --git a/src/mongo/scripting/mozjs/cursor.h b/src/mongo/scripting/mozjs/cursor.h
index 87bd8e1de80..b354152a027 100644
--- a/src/mongo/scripting/mozjs/cursor.h
+++ b/src/mongo/scripting/mozjs/cursor.h
@@ -45,10 +45,10 @@ struct CursorInfo : public BaseInfo {
static void finalize(JSFreeOp* fop, JSObject* obj);
struct Functions {
- MONGO_DEFINE_JS_FUNCTION(hasNext);
- MONGO_DEFINE_JS_FUNCTION(next);
- MONGO_DEFINE_JS_FUNCTION(objsLeftInBatch);
- MONGO_DEFINE_JS_FUNCTION(readOnly);
+ MONGO_DECLARE_JS_FUNCTION(hasNext);
+ MONGO_DECLARE_JS_FUNCTION(next);
+ MONGO_DECLARE_JS_FUNCTION(objsLeftInBatch);
+ MONGO_DECLARE_JS_FUNCTION(readOnly);
};
static const JSFunctionSpec methods[5];
diff --git a/src/mongo/scripting/mozjs/cursor_handle.cpp b/src/mongo/scripting/mozjs/cursor_handle.cpp
index fcdc3dd525b..c74c7438331 100644
--- a/src/mongo/scripting/mozjs/cursor_handle.cpp
+++ b/src/mongo/scripting/mozjs/cursor_handle.cpp
@@ -33,13 +33,14 @@
#include "mongo/scripting/mozjs/cursor_handle.h"
#include "mongo/scripting/mozjs/implscope.h"
+#include "mongo/scripting/mozjs/wrapconstrainedmethod.h"
#include "mongo/util/log.h"
namespace mongo {
namespace mozjs {
const JSFunctionSpec CursorHandleInfo::methods[2] = {
- MONGO_ATTACH_JS_FUNCTION(zeroCursorId), JS_FS_END,
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(zeroCursorId, CursorHandleInfo), JS_FS_END,
};
const char* const CursorHandleInfo::className = "CursorHandle";
@@ -84,7 +85,7 @@ void CursorHandleInfo::finalize(JSFreeOp* fop, JSObject* obj) {
}
}
-void CursorHandleInfo::Functions::zeroCursorId(JSContext* cx, JS::CallArgs args) {
+void CursorHandleInfo::Functions::zeroCursorId::call(JSContext* cx, JS::CallArgs args) {
long long* cursorId = getCursorId(args);
if (cursorId) {
*cursorId = 0;
diff --git a/src/mongo/scripting/mozjs/cursor_handle.h b/src/mongo/scripting/mozjs/cursor_handle.h
index 792b382ae5e..71bc963d7c3 100644
--- a/src/mongo/scripting/mozjs/cursor_handle.h
+++ b/src/mongo/scripting/mozjs/cursor_handle.h
@@ -45,7 +45,7 @@ struct CursorHandleInfo : public BaseInfo {
static void finalize(JSFreeOp* fop, JSObject* obj);
struct Functions {
- MONGO_DEFINE_JS_FUNCTION(zeroCursorId);
+ MONGO_DECLARE_JS_FUNCTION(zeroCursorId);
};
static const JSFunctionSpec methods[2];
diff --git a/src/mongo/scripting/mozjs/db.cpp b/src/mongo/scripting/mozjs/db.cpp
index 851d6f3e49f..9a5d45b0984 100644
--- a/src/mongo/scripting/mozjs/db.cpp
+++ b/src/mongo/scripting/mozjs/db.cpp
@@ -100,7 +100,7 @@ void DBInfo::getProperty(JSContext* cx,
uassert(16861,
"getCollection returned something other than a collection",
- scope->getDbCollectionProto().instanceOf(coll));
+ scope->getProto<DBCollectionInfo>().instanceOf(coll));
// cache collection for reuse, don't enumerate
ObjectWrapper(cx, obj).defineProperty(sname.c_str(), coll, 0);
@@ -121,7 +121,7 @@ void DBInfo::construct(JSContext* cx, JS::CallArgs args) {
}
JS::RootedObject thisv(cx);
- scope->getDbProto().newObject(&thisv);
+ scope->getProto<DBInfo>().newObject(&thisv);
ObjectWrapper o(cx, thisv);
o.setValue("_mongo", args.get(0));
diff --git a/src/mongo/scripting/mozjs/dbcollection.cpp b/src/mongo/scripting/mozjs/dbcollection.cpp
index fd8bc086676..c4814251839 100644
--- a/src/mongo/scripting/mozjs/dbcollection.cpp
+++ b/src/mongo/scripting/mozjs/dbcollection.cpp
@@ -64,7 +64,7 @@ void DBCollectionInfo::construct(JSContext* cx, JS::CallArgs args) {
}
JS::RootedObject thisv(cx);
- scope->getDbCollectionProto().newObject(&thisv);
+ scope->getProto<DBCollectionInfo>().newObject(&thisv);
ObjectWrapper o(cx, thisv);
o.setValue("_mongo", args.get(0));
diff --git a/src/mongo/scripting/mozjs/dbpointer.cpp b/src/mongo/scripting/mozjs/dbpointer.cpp
index fbfb8282649..20c3882ba72 100644
--- a/src/mongo/scripting/mozjs/dbpointer.cpp
+++ b/src/mongo/scripting/mozjs/dbpointer.cpp
@@ -49,11 +49,11 @@ void DBPointerInfo::construct(JSContext* cx, JS::CallArgs args) {
if (!args.get(0).isString())
uasserted(ErrorCodes::BadValue, "DBPointer 1st parameter must be a string");
- if (!scope->getOidProto().instanceOf(args.get(1)))
+ if (!scope->getProto<OIDInfo>().instanceOf(args.get(1)))
uasserted(ErrorCodes::BadValue, "DBPointer 2nd parameter must be an ObjectId");
JS::RootedObject thisv(cx);
- scope->getDbPointerProto().newObject(&thisv);
+ scope->getProto<DBPointerInfo>().newObject(&thisv);
ObjectWrapper o(cx, thisv);
o.setValue("ns", args.get(0));
diff --git a/src/mongo/scripting/mozjs/dbquery.cpp b/src/mongo/scripting/mozjs/dbquery.cpp
index e9bddf4b30e..d3c68538884 100644
--- a/src/mongo/scripting/mozjs/dbquery.cpp
+++ b/src/mongo/scripting/mozjs/dbquery.cpp
@@ -46,7 +46,7 @@ void DBQueryInfo::construct(JSContext* cx, JS::CallArgs args) {
uasserted(ErrorCodes::BadValue, "dbQuery constructor requires at least 4 arguments");
JS::RootedObject thisv(cx);
- scope->getDbQueryProto().newObject(&thisv);
+ scope->getProto<DBQueryInfo>().newObject(&thisv);
ObjectWrapper o(cx, thisv);
o.setValue("_mongo", args.get(0));
diff --git a/src/mongo/scripting/mozjs/dbref.cpp b/src/mongo/scripting/mozjs/dbref.cpp
index 16ad0058084..4200ebaa67f 100644
--- a/src/mongo/scripting/mozjs/dbref.cpp
+++ b/src/mongo/scripting/mozjs/dbref.cpp
@@ -48,7 +48,7 @@ void DBRefInfo::construct(JSContext* cx, JS::CallArgs args) {
uasserted(ErrorCodes::BadValue, "DBRef 1st parameter must be a string");
JS::RootedObject thisv(cx);
- scope->getDbRefProto().newObject(&thisv);
+ scope->getProto<DBRefInfo>().newObject(&thisv);
ObjectWrapper o(cx, thisv);
o.setValue("$ref", args.get(0));
diff --git a/src/mongo/scripting/mozjs/exception.cpp b/src/mongo/scripting/mozjs/exception.cpp
index 8350d4f3ef1..28ab1545dac 100644
--- a/src/mongo/scripting/mozjs/exception.cpp
+++ b/src/mongo/scripting/mozjs/exception.cpp
@@ -79,7 +79,7 @@ std::string currentJSStackToString(JSContext* cx) {
auto scope = getScope(cx);
JS::RootedValue error(cx);
- scope->getErrorProto().newInstance(&error);
+ scope->getProto<ErrorInfo>().newInstance(&error);
return ObjectWrapper(cx, error).getString("stack");
}
diff --git a/src/mongo/scripting/mozjs/global.cpp b/src/mongo/scripting/mozjs/global.cpp
index d8c6da94e35..b3bdbec47b0 100644
--- a/src/mongo/scripting/mozjs/global.cpp
+++ b/src/mongo/scripting/mozjs/global.cpp
@@ -57,7 +57,7 @@ logger::MessageLogDomain* jsPrintLogDomain;
} // namespace
-void GlobalInfo::Functions::print(JSContext* cx, JS::CallArgs args) {
+void GlobalInfo::Functions::print::call(JSContext* cx, JS::CallArgs args) {
logger::LogstreamBuilder builder(jsPrintLogDomain, getThreadName(), logger::LogSeverity::Log());
std::ostream& ss = builder.stream();
@@ -82,11 +82,11 @@ void GlobalInfo::Functions::print(JSContext* cx, JS::CallArgs args) {
args.rval().setUndefined();
}
-void GlobalInfo::Functions::version(JSContext* cx, JS::CallArgs args) {
+void GlobalInfo::Functions::version::call(JSContext* cx, JS::CallArgs args) {
ValueReader(cx, args.rval()).fromStringData(JS_VersionToString(JS_GetVersion(cx)));
}
-void GlobalInfo::Functions::gc(JSContext* cx, JS::CallArgs args) {
+void GlobalInfo::Functions::gc::call(JSContext* cx, JS::CallArgs args) {
auto scope = getScope(cx);
scope->gc();
diff --git a/src/mongo/scripting/mozjs/global.h b/src/mongo/scripting/mozjs/global.h
index 1da83350137..8e002b57a90 100644
--- a/src/mongo/scripting/mozjs/global.h
+++ b/src/mongo/scripting/mozjs/global.h
@@ -41,9 +41,9 @@ namespace mozjs {
*/
struct GlobalInfo : public BaseInfo {
struct Functions {
- MONGO_DEFINE_JS_FUNCTION(gc);
- MONGO_DEFINE_JS_FUNCTION(print);
- MONGO_DEFINE_JS_FUNCTION(version);
+ MONGO_DECLARE_JS_FUNCTION(gc);
+ MONGO_DECLARE_JS_FUNCTION(print);
+ MONGO_DECLARE_JS_FUNCTION(version);
};
static const JSFunctionSpec freeFunctions[4];
diff --git a/src/mongo/scripting/mozjs/implscope.h b/src/mongo/scripting/mozjs/implscope.h
index a01365fa2d1..5b464d1461f 100644
--- a/src/mongo/scripting/mozjs/implscope.h
+++ b/src/mongo/scripting/mozjs/implscope.h
@@ -147,103 +147,135 @@ public:
BSONObj callThreadArgs(const BSONObj& obj);
- WrapType<BinDataInfo>& getBinDataProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, BinDataInfo>::value, WrapType<T>&>::type getProto() {
return _binDataProto;
}
- WrapType<BSONInfo>& getBsonProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, BSONInfo>::value, WrapType<T>&>::type getProto() {
return _bsonProto;
}
- WrapType<CountDownLatchInfo>& getCountDownLatchProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, CountDownLatchInfo>::value, WrapType<T>&>::type
+ getProto() {
return _countDownLatchProto;
}
- WrapType<CursorInfo>& getCursorProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, CursorInfo>::value, WrapType<T>&>::type getProto() {
return _cursorProto;
}
- WrapType<CursorHandleInfo>& getCursorHandleProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, CursorHandleInfo>::value, WrapType<T>&>::type
+ getProto() {
return _cursorHandleProto;
}
- WrapType<DBCollectionInfo>& getDbCollectionProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, DBCollectionInfo>::value, WrapType<T>&>::type
+ getProto() {
return _dbCollectionProto;
}
- WrapType<DBPointerInfo>& getDbPointerProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, DBPointerInfo>::value, WrapType<T>&>::type getProto() {
return _dbPointerProto;
}
- WrapType<DBQueryInfo>& getDbQueryProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, DBQueryInfo>::value, WrapType<T>&>::type getProto() {
return _dbQueryProto;
}
- WrapType<DBInfo>& getDbProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, DBInfo>::value, WrapType<T>&>::type getProto() {
return _dbProto;
}
- WrapType<DBRefInfo>& getDbRefProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, DBRefInfo>::value, WrapType<T>&>::type getProto() {
return _dbRefProto;
}
- WrapType<ErrorInfo>& getErrorProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, ErrorInfo>::value, WrapType<T>&>::type getProto() {
return _errorProto;
}
- WrapType<JSThreadInfo>& getJSThreadProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, JSThreadInfo>::value, WrapType<T>&>::type getProto() {
return _jsThreadProto;
}
- WrapType<MaxKeyInfo>& getMaxKeyProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, MaxKeyInfo>::value, WrapType<T>&>::type getProto() {
return _maxKeyProto;
}
- WrapType<MinKeyInfo>& getMinKeyProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, MinKeyInfo>::value, WrapType<T>&>::type getProto() {
return _minKeyProto;
}
- WrapType<MongoExternalInfo>& getMongoExternalProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, MongoExternalInfo>::value, WrapType<T>&>::type
+ getProto() {
return _mongoExternalProto;
}
- WrapType<MongoHelpersInfo>& getMongoHelpersProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, MongoHelpersInfo>::value, WrapType<T>&>::type
+ getProto() {
return _mongoHelpersProto;
}
- WrapType<MongoLocalInfo>& getMongoLocalProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, MongoLocalInfo>::value, WrapType<T>&>::type getProto() {
return _mongoLocalProto;
}
- WrapType<NativeFunctionInfo>& getNativeFunctionProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, NativeFunctionInfo>::value, WrapType<T>&>::type
+ getProto() {
return _nativeFunctionProto;
}
- WrapType<NumberIntInfo>& getNumberIntProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, NumberIntInfo>::value, WrapType<T>&>::type getProto() {
return _numberIntProto;
}
- WrapType<NumberLongInfo>& getNumberLongProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, NumberLongInfo>::value, WrapType<T>&>::type getProto() {
return _numberLongProto;
}
- WrapType<NumberDecimalInfo>& getNumberDecimalProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, NumberDecimalInfo>::value, WrapType<T>&>::type
+ getProto() {
return _numberDecimalProto;
}
- WrapType<ObjectInfo>& getObjectProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, ObjectInfo>::value, WrapType<T>&>::type getProto() {
return _objectProto;
}
- WrapType<OIDInfo>& getOidProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, OIDInfo>::value, WrapType<T>&>::type getProto() {
return _oidProto;
}
- WrapType<RegExpInfo>& getRegExpProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, RegExpInfo>::value, WrapType<T>&>::type getProto() {
return _regExpProto;
}
- WrapType<TimestampInfo>& getTimestampProto() {
+ template <typename T>
+ typename std::enable_if<std::is_same<T, TimestampInfo>::value, WrapType<T>&>::type getProto() {
return _timestampProto;
}
diff --git a/src/mongo/scripting/mozjs/jsthread.cpp b/src/mongo/scripting/mozjs/jsthread.cpp
index 0813a369dc2..3b457851efd 100644
--- a/src/mongo/scripting/mozjs/jsthread.cpp
+++ b/src/mongo/scripting/mozjs/jsthread.cpp
@@ -48,6 +48,8 @@
namespace mongo {
namespace mozjs {
+// These are all executed on some object that owns a js thread, rather than a
+// jsthread itself, so CONSTRAINED_METHOD doesn't do the job here.
const JSFunctionSpec JSThreadInfo::threadMethods[6] = {
MONGO_ATTACH_JS_FUNCTION(init),
MONGO_ATTACH_JS_FUNCTION(start),
@@ -211,7 +213,10 @@ JSThreadConfig* getConfig(JSContext* cx, JS::CallArgs args) {
ObjectWrapper(cx, args.thisv()).getValue("_JSThreadConfig", &value);
if (!value.isObject())
- uasserted(ErrorCodes::InternalError, "_JSThreadConfig not an object");
+ uasserted(ErrorCodes::BadValue, "_JSThreadConfig not an object");
+
+ if (!getScope(cx)->getProto<JSThreadInfo>().instanceOf(value))
+ uasserted(ErrorCodes::BadValue, "_JSThreadConfig is not a JSThread");
return static_cast<JSThreadConfig*>(JS_GetPrivate(value.toObjectOrNull()));
}
@@ -227,11 +232,11 @@ void JSThreadInfo::finalize(JSFreeOp* fop, JSObject* obj) {
delete config;
}
-void JSThreadInfo::Functions::init(JSContext* cx, JS::CallArgs args) {
+void JSThreadInfo::Functions::init::call(JSContext* cx, JS::CallArgs args) {
auto scope = getScope(cx);
JS::RootedObject obj(cx);
- scope->getJSThreadProto().newObject(&obj);
+ scope->getProto<JSThreadInfo>().newObject(&obj);
JSThreadConfig* config = new JSThreadConfig(cx, args);
JS_SetPrivate(obj, config);
@@ -240,28 +245,28 @@ void JSThreadInfo::Functions::init(JSContext* cx, JS::CallArgs args) {
args.rval().setUndefined();
}
-void JSThreadInfo::Functions::start(JSContext* cx, JS::CallArgs args) {
+void JSThreadInfo::Functions::start::call(JSContext* cx, JS::CallArgs args) {
getConfig(cx, args)->start();
args.rval().setUndefined();
}
-void JSThreadInfo::Functions::join(JSContext* cx, JS::CallArgs args) {
+void JSThreadInfo::Functions::join::call(JSContext* cx, JS::CallArgs args) {
getConfig(cx, args)->join();
args.rval().setUndefined();
}
-void JSThreadInfo::Functions::hasFailed(JSContext* cx, JS::CallArgs args) {
+void JSThreadInfo::Functions::hasFailed::call(JSContext* cx, JS::CallArgs args) {
args.rval().setBoolean(getConfig(cx, args)->hasFailed());
}
-void JSThreadInfo::Functions::returnData(JSContext* cx, JS::CallArgs args) {
+void JSThreadInfo::Functions::returnData::call(JSContext* cx, JS::CallArgs args) {
ValueReader(cx, args.rval())
.fromBSONElement(getConfig(cx, args)->returnData().firstElement(), true);
}
-void JSThreadInfo::Functions::_threadInject(JSContext* cx, JS::CallArgs args) {
+void JSThreadInfo::Functions::_threadInject::call(JSContext* cx, JS::CallArgs args) {
uassert(ErrorCodes::JSInterpreterFailure,
"threadInject takes exactly 1 argument",
args.length() == 1);
@@ -277,8 +282,8 @@ void JSThreadInfo::Functions::_threadInject(JSContext* cx, JS::CallArgs args) {
args.rval().setUndefined();
}
-void JSThreadInfo::Functions::_scopedThreadInject(JSContext* cx, JS::CallArgs args) {
- _threadInject(cx, args);
+void JSThreadInfo::Functions::_scopedThreadInject::call(JSContext* cx, JS::CallArgs args) {
+ _threadInject::call(cx, args);
}
} // namespace mozjs
diff --git a/src/mongo/scripting/mozjs/jsthread.h b/src/mongo/scripting/mozjs/jsthread.h
index ff468d987ab..2e6c0a70110 100644
--- a/src/mongo/scripting/mozjs/jsthread.h
+++ b/src/mongo/scripting/mozjs/jsthread.h
@@ -48,14 +48,14 @@ struct JSThreadInfo : public BaseInfo {
static void finalize(JSFreeOp* fop, JSObject* obj);
struct Functions {
- MONGO_DEFINE_JS_FUNCTION(init);
- MONGO_DEFINE_JS_FUNCTION(start);
- MONGO_DEFINE_JS_FUNCTION(join);
- MONGO_DEFINE_JS_FUNCTION(hasFailed);
- MONGO_DEFINE_JS_FUNCTION(returnData);
+ MONGO_DECLARE_JS_FUNCTION(init);
+ MONGO_DECLARE_JS_FUNCTION(start);
+ MONGO_DECLARE_JS_FUNCTION(join);
+ MONGO_DECLARE_JS_FUNCTION(hasFailed);
+ MONGO_DECLARE_JS_FUNCTION(returnData);
- MONGO_DEFINE_JS_FUNCTION(_threadInject);
- MONGO_DEFINE_JS_FUNCTION(_scopedThreadInject);
+ MONGO_DECLARE_JS_FUNCTION(_threadInject);
+ MONGO_DECLARE_JS_FUNCTION(_scopedThreadInject);
};
/**
diff --git a/src/mongo/scripting/mozjs/maxkey.cpp b/src/mongo/scripting/mozjs/maxkey.cpp
index 022ce347773..5fcf6c6f901 100644
--- a/src/mongo/scripting/mozjs/maxkey.cpp
+++ b/src/mongo/scripting/mozjs/maxkey.cpp
@@ -33,12 +33,13 @@
#include "mongo/scripting/mozjs/implscope.h"
#include "mongo/scripting/mozjs/objectwrapper.h"
#include "mongo/scripting/mozjs/valuereader.h"
+#include "mongo/scripting/mozjs/wrapconstrainedmethod.h"
namespace mongo {
namespace mozjs {
const JSFunctionSpec MaxKeyInfo::methods[2] = {
- MONGO_ATTACH_JS_FUNCTION(tojson), JS_FS_END,
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD(tojson, MaxKeyInfo), JS_FS_END,
};
const char* const MaxKeyInfo::className = "MaxKey";
@@ -59,13 +60,13 @@ void MaxKeyInfo::construct(JSContext* cx, JS::CallArgs args) {
void MaxKeyInfo::call(JSContext* cx, JS::CallArgs args) {
auto scope = getScope(cx);
- ObjectWrapper o(cx, scope->getMaxKeyProto().getProto());
+ ObjectWrapper o(cx, scope->getProto<MaxKeyInfo>().getProto());
JS::RootedValue val(cx);
if (!o.hasField(kSingleton)) {
JS::RootedObject thisv(cx);
- scope->getMaxKeyProto().newObject(&thisv);
+ scope->getProto<MaxKeyInfo>().newObject(&thisv);
val.setObjectOrNull(thisv);
o.setValue(kSingleton, val);
@@ -76,7 +77,7 @@ void MaxKeyInfo::call(JSContext* cx, JS::CallArgs args) {
args.rval().setObjectOrNull(val.toObjectOrNull());
}
-void MaxKeyInfo::Functions::tojson(JSContext* cx, JS::CallArgs args) {
+void MaxKeyInfo::Functions::tojson::call(JSContext* cx, JS::CallArgs args) {
ValueReader(cx, args.rval()).fromStringData("{ \"$maxKey\" : 1 }");
}
@@ -84,7 +85,7 @@ void MaxKeyInfo::postInstall(JSContext* cx, JS::HandleObject global, JS::HandleO
ObjectWrapper protoWrapper(cx, proto);
JS::RootedValue value(cx);
- getScope(cx)->getMaxKeyProto().newObject(&value);
+ getScope(cx)->getProto<MaxKeyInfo>().newObject(&value);
ObjectWrapper(cx, global).setValue("MaxKey", value);
protoWrapper.setValue(kSingleton, value);
diff --git a/src/mongo/scripting/mozjs/maxkey.h b/src/mongo/scripting/mozjs/maxkey.h
index ac5d937f157..3a1e4bc4d62 100644
--- a/src/mongo/scripting/mozjs/maxkey.h
+++ b/src/mongo/scripting/mozjs/maxkey.h
@@ -45,7 +45,7 @@ struct MaxKeyInfo : public BaseInfo {
static void construct(JSContext* cx, JS::CallArgs args);
struct Functions {
- MONGO_DEFINE_JS_FUNCTION(tojson);
+ MONGO_DECLARE_JS_FUNCTION(tojson);
};
static const JSFunctionSpec methods[2];
diff --git a/src/mongo/scripting/mozjs/minkey.cpp b/src/mongo/scripting/mozjs/minkey.cpp
index fe06fa6bb49..86ec71892f2 100644
--- a/src/mongo/scripting/mozjs/minkey.cpp
+++ b/src/mongo/scripting/mozjs/minkey.cpp
@@ -33,12 +33,13 @@
#include "mongo/scripting/mozjs/implscope.h"
#include "mongo/scripting/mozjs/objectwrapper.h"
#include "mongo/scripting/mozjs/valuereader.h"
+#include "mongo/scripting/mozjs/wrapconstrainedmethod.h"
namespace mongo {
namespace mozjs {
const JSFunctionSpec MinKeyInfo::methods[2] = {
- MONGO_ATTACH_JS_FUNCTION(tojson), JS_FS_END,
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD(tojson, MinKeyInfo), JS_FS_END,
};
const char* const MinKeyInfo::className = "MinKey";
@@ -59,13 +60,13 @@ void MinKeyInfo::construct(JSContext* cx, JS::CallArgs args) {
void MinKeyInfo::call(JSContext* cx, JS::CallArgs args) {
auto scope = getScope(cx);
- ObjectWrapper o(cx, scope->getMinKeyProto().getProto());
+ ObjectWrapper o(cx, scope->getProto<MinKeyInfo>().getProto());
JS::RootedValue val(cx);
if (!o.hasField(kSingleton)) {
JS::RootedObject thisv(cx);
- scope->getMinKeyProto().newObject(&thisv);
+ scope->getProto<MinKeyInfo>().newObject(&thisv);
val.setObjectOrNull(thisv);
o.setValue(kSingleton, val);
@@ -76,7 +77,7 @@ void MinKeyInfo::call(JSContext* cx, JS::CallArgs args) {
args.rval().setObjectOrNull(val.toObjectOrNull());
}
-void MinKeyInfo::Functions::tojson(JSContext* cx, JS::CallArgs args) {
+void MinKeyInfo::Functions::tojson::call(JSContext* cx, JS::CallArgs args) {
ValueReader(cx, args.rval()).fromStringData("{ \"$minKey\" : 1 }");
}
@@ -84,7 +85,7 @@ void MinKeyInfo::postInstall(JSContext* cx, JS::HandleObject global, JS::HandleO
ObjectWrapper protoWrapper(cx, proto);
JS::RootedValue value(cx);
- getScope(cx)->getMinKeyProto().newObject(&value);
+ getScope(cx)->getProto<MinKeyInfo>().newObject(&value);
ObjectWrapper(cx, global).setValue("MinKey", value);
protoWrapper.setValue(kSingleton, value);
diff --git a/src/mongo/scripting/mozjs/minkey.h b/src/mongo/scripting/mozjs/minkey.h
index caea91d54ac..e164bf108f7 100644
--- a/src/mongo/scripting/mozjs/minkey.h
+++ b/src/mongo/scripting/mozjs/minkey.h
@@ -45,7 +45,7 @@ struct MinKeyInfo : public BaseInfo {
static void construct(JSContext* cx, JS::CallArgs args);
struct Functions {
- MONGO_DEFINE_JS_FUNCTION(tojson);
+ MONGO_DECLARE_JS_FUNCTION(tojson);
};
static const JSFunctionSpec methods[2];
diff --git a/src/mongo/scripting/mozjs/mongo.cpp b/src/mongo/scripting/mozjs/mongo.cpp
index 2f1b41e91cd..bf99381de36 100644
--- a/src/mongo/scripting/mozjs/mongo.cpp
+++ b/src/mongo/scripting/mozjs/mongo.cpp
@@ -41,26 +41,33 @@
#include "mongo/scripting/mozjs/objectwrapper.h"
#include "mongo/scripting/mozjs/valuereader.h"
#include "mongo/scripting/mozjs/valuewriter.h"
+#include "mongo/scripting/mozjs/wrapconstrainedmethod.h"
#include "mongo/stdx/memory.h"
namespace mongo {
namespace mozjs {
const JSFunctionSpec MongoBase::methods[] = {
- MONGO_ATTACH_JS_FUNCTION(auth),
- MONGO_ATTACH_JS_FUNCTION(copyDatabaseWithSCRAM),
- MONGO_ATTACH_JS_FUNCTION(cursorFromId),
- MONGO_ATTACH_JS_FUNCTION(cursorHandleFromId),
- MONGO_ATTACH_JS_FUNCTION(find),
- MONGO_ATTACH_JS_FUNCTION(getClientRPCProtocols),
- MONGO_ATTACH_JS_FUNCTION(getServerRPCProtocols),
- MONGO_ATTACH_JS_FUNCTION(insert),
- MONGO_ATTACH_JS_FUNCTION(logout),
- MONGO_ATTACH_JS_FUNCTION(remove),
- MONGO_ATTACH_JS_FUNCTION(runCommand),
- MONGO_ATTACH_JS_FUNCTION(runCommandWithMetadata),
- MONGO_ATTACH_JS_FUNCTION(setClientRPCProtocols),
- MONGO_ATTACH_JS_FUNCTION(update),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(auth, MongoLocalInfo, MongoExternalInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(
+ copyDatabaseWithSCRAM, MongoLocalInfo, MongoExternalInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(cursorFromId, MongoLocalInfo, MongoExternalInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(
+ cursorHandleFromId, MongoLocalInfo, MongoExternalInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(find, MongoLocalInfo, MongoExternalInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(
+ getClientRPCProtocols, MongoLocalInfo, MongoExternalInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(
+ getServerRPCProtocols, MongoLocalInfo, MongoExternalInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(insert, MongoLocalInfo, MongoExternalInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(logout, MongoLocalInfo, MongoExternalInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(remove, MongoLocalInfo, MongoExternalInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(runCommand, MongoLocalInfo, MongoExternalInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(
+ runCommandWithMetadata, MongoLocalInfo, MongoExternalInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(
+ setClientRPCProtocols, MongoLocalInfo, MongoExternalInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(update, MongoLocalInfo, MongoExternalInfo),
JS_FS_END,
};
@@ -106,7 +113,7 @@ void MongoBase::finalize(JSFreeOp* fop, JSObject* obj) {
}
}
-void MongoBase::Functions::runCommand(JSContext* cx, JS::CallArgs args) {
+void MongoBase::Functions::runCommand::call(JSContext* cx, JS::CallArgs args) {
if (args.length() != 3)
uasserted(ErrorCodes::BadValue, "runCommand needs 3 args");
@@ -133,7 +140,7 @@ void MongoBase::Functions::runCommand(JSContext* cx, JS::CallArgs args) {
ValueReader(cx, args.rval()).fromBSON(cmdRes, false /* read only */);
}
-void MongoBase::Functions::runCommandWithMetadata(JSContext* cx, JS::CallArgs args) {
+void MongoBase::Functions::runCommandWithMetadata::call(JSContext* cx, JS::CallArgs args) {
if (args.length() != 4)
uasserted(ErrorCodes::BadValue, "runCommandWithMetadata needs 4 args");
@@ -169,7 +176,7 @@ void MongoBase::Functions::runCommandWithMetadata(JSContext* cx, JS::CallArgs ar
ValueReader(cx, args.rval()).fromBSON(mergedResult, false);
}
-void MongoBase::Functions::find(JSContext* cx, JS::CallArgs args) {
+void MongoBase::Functions::find::call(JSContext* cx, JS::CallArgs args) {
auto scope = getScope(cx);
if (args.length() != 7)
@@ -213,14 +220,14 @@ void MongoBase::Functions::find(JSContext* cx, JS::CallArgs args) {
}
JS::RootedObject c(cx);
- scope->getCursorProto().newObject(&c);
+ scope->getProto<CursorInfo>().newObject(&c);
setCursor(c, std::move(cursor), args);
args.rval().setObjectOrNull(c);
}
-void MongoBase::Functions::insert(JSContext* cx, JS::CallArgs args) {
+void MongoBase::Functions::insert::call(JSContext* cx, JS::CallArgs args) {
auto scope = getScope(cx);
if (args.length() != 3)
@@ -250,7 +257,7 @@ void MongoBase::Functions::insert(JSContext* cx, JS::CallArgs args) {
if (!ele.hasField("_id")) {
JS::RootedValue value(cx);
- scope->getOidProto().newInstance(&value);
+ scope->getProto<OIDInfo>().newInstance(&value);
ele.setValue("_id", value);
}
@@ -285,7 +292,7 @@ void MongoBase::Functions::insert(JSContext* cx, JS::CallArgs args) {
args.rval().setUndefined();
}
-void MongoBase::Functions::remove(JSContext* cx, JS::CallArgs args) {
+void MongoBase::Functions::remove::call(JSContext* cx, JS::CallArgs args) {
if (!(args.length() == 2 || args.length() == 3))
uasserted(ErrorCodes::BadValue, "remove needs 2 or 3 args");
@@ -311,7 +318,7 @@ void MongoBase::Functions::remove(JSContext* cx, JS::CallArgs args) {
args.rval().setUndefined();
}
-void MongoBase::Functions::update(JSContext* cx, JS::CallArgs args) {
+void MongoBase::Functions::update::call(JSContext* cx, JS::CallArgs args) {
if (args.length() < 3)
uasserted(ErrorCodes::BadValue, "update needs at least 3 args");
@@ -339,7 +346,7 @@ void MongoBase::Functions::update(JSContext* cx, JS::CallArgs args) {
args.rval().setUndefined();
}
-void MongoBase::Functions::auth(JSContext* cx, JS::CallArgs args) {
+void MongoBase::Functions::auth::call(JSContext* cx, JS::CallArgs args) {
auto conn = getConnection(args);
if (!conn)
uasserted(ErrorCodes::BadValue, "no connection");
@@ -365,7 +372,7 @@ void MongoBase::Functions::auth(JSContext* cx, JS::CallArgs args) {
args.rval().setBoolean(true);
}
-void MongoBase::Functions::logout(JSContext* cx, JS::CallArgs args) {
+void MongoBase::Functions::logout::call(JSContext* cx, JS::CallArgs args) {
if (args.length() != 1)
uasserted(ErrorCodes::BadValue, "logout needs 1 arg");
@@ -381,13 +388,13 @@ void MongoBase::Functions::logout(JSContext* cx, JS::CallArgs args) {
ValueReader(cx, args.rval()).fromBSON(ret, false);
}
-void MongoBase::Functions::cursorFromId(JSContext* cx, JS::CallArgs args) {
+void MongoBase::Functions::cursorFromId::call(JSContext* cx, JS::CallArgs args) {
auto scope = getScope(cx);
if (!(args.length() == 2 || args.length() == 3))
uasserted(ErrorCodes::BadValue, "cursorFromId needs 2 or 3 args");
- if (!scope->getNumberLongProto().instanceOf(args.get(1)))
+ if (!scope->getProto<NumberLongInfo>().instanceOf(args.get(1)))
uasserted(ErrorCodes::BadValue, "2nd arg must be a NumberLong");
if (!(args.get(2).isNumber() || args.get(2).isUndefined()))
@@ -405,34 +412,34 @@ void MongoBase::Functions::cursorFromId(JSContext* cx, JS::CallArgs args) {
cursor->setBatchSize(ValueWriter(cx, args.get(2)).toInt32());
JS::RootedObject c(cx);
- scope->getCursorProto().newObject(&c);
+ scope->getProto<CursorInfo>().newObject(&c);
setCursor(c, std::move(cursor), args);
args.rval().setObjectOrNull(c);
}
-void MongoBase::Functions::cursorHandleFromId(JSContext* cx, JS::CallArgs args) {
+void MongoBase::Functions::cursorHandleFromId::call(JSContext* cx, JS::CallArgs args) {
auto scope = getScope(cx);
if (args.length() != 1) {
uasserted(ErrorCodes::BadValue, "cursorHandleFromId needs 1 arg");
}
- if (!scope->getNumberLongProto().instanceOf(args.get(0))) {
+ if (!scope->getProto<NumberLongInfo>().instanceOf(args.get(0))) {
uasserted(ErrorCodes::BadValue, "1st arg must be a NumberLong");
}
long long cursorId = NumberLongInfo::ToNumberLong(cx, args.get(0));
JS::RootedObject c(cx);
- scope->getCursorHandleProto().newObject(&c);
+ scope->getProto<CursorHandleInfo>().newObject(&c);
setCursorHandle(c, cursorId, args);
args.rval().setObjectOrNull(c);
}
-void MongoBase::Functions::copyDatabaseWithSCRAM(JSContext* cx, JS::CallArgs args) {
+void MongoBase::Functions::copyDatabaseWithSCRAM::call(JSContext* cx, JS::CallArgs args) {
auto conn = getConnection(args);
if (!conn)
@@ -516,7 +523,7 @@ void MongoBase::Functions::copyDatabaseWithSCRAM(JSContext* cx, JS::CallArgs arg
ValueReader(cx, args.rval()).fromBSON(inputObj, true);
}
-void MongoBase::Functions::getClientRPCProtocols(JSContext* cx, JS::CallArgs args) {
+void MongoBase::Functions::getClientRPCProtocols::call(JSContext* cx, JS::CallArgs args) {
auto conn = getConnection(args);
if (args.length() != 0)
@@ -530,7 +537,7 @@ void MongoBase::Functions::getClientRPCProtocols(JSContext* cx, JS::CallArgs arg
ValueReader(cx, args.rval()).fromStringData(protoStr);
}
-void MongoBase::Functions::setClientRPCProtocols(JSContext* cx, JS::CallArgs args) {
+void MongoBase::Functions::setClientRPCProtocols::call(JSContext* cx, JS::CallArgs args) {
auto conn = getConnection(args);
if (args.length() != 1)
@@ -548,7 +555,7 @@ void MongoBase::Functions::setClientRPCProtocols(JSContext* cx, JS::CallArgs arg
args.rval().setUndefined();
}
-void MongoBase::Functions::getServerRPCProtocols(JSContext* cx, JS::CallArgs args) {
+void MongoBase::Functions::getServerRPCProtocols::call(JSContext* cx, JS::CallArgs args) {
auto conn = getConnection(args);
if (args.length() != 0)
@@ -573,7 +580,7 @@ void MongoLocalInfo::construct(JSContext* cx, JS::CallArgs args) {
conn.reset(createDirectClient(scope->getOpContext()));
JS::RootedObject thisv(cx);
- scope->getMongoLocalProto().newObject(&thisv);
+ scope->getProto<MongoLocalInfo>().newObject(&thisv);
ObjectWrapper o(cx, thisv);
JS_SetPrivate(thisv, new std::shared_ptr<DBClientBase>(conn.release()));
@@ -606,7 +613,7 @@ void MongoExternalInfo::construct(JSContext* cx, JS::CallArgs args) {
}
JS::RootedObject thisv(cx);
- scope->getMongoExternalProto().newObject(&thisv);
+ scope->getProto<MongoExternalInfo>().newObject(&thisv);
ObjectWrapper o(cx, thisv);
JS_SetPrivate(thisv, new std::shared_ptr<DBClientBase>(conn.release()));
@@ -617,7 +624,7 @@ void MongoExternalInfo::construct(JSContext* cx, JS::CallArgs args) {
args.rval().setObjectOrNull(thisv);
}
-void MongoExternalInfo::Functions::load(JSContext* cx, JS::CallArgs args) {
+void MongoExternalInfo::Functions::load::call(JSContext* cx, JS::CallArgs args) {
auto scope = getScope(cx);
for (unsigned i = 0; i < args.length(); ++i) {
@@ -631,7 +638,7 @@ void MongoExternalInfo::Functions::load(JSContext* cx, JS::CallArgs args) {
args.rval().setBoolean(true);
}
-void MongoExternalInfo::Functions::quit(JSContext* cx, JS::CallArgs args) {
+void MongoExternalInfo::Functions::quit::call(JSContext* cx, JS::CallArgs args) {
auto scope = getScope(cx);
scope->setQuickExit(args.get(0).isNumber() ? args.get(0).toNumber() : 0);
@@ -639,7 +646,7 @@ void MongoExternalInfo::Functions::quit(JSContext* cx, JS::CallArgs args) {
uasserted(ErrorCodes::JSUncatchableError, "Calling Quit");
}
-void MongoExternalInfo::Functions::_forgetReplSet(JSContext* cx, JS::CallArgs args) {
+void MongoExternalInfo::Functions::_forgetReplSet::call(JSContext* cx, JS::CallArgs args) {
if (args.length() != 1) {
uasserted(ErrorCodes::BadValue,
str::stream() << "_forgetReplSet takes exactly 1 argument, but was given "
diff --git a/src/mongo/scripting/mozjs/mongo.h b/src/mongo/scripting/mozjs/mongo.h
index a5fc7921e92..77a1c17bff2 100644
--- a/src/mongo/scripting/mozjs/mongo.h
+++ b/src/mongo/scripting/mozjs/mongo.h
@@ -44,20 +44,20 @@ struct MongoBase : public BaseInfo {
static void finalize(JSFreeOp* fop, JSObject* obj);
struct Functions {
- MONGO_DEFINE_JS_FUNCTION(auth);
- MONGO_DEFINE_JS_FUNCTION(copyDatabaseWithSCRAM);
- MONGO_DEFINE_JS_FUNCTION(cursorFromId);
- MONGO_DEFINE_JS_FUNCTION(cursorHandleFromId);
- MONGO_DEFINE_JS_FUNCTION(find);
- MONGO_DEFINE_JS_FUNCTION(getClientRPCProtocols);
- MONGO_DEFINE_JS_FUNCTION(getServerRPCProtocols);
- MONGO_DEFINE_JS_FUNCTION(insert);
- MONGO_DEFINE_JS_FUNCTION(logout);
- MONGO_DEFINE_JS_FUNCTION(remove);
- MONGO_DEFINE_JS_FUNCTION(runCommand);
- MONGO_DEFINE_JS_FUNCTION(runCommandWithMetadata);
- MONGO_DEFINE_JS_FUNCTION(setClientRPCProtocols);
- MONGO_DEFINE_JS_FUNCTION(update);
+ MONGO_DECLARE_JS_FUNCTION(auth);
+ MONGO_DECLARE_JS_FUNCTION(copyDatabaseWithSCRAM);
+ MONGO_DECLARE_JS_FUNCTION(cursorFromId);
+ MONGO_DECLARE_JS_FUNCTION(cursorHandleFromId);
+ MONGO_DECLARE_JS_FUNCTION(find);
+ MONGO_DECLARE_JS_FUNCTION(getClientRPCProtocols);
+ MONGO_DECLARE_JS_FUNCTION(getServerRPCProtocols);
+ MONGO_DECLARE_JS_FUNCTION(insert);
+ MONGO_DECLARE_JS_FUNCTION(logout);
+ MONGO_DECLARE_JS_FUNCTION(remove);
+ MONGO_DECLARE_JS_FUNCTION(runCommand);
+ MONGO_DECLARE_JS_FUNCTION(runCommandWithMetadata);
+ MONGO_DECLARE_JS_FUNCTION(setClientRPCProtocols);
+ MONGO_DECLARE_JS_FUNCTION(update);
};
static const JSFunctionSpec methods[15];
@@ -80,9 +80,9 @@ struct MongoExternalInfo : public MongoBase {
static void construct(JSContext* cx, JS::CallArgs args);
struct Functions {
- MONGO_DEFINE_JS_FUNCTION(_forgetReplSet);
- MONGO_DEFINE_JS_FUNCTION(load);
- MONGO_DEFINE_JS_FUNCTION(quit);
+ MONGO_DECLARE_JS_FUNCTION(_forgetReplSet);
+ MONGO_DECLARE_JS_FUNCTION(load);
+ MONGO_DECLARE_JS_FUNCTION(quit);
};
static const JSFunctionSpec freeFunctions[4];
diff --git a/src/mongo/scripting/mozjs/mongohelpers.cpp b/src/mongo/scripting/mozjs/mongohelpers.cpp
index b27163ce7a3..7215c5aa605 100644
--- a/src/mongo/scripting/mozjs/mongohelpers.cpp
+++ b/src/mongo/scripting/mozjs/mongohelpers.cpp
@@ -57,7 +57,7 @@ std::string parseJSFunctionOrExpression(JSContext* cx, const StringData input) {
JS::RootedValue jsStrIn(cx);
ValueReader(cx, &jsStrIn).fromStringData(input);
- ObjectWrapper helpersWrapper(cx, getScope(cx)->getMongoHelpersProto().getProto());
+ ObjectWrapper helpersWrapper(cx, getScope(cx)->getProto<MongoHelpersInfo>().getProto());
helpersWrapper.callMethod("functionExpressionParser", JS::HandleValueArray(jsStrIn), &jsStrOut);
diff --git a/src/mongo/scripting/mozjs/nativefunction.cpp b/src/mongo/scripting/mozjs/nativefunction.cpp
index 5ffdc5f902d..ef5423f0f21 100644
--- a/src/mongo/scripting/mozjs/nativefunction.cpp
+++ b/src/mongo/scripting/mozjs/nativefunction.cpp
@@ -36,6 +36,7 @@
#include "mongo/scripting/mozjs/objectwrapper.h"
#include "mongo/scripting/mozjs/valuereader.h"
#include "mongo/scripting/mozjs/valuewriter.h"
+#include "mongo/scripting/mozjs/wrapconstrainedmethod.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
@@ -45,7 +46,7 @@ const char* const NativeFunctionInfo::inheritFrom = "Function";
const char* const NativeFunctionInfo::className = "NativeFunction";
const JSFunctionSpec NativeFunctionInfo::methods[2] = {
- MONGO_ATTACH_JS_FUNCTION(toString), JS_FS_END,
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD(toString, NativeFunctionInfo), JS_FS_END,
};
namespace {
@@ -70,7 +71,7 @@ NativeHolder* getHolder(JS::CallArgs args) {
void NativeFunctionInfo::call(JSContext* cx, JS::CallArgs args) {
auto holder = getHolder(args);
- if (! holder) {
+ if (!holder) {
// Calling the prototype
args.rval().setUndefined();
return;
@@ -99,7 +100,7 @@ void NativeFunctionInfo::finalize(JSFreeOp* fop, JSObject* obj) {
delete holder;
}
-void NativeFunctionInfo::Functions::toString(JSContext* cx, JS::CallArgs args) {
+void NativeFunctionInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args) {
ObjectWrapper o(cx, args.thisv());
str::stream ss;
@@ -115,7 +116,7 @@ void NativeFunctionInfo::make(JSContext* cx,
void* data) {
auto scope = getScope(cx);
- scope->getNativeFunctionProto().newObject(obj);
+ scope->getProto<NativeFunctionInfo>().newObject(obj);
JS_SetPrivate(obj, new NativeHolder(function, data));
}
diff --git a/src/mongo/scripting/mozjs/nativefunction.h b/src/mongo/scripting/mozjs/nativefunction.h
index 6a676a180cf..8b818e03512 100644
--- a/src/mongo/scripting/mozjs/nativefunction.h
+++ b/src/mongo/scripting/mozjs/nativefunction.h
@@ -57,7 +57,7 @@ struct NativeFunctionInfo : public BaseInfo {
static const InstallType installType = InstallType::Private;
struct Functions {
- MONGO_DEFINE_JS_FUNCTION(toString);
+ MONGO_DECLARE_JS_FUNCTION(toString);
};
static const JSFunctionSpec methods[2];
diff --git a/src/mongo/scripting/mozjs/numberdecimal.cpp b/src/mongo/scripting/mozjs/numberdecimal.cpp
index 1891a67a45b..a845b3bb99d 100644
--- a/src/mongo/scripting/mozjs/numberdecimal.cpp
+++ b/src/mongo/scripting/mozjs/numberdecimal.cpp
@@ -35,6 +35,7 @@
#include "mongo/scripting/mozjs/objectwrapper.h"
#include "mongo/scripting/mozjs/valuereader.h"
#include "mongo/scripting/mozjs/valuewriter.h"
+#include "mongo/scripting/mozjs/wrapconstrainedmethod.h"
#include "mongo/util/mongoutils/str.h"
#include "mongo/util/text.h"
@@ -42,7 +43,7 @@ namespace mongo {
namespace mozjs {
const JSFunctionSpec NumberDecimalInfo::methods[2] = {
- MONGO_ATTACH_JS_FUNCTION(toString), JS_FS_END,
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD(toString, NumberDecimalInfo), JS_FS_END,
};
const char* const NumberDecimalInfo::className = "NumberDecimal";
@@ -66,7 +67,7 @@ Decimal128 NumberDecimalInfo::ToNumberDecimal(JSContext* cx, JS::HandleObject th
return x ? *x : Decimal128(0);
}
-void NumberDecimalInfo::Functions::toString(JSContext* cx, JS::CallArgs args) {
+void NumberDecimalInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args) {
Decimal128 val = NumberDecimalInfo::ToNumberDecimal(cx, args.thisv());
str::stream ss;
@@ -80,7 +81,7 @@ void NumberDecimalInfo::construct(JSContext* cx, JS::CallArgs args) {
JS::RootedObject thisv(cx);
- scope->getNumberDecimalProto().newObject(&thisv);
+ scope->getProto<NumberDecimalInfo>().newObject(&thisv);
Decimal128 x(0);
@@ -100,7 +101,7 @@ void NumberDecimalInfo::construct(JSContext* cx, JS::CallArgs args) {
void NumberDecimalInfo::make(JSContext* cx, JS::MutableHandleValue thisv, Decimal128 decimal) {
auto scope = getScope(cx);
- scope->getNumberDecimalProto().newInstance(thisv);
+ scope->getProto<NumberDecimalInfo>().newInstance(thisv);
JS_SetPrivate(thisv.toObjectOrNull(), new Decimal128(decimal));
}
diff --git a/src/mongo/scripting/mozjs/numberdecimal.h b/src/mongo/scripting/mozjs/numberdecimal.h
index 76411b45ca4..698bd8fe212 100644
--- a/src/mongo/scripting/mozjs/numberdecimal.h
+++ b/src/mongo/scripting/mozjs/numberdecimal.h
@@ -45,7 +45,7 @@ struct NumberDecimalInfo : public BaseInfo {
static void finalize(JSFreeOp* fop, JSObject* obj);
struct Functions {
- MONGO_DEFINE_JS_FUNCTION(toString);
+ MONGO_DECLARE_JS_FUNCTION(toString);
};
static const JSFunctionSpec methods[2];
diff --git a/src/mongo/scripting/mozjs/numberint.cpp b/src/mongo/scripting/mozjs/numberint.cpp
index 1704154ac74..c55510502e9 100644
--- a/src/mongo/scripting/mozjs/numberint.cpp
+++ b/src/mongo/scripting/mozjs/numberint.cpp
@@ -34,15 +34,16 @@
#include "mongo/scripting/mozjs/objectwrapper.h"
#include "mongo/scripting/mozjs/valuereader.h"
#include "mongo/scripting/mozjs/valuewriter.h"
+#include "mongo/scripting/mozjs/wrapconstrainedmethod.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
namespace mozjs {
const JSFunctionSpec NumberIntInfo::methods[4] = {
- MONGO_ATTACH_JS_FUNCTION(toNumber),
- MONGO_ATTACH_JS_FUNCTION(toString),
- MONGO_ATTACH_JS_FUNCTION(valueOf),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD(toNumber, NumberIntInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD(toString, NumberIntInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD(valueOf, NumberIntInfo),
JS_FS_END,
};
@@ -67,17 +68,17 @@ int NumberIntInfo::ToNumberInt(JSContext* cx, JS::HandleObject thisv) {
return x ? *x : 0;
}
-void NumberIntInfo::Functions::valueOf(JSContext* cx, JS::CallArgs args) {
+void NumberIntInfo::Functions::valueOf::call(JSContext* cx, JS::CallArgs args) {
int out = NumberIntInfo::ToNumberInt(cx, args.thisv());
args.rval().setInt32(out);
}
-void NumberIntInfo::Functions::toNumber(JSContext* cx, JS::CallArgs args) {
- valueOf(cx, args);
+void NumberIntInfo::Functions::toNumber::call(JSContext* cx, JS::CallArgs args) {
+ valueOf::call(cx, args);
}
-void NumberIntInfo::Functions::toString(JSContext* cx, JS::CallArgs args) {
+void NumberIntInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args) {
int val = NumberIntInfo::ToNumberInt(cx, args.thisv());
str::stream ss;
@@ -91,7 +92,7 @@ void NumberIntInfo::construct(JSContext* cx, JS::CallArgs args) {
JS::RootedObject thisv(cx);
- scope->getNumberIntProto().newObject(&thisv);
+ scope->getProto<NumberIntInfo>().newObject(&thisv);
int32_t x = 0;
diff --git a/src/mongo/scripting/mozjs/numberint.h b/src/mongo/scripting/mozjs/numberint.h
index 378c3a0d57e..a9a052bb0b7 100644
--- a/src/mongo/scripting/mozjs/numberint.h
+++ b/src/mongo/scripting/mozjs/numberint.h
@@ -43,9 +43,9 @@ struct NumberIntInfo : public BaseInfo {
static void finalize(JSFreeOp* fop, JSObject* obj);
struct Functions {
- MONGO_DEFINE_JS_FUNCTION(toNumber);
- MONGO_DEFINE_JS_FUNCTION(toString);
- MONGO_DEFINE_JS_FUNCTION(valueOf);
+ MONGO_DECLARE_JS_FUNCTION(toNumber);
+ MONGO_DECLARE_JS_FUNCTION(toString);
+ MONGO_DECLARE_JS_FUNCTION(valueOf);
};
static const JSFunctionSpec methods[4];
diff --git a/src/mongo/scripting/mozjs/numberlong.cpp b/src/mongo/scripting/mozjs/numberlong.cpp
index 5292e372f5c..fcd70b054ff 100644
--- a/src/mongo/scripting/mozjs/numberlong.cpp
+++ b/src/mongo/scripting/mozjs/numberlong.cpp
@@ -36,6 +36,7 @@
#include "mongo/scripting/mozjs/objectwrapper.h"
#include "mongo/scripting/mozjs/valuereader.h"
#include "mongo/scripting/mozjs/valuewriter.h"
+#include "mongo/scripting/mozjs/wrapconstrainedmethod.h"
#include "mongo/util/mongoutils/str.h"
#include "mongo/util/text.h"
@@ -43,10 +44,10 @@ namespace mongo {
namespace mozjs {
const JSFunctionSpec NumberLongInfo::methods[5] = {
- MONGO_ATTACH_JS_FUNCTION(toNumber),
- MONGO_ATTACH_JS_FUNCTION(toString),
- MONGO_ATTACH_JS_FUNCTION(valueOf),
- MONGO_ATTACH_JS_FUNCTION(compare),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD(toNumber, NumberLongInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD(toString, NumberLongInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD(valueOf, NumberLongInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD(compare, NumberLongInfo),
JS_FS_END,
};
@@ -80,17 +81,17 @@ long long NumberLongInfo::ToNumberLong(JSContext* cx, JS::HandleObject thisv) {
(unsigned)(o.getNumber(kBottom)));
}
-void NumberLongInfo::Functions::valueOf(JSContext* cx, JS::CallArgs args) {
+void NumberLongInfo::Functions::valueOf::call(JSContext* cx, JS::CallArgs args) {
long long out = NumberLongInfo::ToNumberLong(cx, args.thisv());
args.rval().setDouble(out);
}
-void NumberLongInfo::Functions::toNumber(JSContext* cx, JS::CallArgs args) {
- valueOf(cx, args);
+void NumberLongInfo::Functions::toNumber::call(JSContext* cx, JS::CallArgs args) {
+ valueOf::call(cx, args);
}
-void NumberLongInfo::Functions::toString(JSContext* cx, JS::CallArgs args) {
+void NumberLongInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args) {
str::stream ss;
long long val = NumberLongInfo::ToNumberLong(cx, args.thisv());
@@ -105,7 +106,7 @@ void NumberLongInfo::Functions::toString(JSContext* cx, JS::CallArgs args) {
ValueReader(cx, args.rval()).fromStringData(ss.operator std::string());
}
-void NumberLongInfo::Functions::compare(JSContext* cx, JS::CallArgs args) {
+void NumberLongInfo::Functions::compare::call(JSContext* cx, JS::CallArgs args) {
uassert(ErrorCodes::BadValue, "NumberLong.compare() needs 1 argument", args.length() == 1);
uassert(ErrorCodes::BadValue,
"NumberLong.compare() argument must be an object",
@@ -133,7 +134,7 @@ void NumberLongInfo::construct(JSContext* cx, JS::CallArgs args) {
JS::RootedObject thisv(cx);
- scope->getNumberLongProto().newObject(&thisv);
+ scope->getProto<NumberLongInfo>().newObject(&thisv);
ObjectWrapper o(cx, thisv);
JS::RootedValue floatApprox(cx);
diff --git a/src/mongo/scripting/mozjs/numberlong.h b/src/mongo/scripting/mozjs/numberlong.h
index c6f42da0ca7..145afd387b5 100644
--- a/src/mongo/scripting/mozjs/numberlong.h
+++ b/src/mongo/scripting/mozjs/numberlong.h
@@ -51,10 +51,10 @@ struct NumberLongInfo : public BaseInfo {
static void construct(JSContext* cx, JS::CallArgs args);
struct Functions {
- MONGO_DEFINE_JS_FUNCTION(toNumber);
- MONGO_DEFINE_JS_FUNCTION(toString);
- MONGO_DEFINE_JS_FUNCTION(valueOf);
- MONGO_DEFINE_JS_FUNCTION(compare);
+ MONGO_DECLARE_JS_FUNCTION(toNumber);
+ MONGO_DECLARE_JS_FUNCTION(toString);
+ MONGO_DECLARE_JS_FUNCTION(valueOf);
+ MONGO_DECLARE_JS_FUNCTION(compare);
};
static const JSFunctionSpec methods[5];
diff --git a/src/mongo/scripting/mozjs/object.cpp b/src/mongo/scripting/mozjs/object.cpp
index a90bec36a72..0bd33b3d72d 100644
--- a/src/mongo/scripting/mozjs/object.cpp
+++ b/src/mongo/scripting/mozjs/object.cpp
@@ -44,7 +44,7 @@ const JSFunctionSpec ObjectInfo::methods[3] = {
const char* const ObjectInfo::className = "Object";
-void ObjectInfo::Functions::bsonsize(JSContext* cx, JS::CallArgs args) {
+void ObjectInfo::Functions::bsonsize::call(JSContext* cx, JS::CallArgs args) {
if (args.length() != 1)
uasserted(ErrorCodes::BadValue, "bsonsize needs 1 argument");
@@ -59,7 +59,7 @@ void ObjectInfo::Functions::bsonsize(JSContext* cx, JS::CallArgs args) {
args.rval().setInt32(ValueWriter(cx, args.get(0)).toBSON().objsize());
}
-void ObjectInfo::Functions::invalidForStorage(JSContext* cx, JS::CallArgs args) {
+void ObjectInfo::Functions::invalidForStorage::call(JSContext* cx, JS::CallArgs args) {
if (args.length() != 1)
uasserted(ErrorCodes::BadValue, "invalidForStorage needs 1 argument");
diff --git a/src/mongo/scripting/mozjs/object.h b/src/mongo/scripting/mozjs/object.h
index 70f475c3f0e..f5e921155c2 100644
--- a/src/mongo/scripting/mozjs/object.h
+++ b/src/mongo/scripting/mozjs/object.h
@@ -41,8 +41,8 @@ namespace mozjs {
*/
struct ObjectInfo : public BaseInfo {
struct Functions {
- MONGO_DEFINE_JS_FUNCTION(bsonsize);
- MONGO_DEFINE_JS_FUNCTION(invalidForStorage);
+ MONGO_DECLARE_JS_FUNCTION(bsonsize);
+ MONGO_DECLARE_JS_FUNCTION(invalidForStorage);
};
static const JSFunctionSpec methods[3];
diff --git a/src/mongo/scripting/mozjs/objectwrapper.cpp b/src/mongo/scripting/mozjs/objectwrapper.cpp
index 5ca5cdeca97..2dc17726b37 100644
--- a/src/mongo/scripting/mozjs/objectwrapper.cpp
+++ b/src/mongo/scripting/mozjs/objectwrapper.cpp
@@ -343,7 +343,7 @@ void ObjectWrapper::writeThis(BSONObjBuilder* b) {
auto scope = getScope(_context);
BSONObj* originalBSON = nullptr;
- if (scope->getBsonProto().instanceOf(_object)) {
+ if (scope->getProto<BSONInfo>().instanceOf(_object)) {
bool altered;
std::tie(originalBSON, altered) = BSONInfo::originalBSON(_context, _object);
@@ -389,5 +389,17 @@ void ObjectWrapper::_writeField(BSONObjBuilder* b, Key key, BSONObj* originalPar
x.writeThis(b, key.toString(_context));
}
+std::string ObjectWrapper::getClassName() {
+ auto jsclass = JS_GetClass(_object);
+
+ if (jsclass)
+ return jsclass->name;
+
+ JS::RootedValue ctor(_context);
+ getValue("constructor", &ctor);
+
+ return ObjectWrapper(_context, ctor).getString("name");
+}
+
} // namespace mozjs
} // namespace mongo
diff --git a/src/mongo/scripting/mozjs/objectwrapper.h b/src/mongo/scripting/mozjs/objectwrapper.h
index d8d519acc7f..57bdc728494 100644
--- a/src/mongo/scripting/mozjs/objectwrapper.h
+++ b/src/mongo/scripting/mozjs/objectwrapper.h
@@ -160,6 +160,8 @@ public:
return _object;
}
+ std::string getClassName();
+
private:
/**
* writes the field "key" into the associated builder
diff --git a/src/mongo/scripting/mozjs/oid.cpp b/src/mongo/scripting/mozjs/oid.cpp
index cf391bf03e8..8c0debaccc1 100644
--- a/src/mongo/scripting/mozjs/oid.cpp
+++ b/src/mongo/scripting/mozjs/oid.cpp
@@ -34,6 +34,7 @@
#include "mongo/scripting/mozjs/objectwrapper.h"
#include "mongo/scripting/mozjs/valuereader.h"
#include "mongo/scripting/mozjs/valuewriter.h"
+#include "mongo/scripting/mozjs/wrapconstrainedmethod.h"
#include "mongo/stdx/memory.h"
#include "mongo/util/mongoutils/str.h"
@@ -41,12 +42,12 @@ namespace mongo {
namespace mozjs {
const JSFunctionSpec OIDInfo::methods[2] = {
- MONGO_ATTACH_JS_FUNCTION(toString), JS_FS_END,
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD(toString, OIDInfo), JS_FS_END,
};
const char* const OIDInfo::className = "ObjectId";
-void OIDInfo::Functions::toString(JSContext* cx, JS::CallArgs args) {
+void OIDInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args) {
ObjectWrapper o(cx, args.thisv());
if (!o.hasField("str"))
@@ -75,7 +76,7 @@ void OIDInfo::construct(JSContext* cx, JS::CallArgs args) {
}
JS::RootedObject thisv(cx);
- scope->getOidProto().newObject(&thisv);
+ scope->getProto<OIDInfo>().newObject(&thisv);
ObjectWrapper o(cx, thisv);
o.setString("str", oid->toString());
diff --git a/src/mongo/scripting/mozjs/oid.h b/src/mongo/scripting/mozjs/oid.h
index 109282be882..8171d2d2aac 100644
--- a/src/mongo/scripting/mozjs/oid.h
+++ b/src/mongo/scripting/mozjs/oid.h
@@ -42,7 +42,7 @@ struct OIDInfo : public BaseInfo {
static void construct(JSContext* cx, JS::CallArgs args);
struct Functions {
- MONGO_DEFINE_JS_FUNCTION(toString);
+ MONGO_DECLARE_JS_FUNCTION(toString);
};
static const JSFunctionSpec methods[2];
diff --git a/src/mongo/scripting/mozjs/timestamp.cpp b/src/mongo/scripting/mozjs/timestamp.cpp
index f81cc4050ce..8659d8a4d85 100644
--- a/src/mongo/scripting/mozjs/timestamp.cpp
+++ b/src/mongo/scripting/mozjs/timestamp.cpp
@@ -45,7 +45,7 @@ void TimestampInfo::construct(JSContext* cx, JS::CallArgs args) {
auto scope = getScope(cx);
JS::RootedObject thisv(cx);
- scope->getTimestampProto().newObject(&thisv);
+ scope->getProto<TimestampInfo>().newObject(&thisv);
ObjectWrapper o(cx, thisv);
if (args.length() == 0) {
diff --git a/src/mongo/scripting/mozjs/valuereader.cpp b/src/mongo/scripting/mozjs/valuereader.cpp
index e4d005cb399..89289c2f976 100644
--- a/src/mongo/scripting/mozjs/valuereader.cpp
+++ b/src/mongo/scripting/mozjs/valuereader.cpp
@@ -70,7 +70,7 @@ void ValueReader::fromBSONElement(const BSONElement& elem, bool readOnly) {
ValueReader(_context, args[0]).fromStringData(elem.OID().toString());
- scope->getOidProto().newInstance(args, _value);
+ scope->getProto<OIDInfo>().newInstance(args, _value);
return;
}
case mongo::NumberDouble:
@@ -122,7 +122,7 @@ void ValueReader::fromBSONElement(const BSONElement& elem, bool readOnly) {
ValueReader(_context, args[1]).fromStringData(elem.regexFlags());
JS::RootedObject obj(_context);
- scope->getRegExpProto().newInstance(args, &obj);
+ scope->getProto<RegExpInfo>().newInstance(args, &obj);
_value.setObjectOrNull(obj);
@@ -140,7 +140,7 @@ void ValueReader::fromBSONElement(const BSONElement& elem, bool readOnly) {
ValueReader(_context, args[1]).fromStringData(ss.str());
- scope->getBinDataProto().newInstance(args, _value);
+ scope->getProto<BinDataInfo>().newInstance(args, _value);
return;
}
case mongo::bsonTimestamp: {
@@ -149,7 +149,7 @@ void ValueReader::fromBSONElement(const BSONElement& elem, bool readOnly) {
args[0].setDouble(elem.timestampTime().toMillisSinceEpoch() / 1000);
args[1].setNumber(elem.timestampInc());
- scope->getTimestampProto().newInstance(args, _value);
+ scope->getProto<TimestampInfo>().newInstance(args, _value);
return;
}
@@ -163,14 +163,14 @@ void ValueReader::fromBSONElement(const BSONElement& elem, bool readOnly) {
JS::AutoValueArray<1> args(_context);
args[0].setNumber(static_cast<double>(static_cast<long long>(nativeUnsignedLong)));
- scope->getNumberLongProto().newInstance(args, _value);
+ scope->getProto<NumberLongInfo>().newInstance(args, _value);
} else {
JS::AutoValueArray<3> args(_context);
args[0].setNumber(static_cast<double>(static_cast<long long>(nativeUnsignedLong)));
args[1].setDouble(nativeUnsignedLong >> 32);
args[2].setDouble(
static_cast<unsigned long>(nativeUnsignedLong & 0x00000000ffffffff));
- scope->getNumberLongProto().newInstance(args, _value);
+ scope->getProto<NumberLongInfo>().newInstance(args, _value);
}
return;
@@ -181,16 +181,16 @@ void ValueReader::fromBSONElement(const BSONElement& elem, bool readOnly) {
ValueReader(_context, args[0]).fromDecimal128(decimal);
JS::RootedObject obj(_context);
- scope->getNumberDecimalProto().newInstance(args, &obj);
+ scope->getProto<NumberDecimalInfo>().newInstance(args, &obj);
_value.setObjectOrNull(obj);
return;
}
case mongo::MinKey:
- scope->getMinKeyProto().newInstance(_value);
+ scope->getProto<MinKeyInfo>().newInstance(_value);
return;
case mongo::MaxKey:
- scope->getMaxKeyProto().newInstance(_value);
+ scope->getProto<MaxKeyInfo>().newInstance(_value);
return;
case mongo::DBRef: {
JS::AutoValueArray<1> oidArgs(_context);
@@ -198,9 +198,9 @@ void ValueReader::fromBSONElement(const BSONElement& elem, bool readOnly) {
JS::AutoValueArray<2> dbPointerArgs(_context);
ValueReader(_context, dbPointerArgs[0]).fromStringData(elem.dbrefNS());
- scope->getOidProto().newInstance(oidArgs, dbPointerArgs[1]);
+ scope->getProto<OIDInfo>().newInstance(oidArgs, dbPointerArgs[1]);
- scope->getDbPointerProto().newInstance(dbPointerArgs, _value);
+ scope->getProto<DBPointerInfo>().newInstance(dbPointerArgs, _value);
return;
}
default:
@@ -231,7 +231,7 @@ void ValueReader::fromBSON(const BSONObj& obj, bool readOnly) {
auto scope = getScope(_context);
- scope->getDbRefProto().newInstance(args, &obj);
+ scope->getProto<DBRefInfo>().newInstance(args, &obj);
ObjectWrapper o(_context, obj);
while (it.more()) {
diff --git a/src/mongo/scripting/mozjs/valuewriter.cpp b/src/mongo/scripting/mozjs/valuewriter.cpp
index 72a44583a5b..7fdb1596fa3 100644
--- a/src/mongo/scripting/mozjs/valuewriter.cpp
+++ b/src/mongo/scripting/mozjs/valuewriter.cpp
@@ -82,13 +82,42 @@ int ValueWriter::type() {
uasserted(ErrorCodes::BadValue, "unable to get type");
}
+std::string ValueWriter::typeAsString() {
+ if (_value.isNull())
+ return "null";
+ if (_value.isUndefined())
+ return "undefined";
+ if (_value.isString())
+ return "string";
+ if (JS_IsArrayObject(_context, _value))
+ return "array";
+ if (_value.isBoolean())
+ return "boolean";
+ if (_value.isNumber())
+ return "number";
+
+ if (_value.isObject()) {
+ JS::RootedObject obj(_context, _value.toObjectOrNull());
+ if (JS_IsArrayObject(_context, obj))
+ return "array";
+ if (JS_ObjectIsDate(_context, obj))
+ return "date";
+ if (JS_ObjectIsFunction(_context, obj))
+ return "function";
+
+ return ObjectWrapper(_context, _value).getClassName();
+ }
+
+ uasserted(ErrorCodes::BadValue, "unable to get type");
+}
+
BSONObj ValueWriter::toBSON() {
if (!_value.isObject())
return BSONObj();
JS::RootedObject obj(_context, _value.toObjectOrNull());
- if (getScope(_context)->getBsonProto().instanceOf(obj)) {
+ if (getScope(_context)->getProto<BSONInfo>().instanceOf(obj)) {
BSONObj* originalBSON;
bool altered;
@@ -130,7 +159,7 @@ int32_t ValueWriter::toInt32() {
int64_t ValueWriter::toInt64() {
int64_t out;
- if (getScope(_context)->getNumberLongProto().instanceOf(_value))
+ if (getScope(_context)->getProto<NumberLongInfo>().instanceOf(_value))
return NumberLongInfo::ToNumberLong(_context, _value);
if (JS::ToInt64(_context, _value, &out))
@@ -144,13 +173,13 @@ Decimal128 ValueWriter::toDecimal128() {
return Decimal128(toNumber());
}
- if (getScope(_context)->getNumberIntProto().instanceOf(_value))
+ if (getScope(_context)->getProto<NumberIntInfo>().instanceOf(_value))
return Decimal128(NumberIntInfo::ToNumberInt(_context, _value));
- if (getScope(_context)->getNumberLongProto().instanceOf(_value))
+ if (getScope(_context)->getProto<NumberLongInfo>().instanceOf(_value))
return Decimal128(NumberLongInfo::ToNumberLong(_context, _value));
- if (getScope(_context)->getNumberDecimalProto().instanceOf(_value))
+ if (getScope(_context)->getProto<NumberDecimalInfo>().instanceOf(_value))
return NumberDecimalInfo::ToNumberDecimal(_context, _value);
if (_value.isString()) {
@@ -214,7 +243,7 @@ void ValueWriter::_writeObject(BSONObjBuilder* b, StringData sd, JS::HandleObjec
if (JS_ObjectIsFunction(_context, _value.toObjectOrNull())) {
uassert(16716,
"cannot convert native function to BSON",
- !scope->getNativeFunctionProto().instanceOf(obj));
+ !scope->getProto<NativeFunctionInfo>().instanceOf(obj));
b->appendCode(sd, ValueWriter(_context, _value).toString());
} else if (JS_ObjectIsRegExp(_context, obj)) {
JS::RootedValue v(_context);
@@ -232,21 +261,21 @@ void ValueWriter::_writeObject(BSONObjBuilder* b, StringData sd, JS::HandleObjec
auto d = Date_t::fromMillisSinceEpoch(ValueWriter(_context, dateval).toNumber());
b->appendDate(sd, d);
- } else if (scope->getOidProto().instanceOf(obj)) {
+ } else if (scope->getProto<OIDInfo>().instanceOf(obj)) {
b->append(sd, OID(o.getString("str")));
- } else if (scope->getNumberLongProto().instanceOf(obj)) {
+ } else if (scope->getProto<NumberLongInfo>().instanceOf(obj)) {
long long out = NumberLongInfo::ToNumberLong(_context, obj);
b->append(sd, out);
- } else if (scope->getNumberIntProto().instanceOf(obj)) {
+ } else if (scope->getProto<NumberIntInfo>().instanceOf(obj)) {
b->append(sd, NumberIntInfo::ToNumberInt(_context, obj));
- } else if (scope->getNumberDecimalProto().instanceOf(obj)) {
+ } else if (scope->getProto<NumberDecimalInfo>().instanceOf(obj)) {
b->append(sd, NumberDecimalInfo::ToNumberDecimal(_context, obj));
- } else if (scope->getDbPointerProto().instanceOf(obj)) {
+ } else if (scope->getProto<DBPointerInfo>().instanceOf(obj)) {
JS::RootedValue id(_context);
o.getValue("id", &id);
b->appendDBRef(sd, o.getString("ns"), OID(ObjectWrapper(_context, id).getString("str")));
- } else if (scope->getBinDataProto().instanceOf(obj)) {
+ } else if (scope->getProto<BinDataInfo>().instanceOf(obj)) {
auto str = static_cast<std::string*>(JS_GetPrivate(obj));
auto binData = base64::decode(*str);
@@ -255,12 +284,12 @@ void ValueWriter::_writeObject(BSONObjBuilder* b, StringData sd, JS::HandleObjec
binData.size(),
static_cast<mongo::BinDataType>(static_cast<int>(o.getNumber("type"))),
binData.c_str());
- } else if (scope->getTimestampProto().instanceOf(obj)) {
+ } else if (scope->getProto<TimestampInfo>().instanceOf(obj)) {
Timestamp ot(o.getNumber("t"), o.getNumber("i"));
b->append(sd, ot);
- } else if (scope->getMinKeyProto().instanceOf(obj)) {
+ } else if (scope->getProto<MinKeyInfo>().instanceOf(obj)) {
b->appendMinKey(sd);
- } else if (scope->getMaxKeyProto().instanceOf(obj)) {
+ } else if (scope->getProto<MaxKeyInfo>().instanceOf(obj)) {
b->appendMaxKey(sd);
} else {
// nested object or array
diff --git a/src/mongo/scripting/mozjs/valuewriter.h b/src/mongo/scripting/mozjs/valuewriter.h
index dd0eb98af92..1945303867b 100644
--- a/src/mongo/scripting/mozjs/valuewriter.h
+++ b/src/mongo/scripting/mozjs/valuewriter.h
@@ -63,6 +63,11 @@ public:
bool toBoolean();
/**
+ * Provides the type of the value. For objects, it fetches the class name if possible.
+ */
+ std::string typeAsString();
+
+ /**
* Writes the value into a bsonobjbuilder under the name in sd.
*/
void writeThis(BSONObjBuilder* b, StringData sd);
diff --git a/src/mongo/scripting/mozjs/wrapconstrainedmethod.h b/src/mongo/scripting/mozjs/wrapconstrainedmethod.h
new file mode 100644
index 00000000000..db21289cb93
--- /dev/null
+++ b/src/mongo/scripting/mozjs/wrapconstrainedmethod.h
@@ -0,0 +1,123 @@
+/**
+ * Copyright (C) 2015 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+#include <jsapi.h>
+
+#include "mongo/scripting/mozjs/implscope.h"
+#include "mongo/scripting/mozjs/objectwrapper.h"
+#include "mongo/scripting/mozjs/valuewriter.h"
+#include "mongo/util/assert_util.h"
+#include "mongo/util/stringutils.h"
+
+namespace mongo {
+namespace mozjs {
+namespace smUtils {
+
+/**
+ * Returns true if "value" is an instance of any of the types passed as
+ * template parameters. Additionally sets isProto if the value is also the
+ * prototype for that type.
+ *
+ * We recurse until we hit the void specialization which we set up by adding
+ * void as the last type in wrapConstrainedMethod.
+ */
+template <typename T, typename... Args>
+bool instanceOf(MozJSImplScope* scope, bool* isProto, JS::HandleValue value) {
+ auto& proto = scope->getProto<T>();
+
+ if (proto.instanceOf(value)) {
+ if (value.toObjectOrNull() == proto.getProto()) {
+ *isProto = true;
+ }
+
+ return true;
+ }
+
+ return instanceOf<Args...>(scope, isProto, value);
+}
+
+/**
+ * Terminating specialization for instanceOf.
+ *
+ * We use this to identify the end of the template list in the general case.
+ */
+template <>
+inline bool instanceOf<void>(MozJSImplScope* scope, bool* isProto, JS::HandleValue value) {
+ return false;
+}
+
+
+/**
+ * Wraps a method with an additional check against a list of possible wrap types.
+ *
+ * Template Parameters:
+ * T - A type with
+ * ::call - a static function of type void (JSContext* cx, JS::CallArgs args)
+ * ::name - a static function which returns a const char* with the type name
+ * noProto - whether the method can be invoked on the prototype
+ * Args - The list of types to check against scope->getProto<T>().instanceOf
+ * for the thisv the method has been invoked against
+ */
+template <typename T, bool noProto, typename... Args>
+bool wrapConstrainedMethod(JSContext* cx, unsigned argc, JS::Value* vp) {
+ try {
+ JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+ bool isProto = false;
+
+ if (!args.thisv().isObject()) {
+ uasserted(ErrorCodes::BadValue,
+ str::stream() << "Cannot call \"" << T::name()
+ << "\" on non-object of type \""
+ << ValueWriter(cx, args.thisv()).typeAsString() << "\"");
+ }
+
+ if (!instanceOf<Args..., void>(getScope(cx), &isProto, args.thisv())) {
+ uasserted(ErrorCodes::BadValue,
+ str::stream() << "Cannot call \"" << T::name() << "\" on object of type \""
+ << ObjectWrapper(cx, args.thisv()).getClassName() << "\"");
+ }
+
+ if (noProto && isProto) {
+ uasserted(ErrorCodes::BadValue,
+ str::stream() << "Cannot call \"" << T::name() << "\" on prototype of \""
+ << ObjectWrapper(cx, args.thisv()).getClassName() << "\"");
+ }
+
+ T::call(cx, args);
+ return true;
+ } catch (...) {
+ mongoToJSException(cx);
+ return false;
+ }
+}
+
+} // namespace smUtils
+} // namespace mozjs
+} // namespace mongo
diff --git a/src/mongo/scripting/mozjs/wraptype.h b/src/mongo/scripting/mozjs/wraptype.h
index 7b45e24e13e..d569bcb9d86 100644
--- a/src/mongo/scripting/mozjs/wraptype.h
+++ b/src/mongo/scripting/mozjs/wraptype.h
@@ -53,35 +53,55 @@
// MONGO_*_JS_FUNCTION_* macros are public and allow wrapped types to install
// their own functions on types and into the global scope
-#define MONGO_DEFINE_JS_FUNCTION(name) \
- static void name(JSContext* cx, JS::CallArgs args); \
- static bool WRAPPER_##name(JSContext* cx, unsigned argc, JS::Value* vp) { \
- try { \
- JS::CallArgs args = JS::CallArgsFromVp(argc, vp); \
- name(cx, args); \
- return true; \
- } catch (...) { \
- mongoToJSException(cx); \
- return false; \
- } \
- }
+#define MONGO_DECLARE_JS_FUNCTION(function) \
+ struct function { \
+ static const char* name() { \
+ return #function; \
+ } \
+ static void call(JSContext* cx, JS::CallArgs args); \
+ };
#define MONGO_ATTACH_JS_FUNCTION_WITH_FLAGS(name, flags) \
- JS_FS(#name, Functions::WRAPPER_##name, 0, flags)
+ JS_FS(#name, smUtils::wrapFunction<Functions::name>, 0, flags)
#define MONGO_ATTACH_JS_FUNCTION(name) MONGO_ATTACH_JS_FUNCTION_WITH_FLAGS(name, 0)
+#define MONGO_ATTACH_JS_CONSTRAINED_METHOD(name, ...) \
+ { \
+ #name, {smUtils::wrapConstrainedMethod < Functions::name, false, __VA_ARGS__ >, nullptr }, \
+ 0, \
+ 0, \
+ nullptr \
+ }
+
+#define MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(name, ...) \
+ { \
+ #name, {smUtils::wrapConstrainedMethod < Functions::name, true, __VA_ARGS__ >, nullptr }, \
+ 0, \
+ 0, \
+ nullptr \
+ }
+
namespace mongo {
namespace mozjs {
namespace smUtils {
+template <typename T>
+bool wrapFunction(JSContext* cx, unsigned argc, JS::Value* vp) {
+ try {
+ JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+ T::call(cx, args);
+ return true;
+ } catch (...) {
+ mongoToJSException(cx);
+ return false;
+ }
+}
+
// Now all the spidermonkey type methods
template <typename T>
-static bool addProperty(JSContext* cx,
- JS::HandleObject obj,
- JS::HandleId id,
- JS::MutableHandleValue v) {
+bool addProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue v) {
try {
T::addProperty(cx, obj, id, v);
return true;
@@ -92,7 +112,7 @@ static bool addProperty(JSContext* cx,
};
template <typename T>
-static bool call(JSContext* cx, unsigned argc, JS::Value* vp) {
+bool call(JSContext* cx, unsigned argc, JS::Value* vp) {
try {
T::call(cx, JS::CallArgsFromVp(argc, vp));
return true;
@@ -103,7 +123,7 @@ static bool call(JSContext* cx, unsigned argc, JS::Value* vp) {
};
template <typename T>
-static bool construct(JSContext* cx, unsigned argc, JS::Value* vp) {
+bool construct(JSContext* cx, unsigned argc, JS::Value* vp) {
try {
T::construct(cx, JS::CallArgsFromVp(argc, vp));
return true;
@@ -114,7 +134,7 @@ static bool construct(JSContext* cx, unsigned argc, JS::Value* vp) {
};
template <typename T>
-static bool convert(JSContext* cx, JS::HandleObject obj, JSType type, JS::MutableHandleValue vp) {
+bool convert(JSContext* cx, JS::HandleObject obj, JSType type, JS::MutableHandleValue vp) {
try {
T::convert(cx, obj, type, vp);
return true;
@@ -125,7 +145,7 @@ static bool convert(JSContext* cx, JS::HandleObject obj, JSType type, JS::Mutabl
};
template <typename T>
-static bool delProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* succeeded) {
+bool delProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* succeeded) {
try {
T::delProperty(cx, obj, id, succeeded);
return true;
@@ -136,7 +156,7 @@ static bool delProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bo
};
template <typename T>
-static bool enumerate(JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties) {
+bool enumerate(JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties) {
try {
T::enumerate(cx, obj, properties);
return true;
@@ -147,10 +167,7 @@ static bool enumerate(JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& pro
};
template <typename T>
-static bool getProperty(JSContext* cx,
- JS::HandleObject obj,
- JS::HandleId id,
- JS::MutableHandleValue vp) {
+bool getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp) {
try {
T::getProperty(cx, obj, id, vp);
return true;
@@ -161,7 +178,7 @@ static bool getProperty(JSContext* cx,
};
template <typename T>
-static bool hasInstance(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp, bool* bp) {
+bool hasInstance(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp, bool* bp) {
try {
T::hasInstance(cx, obj, vp, bp);
return true;
@@ -172,7 +189,7 @@ static bool hasInstance(JSContext* cx, JS::HandleObject obj, JS::MutableHandleVa
};
template <typename T>
-static bool setProperty(
+bool setProperty(
JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool strict, JS::MutableHandleValue vp) {
try {
T::setProperty(cx, obj, id, strict, vp);
@@ -184,7 +201,7 @@ static bool setProperty(
};
template <typename T>
-static bool resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolvedp) {
+bool resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolvedp) {
try {
T::resolve(cx, obj, id, resolvedp);
return true;