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(); }
void DBRefInfo::construct(JSContext* cx, JS::CallArgs args) { if (!(args.length() == 2 || args.length() == 3)) uasserted(ErrorCodes::BadValue, "DBRef needs 2 or 3 arguments"); if (!args.get(0).isString()) uasserted(ErrorCodes::BadValue, "DBRef 1st parameter must be a string"); JS::RootedObject thisv(cx, JS_NewPlainObject(cx)); ObjectWrapper o(cx, thisv); o.setValue(InternedString::dollar_ref, args.get(0)); o.setValue(InternedString::dollar_id, args.get(1)); if (args.length() == 3) { if (!args.get(2).isString()) uasserted(ErrorCodes::BadValue, "DBRef 3rd parameter must be a string"); o.setValue(InternedString::dollar_db, args.get(2)); } JS::RootedObject out(cx); DBRefInfo::make(cx, &out, o.toBSON(), nullptr, false); args.rval().setObjectOrNull(out); }
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 MongoStatusInfo::fromStatus(JSContext* cx, Status status, JS::MutableHandleValue value) { auto scope = getScope(cx); JS::RootedValue undef(cx); undef.setUndefined(); JS::AutoValueArray<1> args(cx); ValueReader(cx, args[0]).fromStringData(status.reason()); JS::RootedObject error(cx); scope->getProto<ErrorInfo>().newInstance(args, &error); JS::RootedObject thisv(cx); scope->getProto<MongoStatusInfo>().newObjectWithProto(&thisv, error); ObjectWrapper thisvObj(cx, thisv); thisvObj.defineProperty( InternedString::code, undef, JSPROP_ENUMERATE | JSPROP_SHARED, smUtils::wrapConstrainedMethod<Functions::code, false, MongoStatusInfo>); thisvObj.defineProperty( InternedString::reason, undef, JSPROP_ENUMERATE | JSPROP_SHARED, smUtils::wrapConstrainedMethod<Functions::reason, false, MongoStatusInfo>); JS_SetPrivate(thisv, scope->trackedNew<Status>(std::move(status))); value.setObjectOrNull(thisv); }
void TimestampInfo::construct(JSContext* cx, JS::CallArgs args) { auto scope = getScope(cx); JS::RootedObject thisv(cx); scope->getProto<TimestampInfo>().newObject(&thisv); ObjectWrapper o(cx, thisv); if (args.length() == 0) { o.setNumber(InternedString::t, 0); o.setNumber(InternedString::i, 0); } else if (args.length() == 2) { if (!args.get(0).isNumber()) uasserted(ErrorCodes::BadValue, "Timestamp time must be a number"); if (!args.get(1).isNumber()) uasserted(ErrorCodes::BadValue, "Timestamp increment must be a number"); int64_t t = ValueWriter(cx, args.get(0)).toInt64(); int64_t largestVal = int64_t(Timestamp::max().getSecs()); if (t > largestVal) uasserted(ErrorCodes::BadValue, str::stream() << "The first argument must be in seconds; " << t << " is too large (max " << largestVal << ")"); o.setValue(InternedString::t, args.get(0)); o.setValue(InternedString::i, args.get(1)); } else { uasserted(ErrorCodes::BadValue, "Timestamp needs 0 or 2 arguments"); } args.rval().setObjectOrNull(thisv); }
void DBInfo::construct(JSContext* cx, JS::CallArgs args) { auto scope = getScope(cx); if (args.length() != 2) uasserted(ErrorCodes::BadValue, "db constructor requires 2 arguments"); for (unsigned i = 0; i < args.length(); ++i) { uassert(ErrorCodes::BadValue, "db initializer called with undefined argument", !args.get(i).isUndefined()); } JS::RootedObject thisv(cx); scope->getProto<DBInfo>().newObject(&thisv); ObjectWrapper o(cx, thisv); o.setValue(InternedString::_mongo, args.get(0)); o.setValue(InternedString::_name, args.get(1)); std::string dbName = ValueWriter(cx, args.get(1)).toString(); if (!NamespaceString::validDBName(dbName, NamespaceString::DollarInDbNameBehavior::Allow)) uasserted(ErrorCodes::BadValue, str::stream() << "[" << dbName << "] is not a valid database name"); args.rval().setObjectOrNull(thisv); }
void CodeInfo::construct(JSContext* cx, JS::CallArgs args) { uassert(ErrorCodes::BadValue, "Code needs 0, 1 or 2 arguments", args.length() == 0 || args.length() == 1 || args.length() == 2); auto scope = getScope(cx); JS::RootedObject thisv(cx); scope->getProto<CodeInfo>().newObject(&thisv); ObjectWrapper o(cx, thisv); if (args.length() == 0) { o.setString(InternedString::code, ""); } else if (args.length() == 1) { JS::HandleValue codeArg = args.get(0); if (!codeArg.isString()) uasserted(ErrorCodes::BadValue, "code must be a string"); o.setValue(InternedString::code, codeArg); } else { if (!args.get(0).isString()) uasserted(ErrorCodes::BadValue, "code must be a string"); if (!args.get(1).isObject()) uasserted(ErrorCodes::BadValue, "scope must be an object"); o.setValue(InternedString::code, args.get(0)); o.setValue(InternedString::scope, args.get(1)); } args.rval().setObjectOrNull(thisv); }
void DBCollectionInfo::construct(JSContext* cx, JS::CallArgs args) { auto scope = getScope(cx); if (args.length() != 4) uasserted(ErrorCodes::BadValue, "collection constructor requires 4 arguments"); for (unsigned i = 0; i < args.length(); ++i) { uassert(ErrorCodes::BadValue, "collection constructor called with undefined argument", !args.get(i).isUndefined()); } JS::RootedObject thisv(cx); scope->getDbCollectionProto().newObject(&thisv); ObjectWrapper o(cx, thisv); o.setValue("_mongo", args.get(0)); o.setValue("_db", args.get(1)); o.setValue("_shortName", args.get(2)); o.setValue("_fullName", args.get(3)); std::string fullName = ValueWriter(cx, args.get(3)).toString(); auto context = scope->getOpContext(); if (context && haveLocalShardingInfo(context->getClient(), fullName)) uasserted(ErrorCodes::BadValue, "can't use sharded collection from db.eval"); args.rval().setObjectOrNull(thisv); }
void OIDInfo::make(JSContext* cx, const OID& oid, JS::MutableHandleValue out) { auto scope = getScope(cx); JS::RootedObject thisv(cx); scope->getProto<OIDInfo>().newObject(&thisv); JS_SetPrivate(thisv, scope->trackedNew<OID>(oid)); out.setObjectOrNull(thisv); }
static void * callCountHook(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing, bool before, bool *ok, void *closure) { callCount[before]++; JS::RootedValue thisv(cx); frame.getThisValue(cx, &thisv); // assert if fp is incomplete return cx; // any non-null value causes the hook to be called again after }
bool rs::jsapi::Object::CallFunction(JSContext* cx, unsigned argc, JS::Value* vp) { JSAutoRequest ar(cx); char nameBuffer[256]; const char* name = nameBuffer; auto args = JS::CallArgsFromVp(argc, vp); auto func = JS_ValueToFunction(cx, args.calleev()); if (func != nullptr) { auto funcName = JS_GetFunctionId(func); if (funcName != nullptr) { auto nameLength = JS_EncodeStringToBuffer(cx, funcName, nameBuffer, sizeof(nameBuffer)); if ((nameLength + 1) < sizeof(nameBuffer)) { nameBuffer[nameLength] = '\0'; } else { std::vector<char> vBuffer(nameLength + 1); JS_EncodeStringToBuffer(cx, funcName, &vBuffer[0], nameLength); vBuffer[nameLength] = '\0'; name = &vBuffer[0]; } } } if (name == nullptr) { // TODO: test this case JS_ReportError(cx, "Unable to find function in libjsapi object"); return false; } else { auto that = args.thisv(); auto state = that.isObjectOrNull() ? Object::GetState(cx, JS::RootedObject(cx, that.toObjectOrNull())) : nullptr; if (state == nullptr) { // TODO: test this case JS_ReportError(cx, "Unable to find function callback in libjsapi object"); return false; } else { try { static thread_local std::vector<Value> vArgs; VectorUtils::ScopedVectorCleaner<Value> clean(vArgs); for (int i = 0; i < argc; ++i) { vArgs.emplace_back(cx, args.get(i)); } Value result(cx); state->functions[name](vArgs, result); args.rval().set(result); return true; } catch (const std::exception& ex) { JS_ReportError(cx, ex.what()); return false; } } } }
static void * nonStrictThisHook(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing, bool before, bool *ok, void *closure) { if (before) { bool *allWrapped = (bool *) closure; JS::RootedValue thisv(cx); frame.getThisValue(cx, &thisv); *allWrapped = *allWrapped && !JSVAL_IS_PRIMITIVE(thisv); } return NULL; }
static void * strictThisHook(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing, JSBool before, JSBool *ok, void *closure) { if (before) { bool *anyWrapped = (bool *) closure; js::RootedValue thisv(cx); frame.getThisValue(cx, thisv.address()); *anyWrapped = *anyWrapped || !JSVAL_IS_PRIMITIVE(thisv); } return NULL; }
void TimestampInfo::construct(JSContext* cx, JS::CallArgs args) { auto scope = getScope(cx); JS::RootedObject thisv(cx); scope->getProto<TimestampInfo>().newObject(&thisv); ObjectWrapper o(cx, thisv); if (args.length() == 0) { o.setNumber(InternedString::t, 0); o.setNumber(InternedString::i, 0); } else if (args.length() == 2) { o.setNumber(InternedString::t, getTimestampArg(cx, args, 0, "Timestamp time (seconds)")); o.setNumber(InternedString::i, getTimestampArg(cx, args, 1, "Timestamp increment")); } else { uasserted(ErrorCodes::BadValue, "Timestamp needs 0 or 2 arguments"); } args.rval().setObjectOrNull(thisv); }
void NumberIntInfo::construct(JSContext* cx, JS::CallArgs args) { auto scope = getScope(cx); JS::RootedObject thisv(cx); scope->getProto<NumberIntInfo>().newObject(&thisv); int32_t x = 0; if (args.length() == 0) { // Do nothing } else if (args.length() == 1) { x = ValueWriter(cx, args.get(0)).toInt32(); } else { uasserted(ErrorCodes::BadValue, "NumberInt takes 0 or 1 arguments"); } JS_SetPrivate(thisv, new int(x)); args.rval().setObjectOrNull(thisv); }
void DBPointerInfo::construct(JSContext* cx, JS::CallArgs args) { auto scope = getScope(cx); if (args.length() != 2) uasserted(ErrorCodes::BadValue, "DBPointer needs 2 arguments"); if (!args.get(0).isString()) uasserted(ErrorCodes::BadValue, "DBPointer 1st parameter must be a string"); if (!scope->getProto<OIDInfo>().instanceOf(args.get(1))) uasserted(ErrorCodes::BadValue, "DBPointer 2nd parameter must be an ObjectId"); JS::RootedObject thisv(cx); scope->getProto<DBPointerInfo>().newObject(&thisv); ObjectWrapper o(cx, thisv); o.setValue(InternedString::ns, args.get(0)); o.setValue(InternedString::id, args.get(1)); args.rval().setObjectOrNull(thisv); }
void NumberDecimalInfo::construct(JSContext* cx, JS::CallArgs args) { auto scope = getScope(cx); JS::RootedObject thisv(cx); scope->getProto<NumberDecimalInfo>().newObject(&thisv); Decimal128 x(0); if (args.length() == 0) { // Do nothing } else if (args.length() == 1) { x = ValueWriter(cx, args.get(0)).toDecimal128(); } else { uasserted(ErrorCodes::BadValue, "NumberDecimal takes 0 or 1 arguments"); } JS_SetPrivate(thisv, scope->trackedNew<Decimal128>(x)); args.rval().setObjectOrNull(thisv); }
/** * The idea here is that MinKey and MaxKey are singleton callable objects that * return the singleton when called. This enables all instances to compare * == and === to MinKey even if created by "new MinKey()" in JS. */ void MaxKeyInfo::call(JSContext* cx, JS::CallArgs args) { auto scope = getScope(cx); ObjectWrapper o(cx, scope->getProto<MaxKeyInfo>().getProto()); JS::RootedValue val(cx); if (!o.hasField(InternedString::singleton)) { JS::RootedObject thisv(cx); scope->getProto<MaxKeyInfo>().newObject(&thisv); val.setObjectOrNull(thisv); o.setValue(InternedString::singleton, val); } else { o.getValue(InternedString::singleton, &val); if (!getScope(cx)->getProto<MaxKeyInfo>().instanceOf(val)) uasserted(ErrorCodes::BadValue, "MaxKey singleton not of type MaxKey"); } args.rval().set(val); }
void BinDataInfo::construct(JSContext* cx, JS::CallArgs args) { auto scope = getScope(cx); if (args.length() != 2) { uasserted(ErrorCodes::BadValue, "BinData takes 2 arguments -- BinData(subtype,data)"); } auto type = args.get(0); auto typeNumber = ValueWriter(cx, type).toInt32(); if (!type.isNumber() || typeNumber < 0 || typeNumber > 255) { uasserted(ErrorCodes::BadValue, "BinData subtype must be a Number between 0 and 255 inclusive"); } auto utf = args.get(1); if (!utf.isString()) { uasserted(ErrorCodes::BadValue, "BinData data must be a String"); } auto str = ValueWriter(cx, utf).toString(); auto tmpBase64 = base64::decode(str); JS::RootedObject thisv(cx); scope->getProto<BinDataInfo>().newObject(&thisv); ObjectWrapper o(cx, thisv); JS::RootedValue len(cx); len.setInt32(tmpBase64.length()); o.defineProperty(InternedString::len, len, JSPROP_READONLY); o.defineProperty(InternedString::type, type, JSPROP_READONLY); JS_SetPrivate(thisv, scope->trackedNew<std::string>(std::move(str))); args.rval().setObjectOrNull(thisv); }
void DBCollectionInfo::construct(JSContext* cx, JS::CallArgs args) { auto scope = getScope(cx); if (args.length() != 4) uasserted(ErrorCodes::BadValue, "collection constructor requires 4 arguments"); for (unsigned i = 0; i < args.length(); ++i) { uassert(ErrorCodes::BadValue, "collection constructor called with undefined argument", !args.get(i).isUndefined()); } JS::RootedObject thisv(cx); scope->getProto<DBCollectionInfo>().newObject(&thisv); ObjectWrapper o(cx, thisv); o.setValue(InternedString::_mongo, args.get(0)); o.setValue(InternedString::_db, args.get(1)); o.setValue(InternedString::_shortName, args.get(2)); o.setValue(InternedString::_fullName, args.get(3)); args.rval().setObjectOrNull(thisv); }
void DBQueryInfo::construct(JSContext* cx, JS::CallArgs args) { auto scope = getScope(cx); if (args.length() < 4) uasserted(ErrorCodes::BadValue, "dbQuery constructor requires at least 4 arguments"); JS::RootedObject thisv(cx); scope->getProto<DBQueryInfo>().newObject(&thisv); ObjectWrapper o(cx, thisv); o.setValue(InternedString::_mongo, args.get(0)); o.setValue(InternedString::_db, args.get(1)); o.setValue(InternedString::_collection, args.get(2)); o.setValue(InternedString::_ns, args.get(3)); JS::RootedObject emptyObj(cx); JS::RootedValue emptyObjVal(cx); emptyObjVal.setObjectOrNull(emptyObj); JS::RootedValue nullVal(cx); nullVal.setNull(); if (args.length() > 4 && args.get(4).isObject()) { o.setValue(InternedString::_query, args.get(4)); } else { o.setValue(InternedString::_query, emptyObjVal); } if (args.length() > 5 && args.get(5).isObject()) { o.setValue(InternedString::_fields, args.get(5)); } else { o.setValue(InternedString::_fields, nullVal); } if (args.length() > 6 && args.get(6).isNumber()) { o.setValue(InternedString::_limit, args.get(6)); } else { o.setNumber(InternedString::_limit, 0); } if (args.length() > 7 && args.get(7).isNumber()) { o.setValue(InternedString::_skip, args.get(7)); } else { o.setNumber(InternedString::_skip, 0); } if (args.length() > 8 && args.get(8).isNumber()) { o.setValue(InternedString::_batchSize, args.get(8)); } else { o.setNumber(InternedString::_batchSize, 0); } if (args.length() > 9 && args.get(9).isNumber()) { o.setValue(InternedString::_options, args.get(9)); } else { o.setNumber(InternedString::_options, 0); } o.setValue(InternedString::_cursor, nullVal); o.setNumber(InternedString::_numReturned, 0); o.setBoolean(InternedString::_special, false); args.rval().setObjectOrNull(thisv); }