namespace mozjs { const JSFunctionSpec TimestampInfo::methods[2] = { MONGO_ATTACH_JS_CONSTRAINED_METHOD(toJSON, TimestampInfo), JS_FS_END, }; const char* const TimestampInfo::className = "Timestamp"; namespace { // Checks that argument 'idx' of 'args' is a number in the range of an unsigned 32-bit integer, // or uasserts a complaint about an invalid value for 'name'. double getTimestampArg(JSContext* cx, JS::CallArgs args, int idx, std::string name) { int64_t maxArgVal = std::numeric_limits<uint32_t>::max(); if (!args.get(idx).isNumber()) uasserted(ErrorCodes::BadValue, str::stream() << name << " must be a number"); int64_t val = ValueWriter(cx, args.get(idx)).toInt64(); if (val < 0 || val > maxArgVal) { uasserted(ErrorCodes::BadValue, str::stream() << name << " must be non-negative and not greater than " << maxArgVal << ", got " << val); } return val; } } // namespace 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 TimestampInfo::Functions::toJSON::call(JSContext* cx, JS::CallArgs args) { ObjectWrapper o(cx, args.thisv()); ValueReader(cx, args.rval()) .fromBSON(BSON("$timestamp" << BSON("t" << o.getNumber(InternedString::t) << "i" << o.getNumber(InternedString::i))), nullptr, false); } } // namespace mozjs
namespace mozjs { const JSFunctionSpec CodeInfo::methods[2] = { MONGO_ATTACH_JS_CONSTRAINED_METHOD(toString, CodeInfo), JS_FS_END, }; const char* const CodeInfo::className = "Code"; void CodeInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args) { ObjectWrapper o(cx, args.thisv()); std::string str = str::stream() << "Code({\"code\":\"" << o.getString(InternedString::code) << "\"," << "\"scope\":" << o.getObject(InternedString::scope) << "\"})"; ValueReader(cx, args.rval()).fromStringData(str); } 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); } } // namespace mozjs
namespace mozjs { const JSFunctionSpec MaxKeyInfo::methods[3] = { MONGO_ATTACH_JS_CONSTRAINED_METHOD(tojson, MaxKeyInfo), MONGO_ATTACH_JS_CONSTRAINED_METHOD(toJSON, MaxKeyInfo), JS_FS_END, }; const char* const MaxKeyInfo::className = "MaxKey"; void MaxKeyInfo::construct(JSContext* cx, JS::CallArgs args) { call(cx, args); } /** * 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 MaxKeyInfo::hasInstance(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp, bool* bp) { *bp = getScope(cx)->getProto<MaxKeyInfo>().instanceOf(vp); } void MaxKeyInfo::Functions::tojson::call(JSContext* cx, JS::CallArgs args) { ValueReader(cx, args.rval()).fromStringData("{ \"$maxKey\" : 1 }"); } void MaxKeyInfo::Functions::toJSON::call(JSContext* cx, JS::CallArgs args) { ValueReader(cx, args.rval()).fromBSON(BSON("$maxKey" << 1), nullptr, false); } void MaxKeyInfo::postInstall(JSContext* cx, JS::HandleObject global, JS::HandleObject proto) { ObjectWrapper protoWrapper(cx, proto); JS::RootedValue value(cx); getScope(cx)->getProto<MaxKeyInfo>().newObject(&value); ObjectWrapper(cx, global).setValue(InternedString::MaxKey, value); protoWrapper.setValue(InternedString::singleton, value); } } // namespace mozjs
namespace mozjs { const char* const NativeFunctionInfo::inheritFrom = "Function"; const char* const NativeFunctionInfo::className = "NativeFunction"; const JSFunctionSpec NativeFunctionInfo::methods[2] = { MONGO_ATTACH_JS_CONSTRAINED_METHOD(toString, NativeFunctionInfo), JS_FS_END, }; namespace { /** * Holder for the caller of ::make()'s callback function and context pointer */ class NativeHolder { public: NativeHolder(NativeFunction func, void* ctx) : _func(func), _ctx(ctx) {} NativeFunction _func; void* _ctx; }; NativeHolder* getHolder(JS::CallArgs args) { return static_cast<NativeHolder*>(JS_GetPrivate(&args.callee())); } } // namespace void NativeFunctionInfo::call(JSContext* cx, JS::CallArgs args) { auto holder = getHolder(args); if (!holder) { // Calling the prototype args.rval().setUndefined(); return; } JS::RootedObject robj(cx, JS_NewArrayObject(cx, args)); if (!robj) { uasserted(ErrorCodes::JSInterpreterFailure, "Failed to JS_NewArrayObject"); } BSONObj out = holder->_func(ObjectWrapper(cx, robj).toBSON(), holder->_ctx); ValueReader(cx, args.rval()).fromBSONElement(out.firstElement(), out, false); } void NativeFunctionInfo::finalize(js::FreeOp* fop, JSObject* obj) { auto holder = static_cast<NativeHolder*>(JS_GetPrivate(obj)); if (holder) getScope(fop)->trackedDelete(holder); } void NativeFunctionInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args) { ObjectWrapper o(cx, args.thisv()); str::stream ss; ss << "[native code]"; ValueReader(cx, args.rval()).fromStringData(ss.operator std::string()); } void NativeFunctionInfo::make(JSContext* cx, JS::MutableHandleObject obj, NativeFunction function, void* data) { auto scope = getScope(cx); scope->getProto<NativeFunctionInfo>().newObject(obj); JS_SetPrivate(obj, scope->trackedNew<NativeHolder>(function, data)); } } // namespace mozjs
namespace mozjs { const JSFunctionSpec NumberDecimalInfo::methods[3] = { MONGO_ATTACH_JS_CONSTRAINED_METHOD(toString, NumberDecimalInfo), MONGO_ATTACH_JS_CONSTRAINED_METHOD(toJSON, NumberDecimalInfo), JS_FS_END, }; const char* const NumberDecimalInfo::className = "NumberDecimal"; void NumberDecimalInfo::finalize(js::FreeOp* fop, JSObject* obj) { auto x = static_cast<Decimal128*>(JS_GetPrivate(obj)); if (x) getScope(fop)->trackedDelete(x); } Decimal128 NumberDecimalInfo::ToNumberDecimal(JSContext* cx, JS::HandleValue thisv) { auto x = static_cast<Decimal128*>(JS_GetPrivate(thisv.toObjectOrNull())); return x ? *x : Decimal128(0); } Decimal128 NumberDecimalInfo::ToNumberDecimal(JSContext* cx, JS::HandleObject thisv) { auto x = static_cast<Decimal128*>(JS_GetPrivate(thisv)); return x ? *x : Decimal128(0); } void NumberDecimalInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args) { Decimal128 val = NumberDecimalInfo::ToNumberDecimal(cx, args.thisv()); str::stream ss; ss << "NumberDecimal(\"" << val.toString() << "\")"; ValueReader(cx, args.rval()).fromStringData(ss.operator std::string()); } void NumberDecimalInfo::Functions::toJSON::call(JSContext* cx, JS::CallArgs args) { Decimal128 val = NumberDecimalInfo::ToNumberDecimal(cx, args.thisv()); ValueReader(cx, args.rval()).fromBSON(BSON("$numberDecimal" << val.toString()), nullptr, false); } 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); } void NumberDecimalInfo::make(JSContext* cx, JS::MutableHandleValue thisv, Decimal128 decimal) { auto scope = getScope(cx); scope->getProto<NumberDecimalInfo>().newObject(thisv); JS_SetPrivate(thisv.toObjectOrNull(), scope->trackedNew<Decimal128>(decimal)); } } // namespace mozjs
namespace mozjs { const JSFunctionSpec NumberIntInfo::methods[4] = { MONGO_ATTACH_JS_CONSTRAINED_METHOD(toNumber, NumberIntInfo), MONGO_ATTACH_JS_CONSTRAINED_METHOD(toString, NumberIntInfo), MONGO_ATTACH_JS_CONSTRAINED_METHOD(valueOf, NumberIntInfo), JS_FS_END, }; const char* const NumberIntInfo::className = "NumberInt"; void NumberIntInfo::finalize(JSFreeOp* fop, JSObject* obj) { auto x = static_cast<int*>(JS_GetPrivate(obj)); if (x) delete x; } int NumberIntInfo::ToNumberInt(JSContext* cx, JS::HandleValue thisv) { auto x = static_cast<int*>(JS_GetPrivate(thisv.toObjectOrNull())); return x ? *x : 0; } int NumberIntInfo::ToNumberInt(JSContext* cx, JS::HandleObject thisv) { auto x = static_cast<int*>(JS_GetPrivate(thisv)); return x ? *x : 0; } 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::call(JSContext* cx, JS::CallArgs args) { valueOf::call(cx, args); } void NumberIntInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args) { int val = NumberIntInfo::ToNumberInt(cx, args.thisv()); str::stream ss; ss << "NumberInt(" << val << ")"; ValueReader(cx, args.rval()).fromStringData(ss.operator std::string()); } 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); } } // namespace mozjs