BSONObj MozJSImplScope::callThreadArgs(const BSONObj& args) { MozJSEntry entry(this); JS::RootedValue function(_context); ValueReader(_context, &function).fromBSONElement(args.firstElement(), args, true); int argc = args.nFields() - 1; JS::AutoValueVector argv(_context); BSONObjIterator it(args); it.next(); JS::RootedValue value(_context); for (int i = 0; i < argc; ++i) { ValueReader(_context, &value).fromBSONElement(*it, args, true); argv.append(value); it.next(); } JS::RootedValue out(_context); JS::RootedObject thisv(_context); _checkErrorState(JS::Call(_context, thisv, function, argv, &out), false, true); JS::RootedObject rout(_context, JS_NewPlainObject(_context)); ObjectWrapper wout(_context, rout); wout.setValue("ret", out); return wout.toBSON(); }
BSONObj MozJSImplScope::callThreadArgs(const BSONObj& args) { MozJSEntry entry(this); JS::RootedValue function(_context); ValueReader(_context, &function).fromBSONElement(args.firstElement(), true); int argc = args.nFields() - 1; JS::AutoValueVector argv(_context); BSONObjIterator it(args); it.next(); JS::RootedValue value(_context); for (int i = 0; i < argc; ++i) { ValueReader(_context, &value).fromBSONElement(*it, true); argv.append(value); it.next(); } JS::RootedValue out(_context); JS::RootedObject thisv(_context); _checkErrorState(JS::Call(_context, thisv, function, argv, &out), false, true); BSONObjBuilder b; ValueWriter(_context, out).writeThis(&b, "ret"); return b.obj(); }
void MozJSImplScope::newFunction(StringData raw, JS::MutableHandleValue out) { MozJSEntry entry(this); std::string code = str::stream() << "____MongoToSM_newFunction_temp = " << raw; JS::CompileOptions co(_context); setCompileOptions(&co); _checkErrorState(JS::Evaluate(_context, _global, co, code.c_str(), code.length(), out)); }
bool MozJSImplScope::exec(StringData code, const std::string& name, bool printResult, bool reportError, bool assertOnError, int timeoutMs) { MozJSEntry entry(this); JS::CompileOptions co(_context); setCompileOptions(&co); co.setFile(name.c_str()); JS::RootedScript script(_context); bool success = JS::Compile(_context, _global, co, code.rawData(), code.size(), &script); if (_checkErrorState(success, reportError, assertOnError)) return false; if (timeoutMs) _engine->getDeadlineMonitor().startDeadline(this, timeoutMs); JS::RootedValue out(_context); success = JS_ExecuteScript(_context, _global, script, &out); if (timeoutMs) _engine->getDeadlineMonitor().stopDeadline(this); if (_checkErrorState(success, reportError, assertOnError)) return false; ObjectWrapper(_context, _global).setValue(kExecResult, out); if (printResult && !out.isUndefined()) { // appears to only be used by shell std::cout << ValueWriter(_context, out).toString() << std::endl; } return true; }
void MozJSImplScope::_MozJSCreateFunction(const char* raw, ScriptingFunction functionNumber, JS::MutableHandleValue fun) { std::string code = str::stream() << "_funcs" << functionNumber << " = " << parseJSFunctionOrExpression(_context, StringData(raw)); JS::CompileOptions co(_context); setCompileOptions(&co); _checkErrorState(JS::Evaluate(_context, _global, co, code.c_str(), code.length(), fun)); uassert(10232, "not a function", fun.isObject() && JS_ObjectIsFunction(_context, fun.toObjectOrNull())); }
// TODO: This function identification code is broken. Fix it up to be more robust // // See: SERVER-16703 for more info void MozJSImplScope::_MozJSCreateFunction(const char* raw, ScriptingFunction functionNumber, JS::MutableHandleValue fun) { std::string code = jsSkipWhiteSpace(raw); if (!hasFunctionIdentifier(code)) { if (code.find('\n') == std::string::npos && !hasJSReturn(code) && (code.find(';') == std::string::npos || code.find(';') == code.size() - 1)) { code = "return " + code; } code = "function(){ " + code + "}"; } code = str::stream() << "_funcs" << functionNumber << " = " << code; JS::CompileOptions co(_context); setCompileOptions(&co); _checkErrorState(JS::Evaluate(_context, _global, co, code.c_str(), code.length(), fun)); uassert(10232, "not a function", fun.isObject() && JS_ObjectIsFunction(_context, fun.toObjectOrNull())); }
int MozJSImplScope::invoke(ScriptingFunction func, const BSONObj* argsObject, const BSONObj* recv, int timeoutMs, bool ignoreReturn, bool readOnlyArgs, bool readOnlyRecv) { MozJSEntry entry(this); auto funcValue = _funcs[func - 1]; JS::RootedValue result(_context); const int nargs = argsObject ? argsObject->nFields() : 0; JS::AutoValueVector args(_context); if (nargs) { BSONObjIterator it(*argsObject); for (int i = 0; i < nargs; i++) { BSONElement next = it.next(); JS::RootedValue value(_context); ValueReader(_context, &value).fromBSONElement(next, *argsObject, readOnlyArgs); args.append(value); } } JS::RootedValue smrecv(_context); if (recv) ValueReader(_context, &smrecv).fromBSON(*recv, nullptr, readOnlyRecv); else smrecv.setObjectOrNull(_global); if (timeoutMs) _engine->getDeadlineMonitor().startDeadline(this, timeoutMs); JS::RootedValue out(_context); JS::RootedObject obj(_context, smrecv.toObjectOrNull()); bool success = JS::Call(_context, obj, funcValue, args, &out); if (timeoutMs) _engine->getDeadlineMonitor().stopDeadline(this); _checkErrorState(success); if (!ignoreReturn) { // must validate the handle because TerminateExecution may have // been thrown after the above checks if (out.isObject() && _nativeFunctionProto.instanceOf(out)) { warning() << "storing native function as return value"; _lastRetIsNativeCode = true; } else { _lastRetIsNativeCode = false; } ObjectWrapper(_context, _global).setValue(kInvokeResult, out); } return 0; }
MozJSImplScope::MozJSImplScope(MozJSScriptEngine* engine) : _engine(engine), _mr(), _runtime(_mr._runtime), _context(_mr._context), _globalProto(_context), _global(_globalProto.getProto()), _funcs(), _internedStrings(_context), _pendingKill(false), _opId(0), _opCtx(nullptr), _pendingGC(false), _connectState(ConnectState::Not), _status(Status::OK()), _quickExit(false), _generation(0), _binDataProto(_context), _bsonProto(_context), _countDownLatchProto(_context), _cursorProto(_context), _cursorHandleProto(_context), _dbCollectionProto(_context), _dbPointerProto(_context), _dbQueryProto(_context), _dbProto(_context), _dbRefProto(_context), _errorProto(_context), _jsThreadProto(_context), _maxKeyProto(_context), _minKeyProto(_context), _mongoExternalProto(_context), _mongoHelpersProto(_context), _mongoLocalProto(_context), _nativeFunctionProto(_context), _numberIntProto(_context), _numberLongProto(_context), _numberDecimalProto(_context), _objectProto(_context), _oidProto(_context), _regExpProto(_context), _timestampProto(_context) { kCurrentScope = this; // The default is quite low and doesn't seem to directly correlate with // malloc'd bytes. Set it to MAX_INT here and catching things in the // jscustomallocator.cpp JS_SetGCParameter(_runtime, JSGC_MAX_BYTES, 0xffffffff); JS_SetInterruptCallback(_runtime, _interruptCallback); JS_SetGCCallback(_runtime, _gcCallback, this); JS_SetContextPrivate(_context, this); JSAutoRequest ar(_context); JS_SetErrorReporter(_runtime, _reportError); JSAutoCompartment ac(_context, _global); _checkErrorState(JS_InitStandardClasses(_context, _global)); installBSONTypes(); JS_FireOnNewGlobalObject(_context, _global); execSetup(JSFiles::assert); execSetup(JSFiles::types); // install process-specific utilities in the global scope (dependancy: types.js, assert.js) if (_engine->getScopeInitCallback()) _engine->getScopeInitCallback()(*this); // install global utility functions installGlobalUtils(*this); _mongoHelpersProto.install(_global); }