diff options
22 files changed, 361 insertions, 101 deletions
diff --git a/buildscripts/vcxproj.header b/buildscripts/vcxproj.header index 190c8bc1bd0..45c5de18230 100644 --- a/buildscripts/vcxproj.header +++ b/buildscripts/vcxproj.header @@ -100,7 +100,7 @@ <ItemDefinitionGroup> <ClCompile> <ObjectFileName>Build/%(RelativeDir)/</ObjectFileName> - <AdditionalIncludeDirectories>src;src\mongo;src\third_party\mozjs-38\include;src\third_party\pcre-8.38;src\third_party\boost-1.60.0;src\third_party\snappy-1.1.3;src\third_party\s2;src\third_party\yaml-cpp-0.5.3\include;src\third_party\wiredtiger\src\include</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>src;src\mongo;src\third_party\mozjs-45\include;src\third_party\pcre-8.38;src\third_party\boost-1.60.0;src\third_party\snappy-1.1.3;src\third_party\s2;src\third_party\yaml-cpp-0.5.3\include;src\third_party\wiredtiger\src\include</AdditionalIncludeDirectories> <PreprocessorDefinitions>NTDDI_VERSION=0x06010000;_WIN32_WINNT=0x0601;WIN32;XP_WIN;%(PreprocessorDefinitions)</PreprocessorDefinitions> <!-- above is temp - NTDDI etc. should be configurable, not finished yet, this gets us compiling some for now. <PreprocessorDefinitions>WIN32;XP_WIN;%(PreprocessorDefinitions)</PreprocessorDefinitions> diff --git a/jstests/core/jssymbol.js b/jstests/core/jssymbol.js new file mode 100644 index 00000000000..62843405c9a --- /dev/null +++ b/jstests/core/jssymbol.js @@ -0,0 +1,35 @@ +// Test Symbol.toPrimitive works for DB and BSON objects +// +(function() { + // Exercise Symbol.toPrimitive on DB objects + // clang-format off + assert(`${db}` === 'test'); + // clang-format on + assert(isNaN(+db)); + + // Exercise the special Symbol methods and make sure DB.getProperty handles them + assert(db[Symbol.iterator] != 1); + assert(db[Symbol.match] != 1); + assert(db[Symbol.species] != 1); + assert(db[Symbol.toPrimitive] != 1); + + // Exercise Symbol.toPrimitive on BSON objects + col1 = db.jssymbol_col; + col1.insert({}); + a = db.getCollection("jssymbol_col").getIndexes()[0]; + + assert(isNaN(+a)); + assert(+a.v == 1); + // clang-format off + assert(`${a.v}` == 1); + assert(`${a}` == '[object BSON]'); + // clang-format on + + // Exercise the special Symbol methods and make sure BSON.resolve handles them + assert(db[Symbol.iterator] != 1); + assert(db[Symbol.match] != 1); + assert(db[Symbol.species] != 1); + assert(db[Symbol.toPrimitive] != 1); + + col1.drop(); +})(); diff --git a/jstests/mmap_v1/dur_remove_old_journals.js b/jstests/mmap_v1/dur_remove_old_journals.js index 8ea2d8c724c..0d1b930815b 100644 --- a/jstests/mmap_v1/dur_remove_old_journals.js +++ b/jstests/mmap_v1/dur_remove_old_journals.js @@ -73,6 +73,7 @@ if (db.serverBuildInfo().bits == 32) { db.adminCommand({fsync: 1}); db.foo.remove({}); db.adminCommand({fsync: 1}); + gc(); } } diff --git a/src/mongo/scripting/mozjs/PosixNSPR.cpp b/src/mongo/scripting/mozjs/PosixNSPR.cpp index dae1779e0b3..b6c36d760d3 100644 --- a/src/mongo/scripting/mozjs/PosixNSPR.cpp +++ b/src/mongo/scripting/mozjs/PosixNSPR.cpp @@ -77,6 +77,15 @@ void PR_DestroyFakeThread(PRThread* thread) { } // namespace mongo +// In mozjs-45, js_delete takes a const pointer which is incompatible with std::unique_ptr. +template <class T> +static MOZ_ALWAYS_INLINE void js_delete_nonconst(T* p) { + if (p) { + p->~T(); + js_free(p); + } +} + PRThread* PR_CreateThread(PRThreadType type, void (*start)(void* arg), void* arg, @@ -90,7 +99,7 @@ PRThread* PR_CreateThread(PRThreadType type, try { std::unique_ptr<nspr::Thread, void (*)(nspr::Thread*)> t( js_new<nspr::Thread>(start, arg, state != PR_UNJOINABLE_THREAD), - js_delete<nspr::Thread>); + js_delete_nonconst<nspr::Thread>); t->thread() = mongo::stdx::thread(&nspr::Thread::ThreadRoutine, t.get()); diff --git a/src/mongo/scripting/mozjs/base.cpp b/src/mongo/scripting/mozjs/base.cpp index b85229ae354..7bcc345dab7 100644 --- a/src/mongo/scripting/mozjs/base.cpp +++ b/src/mongo/scripting/mozjs/base.cpp @@ -41,15 +41,17 @@ const char* const BaseInfo::inheritFrom = nullptr; void BaseInfo::addProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandleValue v) {} + JS::HandleValue v) {} void BaseInfo::call(JSContext* cx, JS::CallArgs args) {} void BaseInfo::construct(JSContext* cx, JS::CallArgs args) {} -void BaseInfo::convert(JSContext* cx, - JS::HandleObject obj, - JSType type, - JS::MutableHandleValue vp) {} -void BaseInfo::delProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* succeeded) {} -void BaseInfo::enumerate(JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties) {} +void BaseInfo::delProperty(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::ObjectOpResult& result) {} +void BaseInfo::enumerate(JSContext* cx, + JS::HandleObject obj, + JS::AutoIdVector& properties, + bool enumerableOnly) {} void BaseInfo::finalize(JSFreeOp* fop, JSObject* obj) {} void BaseInfo::getProperty(JSContext* cx, JS::HandleObject obj, @@ -59,10 +61,16 @@ void BaseInfo::hasInstance(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp, bool* bp) {} +bool BaseInfo::mayResolve(const JSAtomState& names, jsid id, JSObject* maybeObj) { + return false; +} void BaseInfo::postInstall(JSContext* cx, JS::HandleObject global, JS::HandleObject proto) {} void BaseInfo::resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolvedp) {} -void BaseInfo::setProperty( - JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool strict, JS::MutableHandleValue vp) {} +void BaseInfo::setProperty(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::MutableHandleValue vp, + JS::ObjectOpResult& result) {} } // namespace mozjs } // namespace mongo diff --git a/src/mongo/scripting/mozjs/base.h b/src/mongo/scripting/mozjs/base.h index fe90ea65b97..6072b652b21 100644 --- a/src/mongo/scripting/mozjs/base.h +++ b/src/mongo/scripting/mozjs/base.h @@ -61,15 +61,17 @@ struct BaseInfo { static void addProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandleValue v); + JS::HandleValue v); static void call(JSContext* cx, JS::CallArgs args); static void construct(JSContext* cx, JS::CallArgs args); - static void convert(JSContext* cx, - JS::HandleObject obj, - JSType type, - JS::MutableHandleValue vp); - static void delProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* succeeded); - static void enumerate(JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties); + static void delProperty(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::ObjectOpResult& result); + static void enumerate(JSContext* cx, + JS::HandleObject obj, + JS::AutoIdVector& properties, + bool enumerableOnly); static void finalize(JSFreeOp* fop, JSObject* obj); static void getProperty(JSContext* cx, JS::HandleObject obj, @@ -79,13 +81,14 @@ struct BaseInfo { JS::HandleObject obj, JS::MutableHandleValue vp, bool* bp); + static bool mayResolve(const JSAtomState& names, jsid id, JSObject* maybeObj); static void postInstall(JSContext* cx, JS::HandleObject global, JS::HandleObject proto); static void resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolvedp); static void setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - bool strict, - JS::MutableHandleValue vp); + JS::MutableHandleValue vp, + JS::ObjectOpResult& result); }; } // namespace mozjs diff --git a/src/mongo/scripting/mozjs/bson.cpp b/src/mongo/scripting/mozjs/bson.cpp index 0cb60fb6117..cf73b44dc55 100644 --- a/src/mongo/scripting/mozjs/bson.cpp +++ b/src/mongo/scripting/mozjs/bson.cpp @@ -119,7 +119,10 @@ void BSONInfo::finalize(JSFreeOp* fop, JSObject* obj) { delete holder; } -void BSONInfo::enumerate(JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties) { +void BSONInfo::enumerate(JSContext* cx, + JS::HandleObject obj, + JS::AutoIdVector& properties, + bool enumerableOnly) { auto holder = getValidHolder(cx, obj); if (!holder) @@ -148,13 +151,17 @@ void BSONInfo::enumerate(JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& } } -void BSONInfo::setProperty( - JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool strict, JS::MutableHandleValue vp) { +void BSONInfo::setProperty(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::MutableHandleValue vp, + JS::ObjectOpResult& result) { auto holder = getValidHolder(cx, obj); if (holder) { if (holder->_readOnly) { uasserted(ErrorCodes::BadValue, "Read only object"); + return; } auto iter = holder->_removed.find(IdWrapper(cx, id).toString()); @@ -167,14 +174,19 @@ void BSONInfo::setProperty( } ObjectWrapper(cx, obj).defineProperty(id, vp, JSPROP_ENUMERATE); + result.succeed(); } -void BSONInfo::delProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* succeeded) { +void BSONInfo::delProperty(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::ObjectOpResult& result) { auto holder = getValidHolder(cx, obj); if (holder) { if (holder->_readOnly) { uasserted(ErrorCodes::BadValue, "Read only object"); + return; } holder->_altered = true; @@ -183,7 +195,7 @@ void BSONInfo::delProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, holder->_removed[IdWrapper(cx, id).toStringData(&jsstr)] = true; } - *succeeded = true; + result.succeed(); } void BSONInfo::resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolvedp) { diff --git a/src/mongo/scripting/mozjs/bson.h b/src/mongo/scripting/mozjs/bson.h index d341f0a856b..475bda4e64e 100644 --- a/src/mongo/scripting/mozjs/bson.h +++ b/src/mongo/scripting/mozjs/bson.h @@ -47,15 +47,21 @@ namespace mozjs { * ::make() from C++. */ struct BSONInfo : public BaseInfo { - static void delProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* succeeded); - static void enumerate(JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties); + static void delProperty(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::ObjectOpResult& result); + static void enumerate(JSContext* cx, + JS::HandleObject obj, + JS::AutoIdVector& properties, + bool enumerableOnly); static void finalize(JSFreeOp* fop, JSObject* obj); static void resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolvedp); static void setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - bool strict, - JS::MutableHandleValue vp); + JS::MutableHandleValue vp, + JS::ObjectOpResult& result); static const char* const className; static const unsigned classFlags = JSCLASS_HAS_PRIVATE; diff --git a/src/mongo/scripting/mozjs/engine.cpp b/src/mongo/scripting/mozjs/engine.cpp index 54c6c5555e6..90038dbea35 100644 --- a/src/mongo/scripting/mozjs/engine.cpp +++ b/src/mongo/scripting/mozjs/engine.cpp @@ -32,6 +32,8 @@ #include "mongo/scripting/mozjs/engine.h" +#include <js/Initialization.h> + #include "mongo/db/operation_context.h" #include "mongo/db/server_parameters.h" #include "mongo/scripting/mozjs/implscope.h" diff --git a/src/mongo/scripting/mozjs/implscope.cpp b/src/mongo/scripting/mozjs/implscope.cpp index 406ccfee1a7..527f81db279 100644 --- a/src/mongo/scripting/mozjs/implscope.cpp +++ b/src/mongo/scripting/mozjs/implscope.cpp @@ -34,6 +34,7 @@ #include <jscustomallocator.h> #include <jsfriendapi.h> +#include <js/CharacterEncoding.h> #include "mongo/base/error_codes.h" #include "mongo/db/operation_context.h" @@ -242,10 +243,11 @@ MozJSImplScope::MozRuntime::MozRuntime(const MozJSScriptEngine* engine) { if (engine->isJITEnabled()) { JS::RuntimeOptionsRef(_runtime) .setAsmJS(true) + .setThrowOnAsmJSValidationFailure(true) .setBaseline(true) .setIon(true) - .setNativeRegExp(true) - .setUnboxedObjects(true); + .setAsyncStack(false) + .setNativeRegExp(true); } const StackLocator locator; @@ -470,7 +472,7 @@ void MozJSImplScope::newFunction(StringData raw, JS::MutableHandleValue out) { JS::CompileOptions co(_context); setCompileOptions(&co); - _checkErrorState(JS::Evaluate(_context, _global, co, code.c_str(), code.length(), out)); + _checkErrorState(JS::Evaluate(_context, co, code.c_str(), code.length(), out)); } BSONObj MozJSImplScope::callThreadArgs(const BSONObj& args) { @@ -526,7 +528,7 @@ void MozJSImplScope::_MozJSCreateFunction(const char* raw, JS::CompileOptions co(_context); setCompileOptions(&co); - _checkErrorState(JS::Evaluate(_context, _global, co, code.c_str(), code.length(), fun)); + _checkErrorState(JS::Evaluate(_context, co, code.c_str(), code.length(), fun)); uassert(10232, "not a function", fun.isObject() && JS_ObjectIsFunction(_context, fun.toObjectOrNull())); @@ -635,7 +637,7 @@ bool MozJSImplScope::exec(StringData code, co.setFile(name.c_str()); JS::RootedScript script(_context); - bool success = JS::Compile(_context, _global, co, code.rawData(), code.size(), &script); + bool success = JS::Compile(_context, co, code.rawData(), code.size(), &script); if (_checkErrorState(success, reportError, assertOnError)) return false; @@ -645,7 +647,7 @@ bool MozJSImplScope::exec(StringData code, JS::RootedValue out(_context); - success = JS_ExecuteScript(_context, _global, script, &out); + success = JS_ExecuteScript(_context, script, &out); if (timeoutMs) _engine->getDeadlineMonitor().stopDeadline(this); diff --git a/src/mongo/scripting/mozjs/internedstring.cpp b/src/mongo/scripting/mozjs/internedstring.cpp index 61510823f2c..8f7e9ef6673 100644 --- a/src/mongo/scripting/mozjs/internedstring.cpp +++ b/src/mongo/scripting/mozjs/internedstring.cpp @@ -42,7 +42,7 @@ InternedStringTable::InternedStringTable(JSContext* cx) { #define MONGO_MOZJS_INTERNED_STRING(name, str) \ do { \ - auto s = JS_InternString(cx, str); \ + auto s = JS_AtomizeAndPinString(cx, str); \ if (!s) { \ uasserted(ErrorCodes::JSInterpreterFailure, "Failed to JS_InternString"); \ } \ diff --git a/src/mongo/scripting/mozjs/mongo.cpp b/src/mongo/scripting/mozjs/mongo.cpp index 92d73db5f9d..53bf47c77c9 100644 --- a/src/mongo/scripting/mozjs/mongo.cpp +++ b/src/mongo/scripting/mozjs/mongo.cpp @@ -269,29 +269,39 @@ void MongoBase::Functions::insert::call(JSContext* cx, JS::CallArgs args) { return ValueWriter(cx, value).toBSON(); }; - if (args.get(1).isObject() && JS_IsArrayObject(cx, args.get(1))) { - JS::RootedObject obj(cx, args.get(1).toObjectOrNull()); - ObjectWrapper array(cx, obj); + if (args.get(1).isObject()) { + bool isArray; - std::vector<BSONObj> bos; + if (!JS_IsArrayObject(cx, args.get(1), &isArray)) { + uasserted(ErrorCodes::BadValue, "Failure to check is object an array"); + } - bool foundElement = false; + if (isArray) { + JS::RootedObject obj(cx, args.get(1).toObjectOrNull()); + ObjectWrapper array(cx, obj); - array.enumerate([&](JS::HandleId id) { - foundElement = true; + std::vector<BSONObj> bos; - JS::RootedValue value(cx); - array.getValue(id, &value); + bool foundElement = false; - bos.push_back(addId(value)); + array.enumerate([&](JS::HandleId id) { + foundElement = true; - return true; - }); + JS::RootedValue value(cx); + array.getValue(id, &value); - if (!foundElement) - uasserted(ErrorCodes::BadValue, "attempted to insert an empty array"); + bos.push_back(addId(value)); - conn->insert(ns, bos, flags); + return true; + }); + + if (!foundElement) + uasserted(ErrorCodes::BadValue, "attempted to insert an empty array"); + + conn->insert(ns, bos, flags); + } else { + conn->insert(ns, addId(args.get(1))); + } } else { conn->insert(ns, addId(args.get(1))); } diff --git a/src/mongo/scripting/mozjs/mongohelpers.cpp b/src/mongo/scripting/mozjs/mongohelpers.cpp index 5ca32e38f28..02db4115056 100644 --- a/src/mongo/scripting/mozjs/mongohelpers.cpp +++ b/src/mongo/scripting/mozjs/mongohelpers.cpp @@ -71,7 +71,7 @@ void MongoHelpersInfo::postInstall(JSContext* cx, JS::HandleObject global, JS::H // Initialize the reflection API and move it under the MongoHelpers object uassert(ErrorCodes::JSInterpreterFailure, "Error initializing javascript reflection API", - JS_InitReflect(cx, global)); + JS_InitReflectParse(cx, global)); JS::RootedValue reflectValue(cx); globalWrapper.getValue(kReflectName, &reflectValue); globalWrapper.deleteProperty(kReflectName); diff --git a/src/mongo/scripting/mozjs/numberlong.cpp b/src/mongo/scripting/mozjs/numberlong.cpp index 28d4999885d..2244c9d25b9 100644 --- a/src/mongo/scripting/mozjs/numberlong.cpp +++ b/src/mongo/scripting/mozjs/numberlong.cpp @@ -215,7 +215,7 @@ void NumberLongInfo::postInstall(JSContext* cx, JS::HandleObject global, JS::Han proto, getScope(cx)->getInternedStringId(InternedString::floatApprox), undef, - JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_SHARED, + JSPROP_ENUMERATE | JSPROP_SHARED, smUtils::wrapConstrainedMethod<Functions::floatApprox, true, NumberLongInfo>, nullptr)) { uasserted(ErrorCodes::JSInterpreterFailure, "Failed to JS_DefinePropertyById"); @@ -226,7 +226,7 @@ void NumberLongInfo::postInstall(JSContext* cx, JS::HandleObject global, JS::Han proto, getScope(cx)->getInternedStringId(InternedString::top), undef, - JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_SHARED, + JSPROP_ENUMERATE | JSPROP_SHARED, smUtils::wrapConstrainedMethod<Functions::top, true, NumberLongInfo>, nullptr)) { uasserted(ErrorCodes::JSInterpreterFailure, "Failed to JS_DefinePropertyById"); @@ -238,7 +238,7 @@ void NumberLongInfo::postInstall(JSContext* cx, JS::HandleObject global, JS::Han proto, getScope(cx)->getInternedStringId(InternedString::bottom), undef, - JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_SHARED, + JSPROP_ENUMERATE | JSPROP_SHARED, smUtils::wrapConstrainedMethod<Functions::bottom, true, NumberLongInfo>, nullptr)) { uasserted(ErrorCodes::JSInterpreterFailure, "Failed to JS_DefinePropertyById"); diff --git a/src/mongo/scripting/mozjs/objectwrapper.cpp b/src/mongo/scripting/mozjs/objectwrapper.cpp index eb15dacccc6..6f26833573d 100644 --- a/src/mongo/scripting/mozjs/objectwrapper.cpp +++ b/src/mongo/scripting/mozjs/objectwrapper.cpp @@ -537,13 +537,19 @@ ObjectWrapper::WriteFieldRecursionFrame::WriteFieldRecursionFrame(JSContext* cx, JSObject* obj, BSONObjBuilder* parent, StringData sd) - : thisv(cx, obj), ids(cx, JS_Enumerate(cx, thisv)) { + : thisv(cx, obj), ids(cx, JS::IdVector(cx)) { if (parent) { - subbob.emplace(JS_IsArrayObject(cx, thisv) ? parent->subarrayStart(sd) - : parent->subobjStart(sd)); + bool isArray; + + if (!JS_IsArrayObject(cx, thisv, &isArray)) { + throwCurrentJSException( + cx, ErrorCodes::JSInterpreterFailure, "Failure to check object is an array"); + } + + subbob.emplace(isArray ? parent->subarrayStart(sd) : parent->subobjStart(sd)); } - if (!ids) { + if (!JS_Enumerate(cx, thisv, &ids)) { throwCurrentJSException( cx, ErrorCodes::JSInterpreterFailure, "Failure to enumerate object"); } diff --git a/src/mongo/scripting/mozjs/objectwrapper.h b/src/mongo/scripting/mozjs/objectwrapper.h index 42be21ff36f..8c85a5b42d1 100644 --- a/src/mongo/scripting/mozjs/objectwrapper.h +++ b/src/mongo/scripting/mozjs/objectwrapper.h @@ -147,9 +147,9 @@ public: */ template <typename T> void enumerate(T&& callback) { - JS::AutoIdArray ids(_context, JS_Enumerate(_context, _object)); + JS::Rooted<JS::IdVector> ids(_context, JS::IdVector(_context)); - if (!ids) + if (!JS_Enumerate(_context, _object, &ids)) throwCurrentJSException( _context, ErrorCodes::JSInterpreterFailure, "Failure to enumerate object"); @@ -198,7 +198,7 @@ private: JS::RootedObject thisv; // ids for the keys of thisv - JS::AutoIdArray ids; + JS::Rooted<JS::IdVector> ids; // Current index of the current key we're working on std::size_t idx = 0; diff --git a/src/mongo/scripting/mozjs/oid.cpp b/src/mongo/scripting/mozjs/oid.cpp index e24dd3f0aca..afd6345441a 100644 --- a/src/mongo/scripting/mozjs/oid.cpp +++ b/src/mongo/scripting/mozjs/oid.cpp @@ -117,7 +117,7 @@ void OIDInfo::postInstall(JSContext* cx, JS::HandleObject global, JS::HandleObje proto, getScope(cx)->getInternedStringId(InternedString::str), undef, - JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_SHARED, + JSPROP_ENUMERATE | JSPROP_SHARED, smUtils::wrapConstrainedMethod<Functions::getter, true, OIDInfo>, nullptr)) { uasserted(ErrorCodes::JSInterpreterFailure, "Failed to JS_DefinePropertyById"); diff --git a/src/mongo/scripting/mozjs/valuereader.cpp b/src/mongo/scripting/mozjs/valuereader.cpp index bc1b61903ba..4383ab805a8 100644 --- a/src/mongo/scripting/mozjs/valuereader.cpp +++ b/src/mongo/scripting/mozjs/valuereader.cpp @@ -34,6 +34,7 @@ #include <cstdio> #include <js/CharacterEncoding.h> +#include <js/Date.h> #include "mongo/base/error_codes.h" #include "mongo/platform/decimal128.h" @@ -117,7 +118,7 @@ void ValueReader::fromBSONElement(const BSONElement& elem, const BSONObj& parent return; case mongo::Date: _value.setObjectOrNull( - JS_NewDateObjectMsec(_context, elem.Date().toMillisSinceEpoch())); + JS::NewDateObject(_context, JS::TimeClip(elem.Date().toMillisSinceEpoch()))); return; case mongo::Bool: _value.setBoolean(elem.Bool()); diff --git a/src/mongo/scripting/mozjs/valuewriter.cpp b/src/mongo/scripting/mozjs/valuewriter.cpp index 44465ef86d5..b4e015b1bc9 100644 --- a/src/mongo/scripting/mozjs/valuewriter.cpp +++ b/src/mongo/scripting/mozjs/valuewriter.cpp @@ -59,8 +59,15 @@ int ValueWriter::type() { return Undefined; if (_value.isString()) return String; - if (JS_IsArrayObject(_context, _value)) + + bool isArray; + + if (!JS_IsArrayObject(_context, _value, &isArray)) { + uasserted(ErrorCodes::BadValue, "unable to check if type is an array"); + } + if (isArray) return Array; + if (_value.isBoolean()) return Bool; @@ -73,8 +80,14 @@ int ValueWriter::type() { if (_value.isObject()) { JS::RootedObject obj(_context, _value.toObjectOrNull()); - if (JS_ObjectIsDate(_context, obj)) + bool isDate; + + if (!JS_ObjectIsDate(_context, obj, &isDate)) { + uasserted(ErrorCodes::BadValue, "unable to check if type is a date"); + } + if (isDate) return Date; + if (JS_ObjectIsFunction(_context, obj)) return Code; @@ -91,7 +104,14 @@ std::string ValueWriter::typeAsString() { return "undefined"; if (_value.isString()) return "string"; - if (JS_IsArrayObject(_context, _value)) + + bool isArray; + + if (!JS_IsArrayObject(_context, _value, &isArray)) { + uasserted(ErrorCodes::BadValue, "unable to check if type is an array"); + } + + if (isArray) return "array"; if (_value.isBoolean()) return "boolean"; @@ -100,10 +120,21 @@ std::string ValueWriter::typeAsString() { if (_value.isObject()) { JS::RootedObject obj(_context, _value.toObjectOrNull()); - if (JS_IsArrayObject(_context, obj)) + + if (!JS_IsArrayObject(_context, obj, &isArray)) { + uasserted(ErrorCodes::BadValue, "unable to check if type is an array"); + } + if (isArray) return "array"; - if (JS_ObjectIsDate(_context, obj)) + + bool isDate; + + if (!JS_ObjectIsDate(_context, obj, &isDate)) { + uasserted(ErrorCodes::BadValue, "unable to check if type is a date"); + } + if (isDate) return "date"; + if (JS_ObjectIsFunction(_context, obj)) return "function"; diff --git a/src/mongo/scripting/mozjs/wraptype.h b/src/mongo/scripting/mozjs/wraptype.h index 3729e964c0e..d6fb135da44 100644 --- a/src/mongo/scripting/mozjs/wraptype.h +++ b/src/mongo/scripting/mozjs/wraptype.h @@ -101,7 +101,7 @@ bool wrapFunction(JSContext* cx, unsigned argc, JS::Value* vp) { // Now all the spidermonkey type methods template <typename T> -bool addProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue v) { +bool addProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v) { try { T::addProperty(cx, obj, id, v); return true; @@ -134,9 +134,9 @@ bool construct(JSContext* cx, unsigned argc, JS::Value* vp) { }; template <typename T> -bool convert(JSContext* cx, JS::HandleObject obj, JSType type, JS::MutableHandleValue vp) { +bool delProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::ObjectOpResult& result) { try { - T::convert(cx, obj, type, vp); + T::delProperty(cx, obj, id, result); return true; } catch (...) { mongoToJSException(cx); @@ -145,9 +145,12 @@ bool convert(JSContext* cx, JS::HandleObject obj, JSType type, JS::MutableHandle }; template <typename T> -bool delProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* succeeded) { +bool enumerate(JSContext* cx, + JS::HandleObject obj, + JS::AutoIdVector& properties, + bool enumerableOnly) { try { - T::delProperty(cx, obj, id, succeeded); + T::enumerate(cx, obj, properties, enumerableOnly); return true; } catch (...) { mongoToJSException(cx); @@ -156,18 +159,13 @@ bool delProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* suc }; template <typename T> -bool enumerate(JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties) { - try { - T::enumerate(cx, obj, properties); +bool getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp) { + if (JSID_IS_SYMBOL(id)) { + // Just default to the SpiderMonkey's standard implementations for Symbol methods + vp.setUndefined(); return true; - } catch (...) { - mongoToJSException(cx); - return false; } -}; -template <typename T> -bool getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp) { try { T::getProperty(cx, obj, id, vp); return true; @@ -189,10 +187,13 @@ bool hasInstance(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp, }; template <typename T> -bool setProperty( - JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool strict, JS::MutableHandleValue vp) { +bool setProperty(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::MutableHandleValue vp, + JS::ObjectOpResult& result) { try { - T::setProperty(cx, obj, id, strict, vp); + T::setProperty(cx, obj, id, vp, result); return true; } catch (...) { mongoToJSException(cx); @@ -202,6 +203,12 @@ bool setProperty( template <typename T> bool resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolvedp) { + if (JSID_IS_SYMBOL(id)) { + // Just default to the SpiderMonkey's standard implementations for Symbol methods + *resolvedp = false; + return true; + } + try { T::resolve(cx, obj, id, resolvedp); return true; @@ -228,7 +235,7 @@ public: // We don't use the regular enumerate because we want the fancy new one nullptr, T::resolve != BaseInfo::resolve ? smUtils::resolve<T> : nullptr, - T::convert != BaseInfo::convert ? smUtils::convert<T> : nullptr, + T::mayResolve != BaseInfo::mayResolve ? T::mayResolve : nullptr, T::finalize != BaseInfo::finalize ? T::finalize : nullptr, T::call != BaseInfo::call ? smUtils::call<T> : nullptr, T::hasInstance != BaseInfo::hasInstance ? smUtils::hasInstance<T> : nullptr, @@ -279,15 +286,7 @@ public: * types without a constructor or inside the constructor */ void newObject(JS::MutableHandleObject out) { - // The regular form of JS_NewObject, where we pass proto as the - // third param, actually does a global object lookup for some - // reason. This way allows object creation with non-public - // prototypes and if someone deletes the symbol up the chain. - out.set(_assertPtr(JS_NewObject(_context, &_jsclass, JS::NullPtr()))); - - if (!JS_SetPrototype(_context, out, _proto)) - throwCurrentJSException( - _context, ErrorCodes::JSInterpreterFailure, "Failed to set prototype"); + out.set(_assertPtr(JS_NewObjectWithGivenProto(_context, &_jsclass, _proto))); } void newObject(JS::MutableHandleValue out) { @@ -385,7 +384,7 @@ private: // See newObject() for why we have to do this dance with the explicit // SetPrototype - _proto.init(_context, _assertPtr(JS_NewObject(_context, &_jsclass, JS::NullPtr()))); + _proto.init(_context, _assertPtr(JS_NewObject(_context, &_jsclass))); if (parent.get() && !JS_SetPrototype(_context, _proto, parent)) throwCurrentJSException( _context, ErrorCodes::JSInterpreterFailure, "Failed to set prototype"); @@ -404,7 +403,6 @@ private: dassert(T::addProperty == BaseInfo::addProperty); dassert(T::call == BaseInfo::call); dassert(T::construct == BaseInfo::construct); - dassert(T::convert == BaseInfo::convert); dassert(T::delProperty == BaseInfo::delProperty); dassert(T::enumerate == BaseInfo::enumerate); dassert(T::finalize == BaseInfo::finalize); @@ -445,7 +443,7 @@ private: // ensure that these two structures are equal. // // This is a landmine to watch out for during upgrades - using enumerateT = bool (*)(JSContext*, JS::HandleObject, JS::AutoIdVector&); + using enumerateT = bool (*)(JSContext*, JS::HandleObject, JS::AutoIdVector&, bool); void _installEnumerate(enumerateT enumerate) { if (!enumerate) return; @@ -486,7 +484,7 @@ private: if (!ctor) return; - auto ptr = JS_NewFunction(_context, ctor, 0, JSFUN_CONSTRUCTOR, JS::NullPtr(), nullptr); + auto ptr = JS_NewFunction(_context, ctor, 0, JSFUN_CONSTRUCTOR, nullptr); if (!ptr) { throwCurrentJSException( _context, ErrorCodes::JSInterpreterFailure, "Failed to install constructor"); diff --git a/src/third_party/SConscript b/src/third_party/SConscript index 616be6d7ff3..5ef4a01fa2b 100644 --- a/src/third_party/SConscript +++ b/src/third_party/SConscript @@ -8,7 +8,7 @@ boostSuffix = "-1.60.0" snappySuffix = '-1.1.3' zlibSuffix = '-1.2.8' pcreSuffix = "-8.38" -mozjsSuffix = '-38' +mozjsSuffix = '-45' yamlSuffix = '-0.5.3' icuSuffix = '-57.1' gperftoolsSuffix = '-2.5' diff --git a/src/third_party/mozjs-45/SConscript b/src/third_party/mozjs-45/SConscript new file mode 100644 index 00000000000..4d1efd7a58b --- /dev/null +++ b/src/third_party/mozjs-45/SConscript @@ -0,0 +1,136 @@ +# -*- mode: python -*- + +Import([ + "get_option", + "env", + ]) + +env = env.Clone() +env.InjectThirdPartyIncludePaths(libraries=['zlib']) + +def removeIfPresent(lst, item): + try: + lst.remove(item) + except ValueError: + pass + +for to_remove in ['-Werror', '-Wall', '-W']: + removeIfPresent(env['CCFLAGS'], to_remove) + +# See what -D's show up in make. The AB_CD one might change, but we're little +# endian only for now so I think it's sane +env.Prepend(CPPDEFINES=[ + 'IMPL_MFBT', + 'JS_USE_CUSTOM_ALLOCATOR', + 'STATIC_JS_API=1', + 'U_NO_DEFAULT_INCLUDE_UTF_HEADERS=1', + ]) + +if get_option('spider-monkey-dbg') == "on": + env.Prepend(CPPDEFINES=[ + 'DEBUG', + 'JS_DEBUG', + 'JS_GC_ZEAL', + ]) + +# js-confdefs.h has to get in front on windows or wherever +if env.TargetOSIs('windows'): + env.Prepend(CCFLAGS=[ + '/FI', 'js-confdefs.h', + + # 'declaration' : no matching operator delete found; memory will not be freed if + # initialization throws an exception + '/wd4291', + + # name" : the inline specifier cannot be used when a friend declaration refers to a + # specialization of a function template + '/wd4396', + + # nonstandard extension used : zero-sized array in struct/union + '/wd4200', + + # 'identifier' : no suitable definition provided for explicit template instantiation + # request + '/wd4661', + + # 'operation' : unsafe mix of type 'type' and type 'type' in operation + '/wd4805', + ]) +else: + if env.TargetOSIs('solaris'): + env.Prepend(CCFLAGS=[ + '-include', 'solaris_hacks.h' + ]) + + env.Append( + CCFLAGS=[ + '-include', 'js-confdefs.h', + '-Wno-invalid-offsetof', + ], + CXXFLAGS=[ + '-Wno-non-virtual-dtor', + ], + ) + +# js/src, js/public and mfbt are the only required sources right now, that +# could change in the future +# +# Also: +# We pre-generate configs for platforms and just check them in. Running +# mozilla's config requires a relatively huge portion of their tree. +env.Prepend(CPPPATH=[ + '#src', + '$BUILD_DIR', + 'extract/js/src', + 'extract/mfbt', + 'extract/intl/icu/source/common', + 'include', + 'mongo_sources', + 'platform/' + env["TARGET_ARCH"] + "/" + env["TARGET_OS"] + "/build", + 'platform/' + env["TARGET_ARCH"] + "/" + env["TARGET_OS"] + "/include", +]) + +sources = [ + "extract/js/src/builtin/RegExp.cpp", + "extract/js/src/frontend/Parser.cpp", + "extract/js/src/jsarray.cpp", + "extract/js/src/jsatom.cpp", + "extract/js/src/jsmath.cpp", + "extract/js/src/jsutil.cpp", + "extract/js/src/gc/StoreBuffer.cpp", + "extract/js/src/mfbt/Unified_cpp_mfbt0.cpp", + "extract/js/src/perf/pm_stub.cpp", + "extract/js/src/vm/Initialization.cpp", + "extract/mfbt/Compression.cpp", +] + + +if env['TARGET_ARCH'] == 'x86_64' and not env.TargetOSIs('solaris'): + sources.extend([ + "extract/js/src/jit/x86-shared/Disassembler-x86-shared.cpp", + ]) + +if env.TargetOSIs('windows'): + env.Prepend(CPPDEFINES=[ + ("_CRT_RAND_S", "1") + ]) + sources.extend([ + "extract/js/src/jit/ExecutableAllocatorWin.cpp", + ]) +else: + sources.extend([ + "extract/js/src/jit/ExecutableAllocatorPosix.cpp", + ]) + +sources.extend(Glob('platform/' + env["TARGET_ARCH"] + "/" + env["TARGET_OS"] + "/build/*.cpp")), + +# All of those unified sources come in from configure. The files don't +# actually build individually anymore. +env.Library( + target="mozjs", + source=sources, + LIBDEPS_TAGS=[ + # Depends on allocation symbols defined elsewhere + 'incomplete' + ], +) |