Esempio n. 1
0
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
Esempio n. 2
0
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
Esempio n. 3
0
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
Esempio n. 4
0
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
Esempio n. 5
0
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
Esempio n. 6
0
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