bool js::math_clz32(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); if (args.length() == 0) { args.rval().setInt32(32); return true; } uint32_t n; if (!ToUint32(cx, args[0], &n)) return false; if (n == 0) { args.rval().setInt32(32); return true; } args.rval().setInt32(mozilla::CountLeadingZeroes32(n)); return true; }
static bool ProtoSetterImpl(JSContext *cx, CallArgs args) { JS_ASSERT(TestProtoThis(args.thisv())); HandleValue thisv = args.thisv(); if (thisv.isPrimitive()) { JS_ASSERT(!thisv.isNullOrUndefined()); // Mutating a boxed primitive's [[Prototype]] has no side effects. args.rval().setUndefined(); return true; } if (!cx->runningWithTrustedPrincipals()) ++sSetProtoCalled; Rooted<JSObject*> obj(cx, &args.thisv().toObject()); /* Do nothing if __proto__ isn't being set to an object or null. */ if (args.length() == 0 || !args[0].isObjectOrNull()) { args.rval().setUndefined(); return true; } Rooted<JSObject*> newProto(cx, args[0].toObjectOrNull()); bool success; if (!JSObject::setProto(cx, obj, newProto, &success)) return false; if (!success) { js_ReportValueError(cx, JSMSG_SETPROTOTYPEOF_FAIL, JSDVG_IGNORE_STACK, thisv, js::NullPtr()); return false; } args.rval().setUndefined(); return true; }
bool js::intrinsic_DefineDataProperty(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); MOZ_ASSERT(args.length() == 4); MOZ_ASSERT(args[0].isObject()); MOZ_ASSERT(args[3].isInt32()); RootedObject obj(cx, &args[0].toObject()); RootedId id(cx); if (!ValueToId<CanGC>(cx, args[1], &id)) return false; RootedValue value(cx, args[2]); unsigned attributes = args[3].toInt32(); Rooted<PropDesc> desc(cx); MOZ_ASSERT(bool(attributes & ATTR_ENUMERABLE) != bool(attributes & ATTR_NONENUMERABLE), "_DefineDataProperty must receive either ATTR_ENUMERABLE xor ATTR_NONENUMERABLE"); PropDesc::Enumerability enumerable = PropDesc::Enumerability(bool(attributes & ATTR_ENUMERABLE)); MOZ_ASSERT(bool(attributes & ATTR_CONFIGURABLE) != bool(attributes & ATTR_NONCONFIGURABLE), "_DefineDataProperty must receive either ATTR_CONFIGURABLE xor " "ATTR_NONCONFIGURABLE"); PropDesc::Configurability configurable = PropDesc::Configurability(bool(attributes & ATTR_CONFIGURABLE)); MOZ_ASSERT(bool(attributes & ATTR_WRITABLE) != bool(attributes & ATTR_NONWRITABLE), "_DefineDataProperty must receive either ATTR_WRITABLE xor ATTR_NONWRITABLE"); PropDesc::Writability writable = PropDesc::Writability(bool(attributes & ATTR_WRITABLE)); desc.set(PropDesc(value, writable, enumerable, configurable)); bool result; return StandardDefineProperty(cx, obj, id, desc, true, &result); }
static bool File(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); if (args.length() == 0) { XPCThrower::Throw(NS_ERROR_UNEXPECTED, cx); return false; } nsCOMPtr<nsISupports> native; nsresult rv = nsDOMMultipartFile::NewFile(getter_AddRefs(native)); if (NS_FAILED(rv)) { XPCThrower::Throw(rv, cx); return false; } nsCOMPtr<nsIJSNativeInitializer> initializer = do_QueryInterface(native); MOZ_ASSERT(initializer); rv = initializer->Initialize(nullptr, cx, nullptr, args); if (NS_FAILED(rv)) { XPCThrower::Throw(rv, cx); return false; } nsXPConnect* xpc = nsXPConnect::XPConnect(); JSObject* glob = CurrentGlobalOrNull(cx); nsCOMPtr<nsIXPConnectJSObjectHolder> holder; rv = xpc->WrapNativeToJSVal(cx, glob, native, nullptr, &NS_GET_IID(nsISupports), true, args.rval().address()); if (NS_FAILED(rv)) { XPCThrower::Throw(rv, cx); return false; } return true; }
bool X4TypeDescr::call(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); const unsigned LANES = 4; if (args.length() < LANES) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED, args.callee().getClass()->name, "3", "s"); return false; } double values[LANES]; for (unsigned i = 0; i < LANES; i++) { if (!ToNumber(cx, args[i], &values[i])) return false; } Rooted<X4TypeDescr*> descr(cx, &args.callee().as<X4TypeDescr>()); Rooted<TypedObject*> result(cx, TypedObject::createZeroed(cx, descr, 0)); if (!result) return false; MOZ_ASSERT(!result->owner().isNeutered()); switch (descr->type()) { #define STORE_LANES(_constant, _type, _name) \ case _constant: \ { \ _type *mem = reinterpret_cast<_type*>(result->typedMem()); \ for (unsigned i = 0; i < LANES; i++) \ mem[i] = ConvertScalar<_type>(values[i]); \ break; \ } JS_FOR_EACH_X4_TYPE_REPR(STORE_LANES) #undef STORE_LANES } args.rval().setObject(*result); return true; }
bool js::math_tan(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); if (args.length() == 0) { args.rval().setNaN(); return true; } double x; if (!ToNumber(cx, args[0], &x)) return false; MathCache *mathCache = cx->runtime()->getMathCache(cx); if (!mathCache) return false; double z = math_tan_impl(mathCache, x); args.rval().setDouble(z); return true; }
bool js_math_sqrt(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); if (args.length() == 0) { args.rval().setDouble(js_NaN); return true; } double x; if (!ToNumber(cx, args[0], &x)) return false; MathCache *mathCache = cx->runtime()->getMathCache(cx); if (!mathCache) return false; double z = mathCache->lookup(sqrt, x); args.rval().setDouble(z); return true; }
bool js::intl_canonicalizeTimeZone(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); MOZ_ASSERT(args.length() == 1); MOZ_ASSERT(args[0].isString()); SharedIntlData& sharedIntlData = cx->runtime()->sharedIntlData.ref(); // Some time zone names are canonicalized differently by ICU -- handle // those first: RootedString timeZone(cx, args[0].toString()); RootedAtom ianaTimeZone(cx); if (!sharedIntlData.tryCanonicalizeTimeZoneConsistentWithIANA(cx, timeZone, &ianaTimeZone)) return false; if (ianaTimeZone) { cx->markAtom(ianaTimeZone); args.rval().setString(ianaTimeZone); return true; } AutoStableStringChars stableChars(cx); if (!stableChars.initTwoByte(cx, timeZone)) return false; mozilla::Range<const char16_t> tzchars = stableChars.twoByteRange(); JSString* str = CallICU(cx, [&tzchars](UChar* chars, uint32_t size, UErrorCode* status) { return ucal_getCanonicalTimeZoneID(tzchars.begin().get(), tzchars.length(), chars, size, nullptr, status); }); if (!str) return false; args.rval().setString(str); return true; }
/* ES5 15.2.4.6. */ static bool obj_isPrototypeOf(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); /* Step 1. */ if (args.length() < 1 || !args[0].isObject()) { args.rval().setBoolean(false); return true; } /* Step 2. */ RootedObject obj(cx, ToObject(cx, args.thisv())); if (!obj) return false; /* Step 3. */ bool isDelegate; if (!IsDelegate(cx, obj, args[0], &isDelegate)) return false; args.rval().setBoolean(isDelegate); return true; }
bool intrinsic_ParallelSpew(ThreadSafeContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); JS_ASSERT(args.length() == 1); JS_ASSERT(args[0].isString()); AutoCheckCannotGC nogc; ScopedThreadSafeStringInspector inspector(args[0].toString()); if (!inspector.ensureChars(cx, nogc)) return false; ScopedJSFreePtr<char> bytes; if (inspector.hasLatin1Chars()) bytes = JS::CharsToNewUTF8CharsZ(cx, inspector.latin1Range()).c_str(); else bytes = JS::CharsToNewUTF8CharsZ(cx, inspector.twoByteRange()).c_str(); parallel::Spew(parallel::SpewOps, bytes); args.rval().setUndefined(); return true; }
/* * SetScriptHints(fun, flags): Sets various internal hints to the ion * compiler for use when compiling |fun| or calls to |fun|. Flags * should be a dictionary object. * * The function |fun| should be a self-hosted function (in particular, * it *must* be a JS function). * * Possible flags: * - |cloneAtCallsite: true| will hint that |fun| should be cloned * each callsite to improve TI resolution. This is important for * higher-order functions like |Array.map|. */ static JSBool intrinsic_SetScriptHints(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); JS_ASSERT(args.length() >= 2); JS_ASSERT(args[0].isObject() && args[0].toObject().isFunction()); JS_ASSERT(args[1].isObject()); RootedFunction fun(cx, args[0].toObject().toFunction()); RootedScript funScript(cx, fun->nonLazyScript()); RootedObject flags(cx, &args[1].toObject()); RootedId id(cx); RootedValue propv(cx); id = AtomToId(Atomize(cx, "cloneAtCallsite", strlen("cloneAtCallsite"))); if (!JSObject::getGeneric(cx, flags, flags, id, &propv)) return false; if (ToBoolean(propv)) funScript->shouldCloneAtCallsite = true; return true; }
bool js::intl_IsValidTimeZoneName(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); MOZ_ASSERT(args.length() == 1); MOZ_ASSERT(args[0].isString()); SharedIntlData& sharedIntlData = cx->runtime()->sharedIntlData.ref(); RootedString timeZone(cx, args[0].toString()); RootedAtom validatedTimeZone(cx); if (!sharedIntlData.validateTimeZoneName(cx, timeZone, &validatedTimeZone)) return false; if (validatedTimeZone) { cx->markAtom(validatedTimeZone); args.rval().setString(validatedTimeZone); } else { args.rval().setNull(); } return true; }
bool CrossCompartmentWrapper::call(JSContext *cx, HandleObject wrapper, const CallArgs &args) { RootedObject wrapped(cx, wrappedObject(wrapper)); { AutoCompartment call(cx, wrapped); args.setCallee(ObjectValue(*wrapped)); if (!cx->compartment->wrap(cx, args.mutableThisv())) return false; for (size_t n = 0; n < args.length(); ++n) { if (!cx->compartment->wrap(cx, args.handleAt(n))) return false; } if (!Wrapper::call(cx, wrapper, args)) return false; } return cx->compartment->wrap(cx, args.rval()); }
static bool intrinsic_MakeConstructible(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); JS_ASSERT(args.length() == 2); JS_ASSERT(args[0].isObject()); JS_ASSERT(args[0].toObject().is<JSFunction>()); JS_ASSERT(args[1].isObject()); // Normal .prototype properties aren't enumerable. But for this to clone // correctly, it must be enumerable. RootedObject ctor(cx, &args[0].toObject()); if (!JSObject::defineProperty(cx, ctor, cx->names().prototype, args[1], JS_PropertyStub, JS_StrictPropertyStub, JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT)) { return false; } ctor->as<JSFunction>().setIsSelfHostedConstructor(); args.rval().setUndefined(); return true; }
static bool WasmTextToBinary(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); RootedObject callee(cx, &args.callee()); if (args.length() != 1) { ReportUsageError(cx, callee, "Wrong number of arguments"); return false; } if (!args[0].isString()) { ReportUsageError(cx, callee, "First argument must be a String"); return false; } AutoStableStringChars twoByteChars(cx); if (!twoByteChars.initTwoByte(cx, args[0].toString())) return false; UniqueChars error; wasm::UniqueBytecode bytes = wasm::TextToBinary(twoByteChars.twoByteChars(), &error); if (!bytes) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_TEXT_FAIL, error.get() ? error.get() : "out of memory"); return false; } Rooted<ArrayBufferObject*> buffer(cx, ArrayBufferObject::create(cx, bytes->length())); if (!buffer) return false; memcpy(buffer->dataPointer(), bytes->begin(), bytes->length()); args.rval().setObject(*buffer); return true; }
bool js::intl_patternForSkeleton(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); MOZ_ASSERT(args.length() == 2); MOZ_ASSERT(args[0].isString()); MOZ_ASSERT(args[1].isString()); JSAutoByteString locale(cx, args[0].toString()); if (!locale) return false; AutoStableStringChars skeleton(cx); if (!skeleton.initTwoByte(cx, args[1].toString())) return false; mozilla::Range<const char16_t> skelChars = skeleton.twoByteRange(); UErrorCode status = U_ZERO_ERROR; UDateTimePatternGenerator* gen = udatpg_open(IcuLocale(locale.ptr()), &status); if (U_FAILURE(status)) { intl::ReportInternalError(cx); return false; } ScopedICUObject<UDateTimePatternGenerator, udatpg_close> toClose(gen); JSString* str = CallICU(cx, [gen, &skelChars](UChar* chars, uint32_t size, UErrorCode* status) { return udatpg_getBestPattern(gen, skelChars.begin().get(), skelChars.length(), chars, size, status); }); if (!str) return false; args.rval().setString(str); return true; }
MOZ_ALWAYS_INLINE bool WeakMap_has_impl(JSContext *cx, CallArgs args) { JS_ASSERT(IsWeakMap(args.thisv())); if (args.length() < 1) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED, "WeakMap.has", "0", "s"); return false; } JSObject *key = GetKeyArg(cx, args); if (!key) return false; if (ObjectValueMap *map = args.thisv().toObject().as<WeakMapObject>().getMap()) { if (map->has(key)) { args.rval().setBoolean(true); return true; } } args.rval().setBoolean(false); return true; }
bool js::obj_construct(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); RootedObject obj(cx, nullptr); if (args.isConstructing() && (&args.newTarget().toObject() != &args.callee())) { RootedObject newTarget(cx, &args.newTarget().toObject()); obj = CreateThis(cx, &PlainObject::class_, newTarget); if (!obj) return false; } else if (args.length() > 0 && !args[0].isNullOrUndefined()) { obj = ToObject(cx, args[0]); if (!obj) return false; } else { /* Make an object whether this was called with 'new' or not. */ if (!NewObjectScriptedCall(cx, &obj)) return false; } args.rval().setObject(*obj); return true; }
static bool InternalConst(JSContext *cx, unsigned argc, jsval *vp) { CallArgs args = CallArgsFromVp(argc, vp); if (args.length() == 0) { JS_ReportError(cx, "the function takes exactly one argument"); return false; } JSString *str = ToString(cx, args[0]); if (!str) return false; JSFlatString *flat = JS_FlattenString(cx, str); if (!flat) return false; if (JS_FlatStringEqualsAscii(flat, "INCREMENTAL_MARK_STACK_BASE_CAPACITY")) { vp[0] = UINT_TO_JSVAL(js::INCREMENTAL_MARK_STACK_BASE_CAPACITY); } else { JS_ReportError(cx, "unknown const name"); return false; } return true; }
bool RilConsumer::PostRILMessage(JSContext* aCx, unsigned aArgc, Value* aVp) { CallArgs args = CallArgsFromVp(aArgc, aVp); if (args.length() != 2) { JS_ReportError(aCx, "Expecting two arguments with the RIL message"); return false; } int clientId = args[0].toInt32(); if ((ssize_t)sRilConsumers.Length() <= clientId || !sRilConsumers[clientId]) { // Probably shutting down. return true; } nsresult rv = sRilConsumers[clientId]->Send(aCx, args); if (NS_FAILED(rv)) { return false; } return true; }
bool Library::Close(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); JSObject* obj = JS_THIS_OBJECT(cx, vp); if (!obj) return false; if (!IsLibrary(obj)) { JS_ReportError(cx, "not a library"); return false; } if (args.length() != 0) { JS_ReportError(cx, "close doesn't take any arguments"); return false; } // delete our internal objects UnloadLibrary(obj); JS_SetReservedSlot(obj, SLOT_LIBRARY, PrivateValue(nullptr)); args.rval().setUndefined(); return true; }
static bool WeakMap_has_impl(JSContext *cx, CallArgs args) { JS_ASSERT(IsWeakMap(args.thisv())); if (args.length() < 1) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, "WeakMap.has", "0", "s"); return false; } JSObject *key = GetKeyArg(cx, args); if (!key) return false; if (ObjectValueMap *map = GetObjectMap(&args.thisv().toObject())) { if (ObjectValueMap::Ptr ptr = map->lookup(key)) { args.rval().setBoolean(true); return true; } } args.rval().setBoolean(false); return true; }
bool Library::Open(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); JSObject* ctypesObj = JS_THIS_OBJECT(cx, vp); if (!ctypesObj) return false; if (!IsCTypesGlobal(ctypesObj)) { JS_ReportErrorASCII(cx, "not a ctypes object"); return false; } if (args.length() != 1 || args[0].isUndefined()) { JS_ReportErrorASCII(cx, "open requires a single argument"); return false; } JSObject* library = Create(cx, args[0], GetCallbacks(ctypesObj)); if (!library) return false; args.rval().setObject(*library); return true; }
bool ContextStack::pushInvokeFrame(JSContext *cx, const CallArgs &args, InitialFrameFlags initial, InvokeFrameGuard *ifg) { JS_ASSERT(onTop()); JS_ASSERT(space().firstUnused() == args.end()); JSObject &callee = args.callee(); JSFunction *fun = callee.toFunction(); JSScript *script = fun->script(); StackFrame::Flags flags = ToFrameFlags(initial); StackFrame *fp = getCallFrame(cx, REPORT_ERROR, args, fun, script, &flags); if (!fp) return false; fp->initCallFrame(cx, *fun, script, args.length(), flags); ifg->regs_.prepareToRun(*fp, script); ifg->prevRegs_ = seg_->pushRegs(ifg->regs_); JS_ASSERT(space().firstUnused() == ifg->regs_.sp); ifg->setPushed(*this); return true; }
bool WrapperOwner::callOrConstruct(JSContext* cx, HandleObject proxy, const CallArgs& args, bool construct) { ObjectId objId = idOf(proxy); InfallibleTArray<JSParam> vals; AutoValueVector outobjects(cx); RootedValue v(cx); for (size_t i = 0; i < args.length() + 2; i++) { // The |this| value for constructors is a magic value that we won't be // able to convert, so skip it. if (i == 1 && construct) v = UndefinedValue(); else v = args.base()[i]; if (v.isObject()) { RootedObject obj(cx, &v.toObject()); if (xpc::IsOutObject(cx, obj)) { // Make sure it is not an in-out object. bool found; if (!JS_HasProperty(cx, obj, "value", &found)) return false; if (found) { JS_ReportErrorASCII(cx, "in-out objects cannot be sent via CPOWs yet"); return false; } vals.AppendElement(JSParam(void_t())); if (!outobjects.append(ObjectValue(*obj))) return false; continue; } } JSVariant val; if (!toVariant(cx, v, &val)) return false; vals.AppendElement(JSParam(val)); } JSVariant result; ReturnStatus status; InfallibleTArray<JSParam> outparams; if (!SendCallOrConstruct(objId, vals, construct, &status, &result, &outparams)) return ipcfail(cx); LOG_STACK(); if (!ok(cx, status)) return false; if (outparams.Length() != outobjects.length()) return ipcfail(cx); RootedObject obj(cx); for (size_t i = 0; i < outparams.Length(); i++) { // Don't bother doing anything for outparams that weren't set. if (outparams[i].type() == JSParam::Tvoid_t) continue; // Take the value the child process returned, and set it on the XPC // object. if (!fromVariant(cx, outparams[i], &v)) return false; obj = &outobjects[i].toObject(); if (!JS_SetProperty(cx, obj, "value", v)) return false; } if (!fromVariant(cx, result, args.rval())) return false; return true; }
/* * Compile a new |RegExpShared| for the |RegExpObject|. * * Per ECMAv5 15.10.4.1, we act on combinations of (pattern, flags) as * arguments: * * RegExp, undefined => flags := pattern.flags * RegExp, _ => throw TypeError * _ => pattern := ToString(pattern) if defined(pattern) else '' * flags := ToString(flags) if defined(flags) else '' */ static bool CompileRegExpObject(JSContext *cx, RegExpObjectBuilder &builder, CallArgs args) { if (args.length() == 0) { RegExpStatics *res = cx->regExpStatics(); Rooted<JSAtom*> empty(cx, cx->runtime->emptyString); RegExpObject *reobj = builder.build(empty, res->getFlags()); if (!reobj) return false; args.rval().setObject(*reobj); return true; } RootedValue sourceValue(cx, args[0]); /* * If we get passed in an object whose internal [[Class]] property is * "RegExp", return a new object with the same source/flags. */ if (IsObjectWithClass(sourceValue, ESClass_RegExp, cx)) { /* * Beware, sourceObj may be a (transparent) proxy to a RegExp, so only * use generic (proxyable) operations on sourceObj that do not assume * sourceObj.isRegExp(). */ RootedObject sourceObj(cx, &sourceValue.toObject()); if (args.hasDefined(1)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEWREGEXP_FLAGGED); return false; } /* * Only extract the 'flags' out of sourceObj; do not reuse the * RegExpShared since it may be from a different compartment. */ RegExpFlag flags; { RegExpGuard g(cx); if (!RegExpToShared(cx, sourceObj, &g)) return false; flags = g->getFlags(); } /* * 'toSource' is a permanent read-only property, so this is equivalent * to executing RegExpObject::getSource on the unwrapped object. */ RootedValue v(cx); if (!JSObject::getProperty(cx, sourceObj, sourceObj, cx->names().source, &v)) return false; Rooted<JSAtom*> sourceAtom(cx, &v.toString()->asAtom()); RegExpObject *reobj = builder.build(sourceAtom, flags); if (!reobj) return false; args.rval().setObject(*reobj); return true; } RootedAtom source(cx); if (sourceValue.isUndefined()) { source = cx->runtime->emptyString; } else { /* Coerce to string and compile. */ JSString *str = ToString<CanGC>(cx, sourceValue); if (!str) return false; source = AtomizeString<CanGC>(cx, str); if (!source) return false; } RegExpFlag flags = RegExpFlag(0); if (args.hasDefined(1)) { RootedString flagStr(cx, ToString<CanGC>(cx, args[1])); if (!flagStr) return false; args[1].setString(flagStr); if (!ParseRegExpFlags(cx, flagStr, &flags)) return false; } RootedAtom escapedSourceStr(cx, EscapeNakedForwardSlashes(cx, source)); if (!escapedSourceStr) return false; if (!js::RegExpShared::checkSyntax(cx, NULL, escapedSourceStr)) return false; RegExpStatics *res = cx->regExpStatics(); RegExpObject *reobj = builder.build(escapedSourceStr, RegExpFlag(flags | res->getFlags())); if (!reobj) return false; args.rval().setObject(*reobj); return true; }
// Common code implementing direct and indirect eval. // // Evaluate call.argv[2], if it is a string, in the context of the given calling // frame, with the provided scope chain, with the semantics of either a direct // or indirect eval (see ES5 10.4.2). If this is an indirect eval, scopeobj // must be a global object. // // On success, store the completion value in call.rval and return true. static bool EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFramePtr caller, HandleObject scopeobj, jsbytecode *pc) { JS_ASSERT((evalType == INDIRECT_EVAL) == !caller); JS_ASSERT((evalType == INDIRECT_EVAL) == !pc); JS_ASSERT_IF(evalType == INDIRECT_EVAL, scopeobj->is<GlobalObject>()); AssertInnerizedScopeChain(cx, *scopeobj); Rooted<GlobalObject*> scopeObjGlobal(cx, &scopeobj->global()); if (!GlobalObject::isRuntimeCodeGenEnabled(cx, scopeObjGlobal)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_EVAL); return false; } // ES5 15.1.2.1 step 1. if (args.length() < 1) { args.rval().setUndefined(); return true; } if (!args[0].isString()) { args.rval().set(args[0]); return true; } RootedString str(cx, args[0].toString()); // ES5 15.1.2.1 steps 2-8. // Per ES5, indirect eval runs in the global scope. (eval is specified this // way so that the compiler can make assumptions about what bindings may or // may not exist in the current frame if it doesn't see 'eval'.) unsigned staticLevel; RootedValue thisv(cx); if (evalType == DIRECT_EVAL) { JS_ASSERT_IF(caller.isInterpreterFrame(), !caller.asInterpreterFrame()->runningInJit()); staticLevel = caller.script()->staticLevel() + 1; // Direct calls to eval are supposed to see the caller's |this|. If we // haven't wrapped that yet, do so now, before we make a copy of it for // the eval code to use. if (!ComputeThis(cx, caller)) return false; thisv = caller.thisValue(); } else { JS_ASSERT(args.callee().global() == *scopeobj); staticLevel = 0; // Use the global as 'this', modulo outerization. JSObject *thisobj = JSObject::thisObject(cx, scopeobj); if (!thisobj) return false; thisv = ObjectValue(*thisobj); } Rooted<JSFlatString*> flatStr(cx, str->ensureFlat(cx)); if (!flatStr) return false; RootedScript callerScript(cx, caller ? caller.script() : nullptr); EvalJSONResult ejr = TryEvalJSON(cx, callerScript, flatStr, args.rval()); if (ejr != EvalJSON_NotJSON) return ejr == EvalJSON_Success; EvalScriptGuard esg(cx); if (evalType == DIRECT_EVAL && caller.isNonEvalFunctionFrame()) esg.lookupInEvalCache(flatStr, callerScript, pc); if (!esg.foundScript()) { RootedScript maybeScript(cx); unsigned lineno; const char *filename; JSPrincipals *originPrincipals; uint32_t pcOffset; DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno, &pcOffset, &originPrincipals, evalType == DIRECT_EVAL ? CALLED_FROM_JSOP_EVAL : NOT_CALLED_FROM_JSOP_EVAL); const char *introducerFilename = filename; if (maybeScript && maybeScript->scriptSource()->introducerFilename()) introducerFilename = maybeScript->scriptSource()->introducerFilename(); CompileOptions options(cx); options.setFileAndLine(filename, 1) .setCompileAndGo(true) .setForEval(true) .setNoScriptRval(false) .setOriginPrincipals(originPrincipals) .setIntroductionInfo(introducerFilename, "eval", lineno, maybeScript, pcOffset); AutoStableStringChars flatChars(cx); if (!flatChars.initTwoByte(cx, flatStr)) return false; const char16_t *chars = flatChars.twoByteRange().start().get(); SourceBufferHolder::Ownership ownership = flatChars.maybeGiveOwnershipToCaller() ? SourceBufferHolder::GiveOwnership : SourceBufferHolder::NoOwnership; SourceBufferHolder srcBuf(chars, flatStr->length(), ownership); JSScript *compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(), scopeobj, callerScript, options, srcBuf, flatStr, staticLevel); if (!compiled) return false; esg.setNewScript(compiled); } return ExecuteKernel(cx, esg.script(), *scopeobj, thisv, ExecuteType(evalType), NullFramePtr() /* evalInFrame */, args.rval().address()); }
bool Library::Declare(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); RootedObject obj(cx, JS_THIS_OBJECT(cx, vp)); if (!obj) return false; if (!IsLibrary(obj)) { JS_ReportErrorASCII(cx, "not a library"); return false; } PRLibrary* library = GetLibrary(obj); if (!library) { JS_ReportErrorASCII(cx, "library not open"); return false; } // We allow two API variants: // 1) library.declare(name, abi, returnType, argType1, ...) // declares a function with the given properties, and resolves the symbol // address in the library. // 2) library.declare(name, type) // declares a symbol of 'type', and resolves it. The object that comes // back will be of type 'type', and will point into the symbol data. // This data will be both readable and writable via the usual CData // accessors. If 'type' is a PointerType to a FunctionType, the result will // be a function pointer, as with 1). if (args.length() < 2) { JS_ReportErrorASCII(cx, "declare requires at least two arguments"); return false; } if (!args[0].isString()) { JS_ReportErrorASCII(cx, "first argument must be a string"); return false; } RootedObject fnObj(cx, nullptr); RootedObject typeObj(cx); bool isFunction = args.length() > 2; if (isFunction) { // Case 1). // Create a FunctionType representing the function. fnObj = FunctionType::CreateInternal(cx, args[1], args[2], HandleValueArray::subarray(args, 3, args.length() - 3)); if (!fnObj) return false; // Make a function pointer type. typeObj = PointerType::CreateInternal(cx, fnObj); if (!typeObj) return false; } else { // Case 2). if (args[1].isPrimitive() || !CType::IsCType(args[1].toObjectOrNull()) || !CType::IsSizeDefined(args[1].toObjectOrNull())) { JS_ReportErrorASCII(cx, "second argument must be a type of defined size"); return false; } typeObj = args[1].toObjectOrNull(); if (CType::GetTypeCode(typeObj) == TYPE_pointer) { fnObj = PointerType::GetBaseType(typeObj); isFunction = fnObj && CType::GetTypeCode(fnObj) == TYPE_function; } } void* data; PRFuncPtr fnptr; RootedString nameStr(cx, args[0].toString()); AutoCString symbol; if (isFunction) { // Build the symbol, with mangling if necessary. FunctionType::BuildSymbolName(nameStr, fnObj, symbol); AppendString(symbol, "\0"); // Look up the function symbol. fnptr = PR_FindFunctionSymbol(library, symbol.begin()); if (!fnptr) { JS_ReportErrorASCII(cx, "couldn't find function symbol in library"); return false; } data = &fnptr; } else { // 'typeObj' is another data type. Look up the data symbol. AppendString(symbol, nameStr); AppendString(symbol, "\0"); data = PR_FindSymbol(library, symbol.begin()); if (!data) { JS_ReportErrorASCII(cx, "couldn't find symbol in library"); return false; } } RootedObject result(cx, CData::Create(cx, typeObj, obj, data, isFunction)); if (!result) return false; if (isFunction) JS_SetReservedSlot(result, SLOT_FUNNAME, StringValue(nameStr)); args.rval().setObject(*result); // Seal the CData object, to prevent modification of the function pointer. // This permanently associates this object with the library, and avoids // having to do things like reset SLOT_REFERENT when someone tries to // change the pointer value. // XXX This will need to change when bug 541212 is fixed -- CData::ValueSetter // could be called on a sealed object. if (isFunction && !JS_FreezeObject(cx, result)) return false; return true; }
// The JSNative for the functions nested in an asm.js module. Calling this // native will trampoline into generated code. static bool CallAsmJS(JSContext *cx, unsigned argc, Value *vp) { CallArgs callArgs = CallArgsFromVp(argc, vp); RootedFunction callee(cx, &callArgs.callee().as<JSFunction>()); // An asm.js function stores, in its extended slots: // - a pointer to the module from which it was returned // - its index in the ordered list of exported functions RootedObject moduleObj(cx, &callee->getExtendedSlot(ASM_MODULE_SLOT).toObject()); AsmJSModule &module = moduleObj->as<AsmJSModuleObject>().module(); // An exported function points to the code as well as the exported // function's signature, which implies the dynamic coercions performed on // the arguments. unsigned exportIndex = callee->getExtendedSlot(ASM_EXPORT_INDEX_SLOT).toInt32(); const AsmJSModule::ExportedFunction &func = module.exportedFunction(exportIndex); // An asm.js module is specialized to its heap's base address and length // which is normally immutable except for the neuter operation that occurs // when an ArrayBuffer is transfered. Throw an internal error if we try to // run with a neutered heap. if (module.maybeHeapBufferObject() && module.maybeHeapBufferObject()->isNeutered()) { js_ReportOverRecursed(cx); return false; } // The calling convention for an external call into asm.js is to pass an // array of 8-byte values where each value contains either a coerced int32 // (in the low word) or double value, with the coercions specified by the // asm.js signature. The external entry point unpacks this array into the // system-ABI-specified registers and stack memory and then calls into the // internal entry point. The return value is stored in the first element of // the array (which, therefore, must have length >= 1). js::Vector<uint64_t, 8> coercedArgs(cx); if (!coercedArgs.resize(Max<size_t>(1, func.numArgs()))) return false; RootedValue v(cx); for (unsigned i = 0; i < func.numArgs(); ++i) { v = i < callArgs.length() ? callArgs[i] : UndefinedValue(); switch (func.argCoercion(i)) { case AsmJS_ToInt32: if (!ToInt32(cx, v, (int32_t*)&coercedArgs[i])) return false; break; case AsmJS_ToNumber: if (!ToNumber(cx, v, (double*)&coercedArgs[i])) return false; break; case AsmJS_FRound: if (!RoundFloat32(cx, v, (float *)&coercedArgs[i])) return false; break; } } { // Push an AsmJSActivation to describe the asm.js frames we're about to // push when running this module. Additionally, push a JitActivation so // that the optimized asm.js-to-Ion FFI call path (which we want to be // very fast) can avoid doing so. The JitActivation is marked as // inactive so stack iteration will skip over it. AsmJSActivation activation(cx, module, exportIndex); JitActivation jitActivation(cx, /* firstFrameIsConstructing = */ false, /* active */ false); // Call the per-exported-function trampoline created by GenerateEntry. AsmJSModule::CodePtr enter = module.entryTrampoline(func); if (!CALL_GENERATED_ASMJS(enter, coercedArgs.begin(), module.globalData())) return false; } switch (func.returnType()) { case AsmJSModule::Return_Void: callArgs.rval().set(UndefinedValue()); break; case AsmJSModule::Return_Int32: callArgs.rval().set(Int32Value(*(int32_t*)&coercedArgs[0])); break; case AsmJSModule::Return_Double: callArgs.rval().set(NumberValue(*(double*)&coercedArgs[0])); break; } return true; }
static bool DynamicallyLinkModule(JSContext *cx, CallArgs args, AsmJSModule &module) { module.setIsDynamicallyLinked(); RootedValue globalVal(cx); if (args.length() > 0) globalVal = args[0]; RootedValue importVal(cx); if (args.length() > 1) importVal = args[1]; RootedValue bufferVal(cx); if (args.length() > 2) bufferVal = args[2]; Rooted<ArrayBufferObject*> heap(cx); if (module.hasArrayView()) { if (!IsTypedArrayBuffer(bufferVal)) return LinkFail(cx, "bad ArrayBuffer argument"); heap = &AsTypedArrayBuffer(bufferVal); if (!LinkModuleToHeap(cx, module, heap)) return false; } AutoObjectVector ffis(cx); if (!ffis.resize(module.numFFIs())) return false; for (unsigned i = 0; i < module.numGlobals(); i++) { AsmJSModule::Global &global = module.global(i); switch (global.which()) { case AsmJSModule::Global::Variable: if (!ValidateGlobalVariable(cx, module, global, importVal)) return false; break; case AsmJSModule::Global::FFI: if (!ValidateFFI(cx, global, importVal, &ffis)) return false; break; case AsmJSModule::Global::ArrayView: if (!ValidateArrayView(cx, global, globalVal, bufferVal)) return false; break; case AsmJSModule::Global::MathBuiltinFunction: if (!ValidateMathBuiltinFunction(cx, global, globalVal)) return false; break; case AsmJSModule::Global::Constant: if (!ValidateConstant(cx, global, globalVal)) return false; break; } } for (unsigned i = 0; i < module.numExits(); i++) module.exitIndexToGlobalDatum(i).fun = &ffis[module.exit(i).ffiIndex()]->as<JSFunction>(); return true; }