static bool args_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags, MutableHandleObject objp) { objp.set(nullptr); Rooted<NormalArgumentsObject*> argsobj(cx, &obj->as<NormalArgumentsObject>()); unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE; if (JSID_IS_INT(id)) { uint32_t arg = uint32_t(JSID_TO_INT(id)); if (arg >= argsobj->initialLength() || argsobj->isElementDeleted(arg)) return true; attrs |= JSPROP_ENUMERATE; } else if (JSID_IS_ATOM(id, cx->names().length)) { if (argsobj->hasOverriddenLength()) return true; } else { if (!JSID_IS_ATOM(id, cx->names().callee)) return true; if (argsobj->callee().isMagic(JS_OVERWRITTEN_CALLEE)) return true; } if (!baseops::DefineGeneric(cx, argsobj, id, UndefinedHandleValue, ArgGetter, ArgSetter, attrs)) return false; objp.set(argsobj); return true; }
JS_NondeterministicGetWeakMapKeys(JSContext *cx, HandleObject objArg, MutableHandleObject ret) { RootedObject obj(cx, objArg); obj = UncheckedUnwrap(obj); if (!obj || !obj->is<WeakMapObject>()) { ret.set(nullptr); return true; } RootedObject arr(cx, NewDenseEmptyArray(cx)); if (!arr) return false; ObjectValueMap *map = obj->as<WeakMapObject>().getMap(); if (map) { // Prevent GC from mutating the weakmap while iterating. AutoSuppressGC suppress(cx); for (ObjectValueMap::Base::Range r = map->all(); !r.empty(); r.popFront()) { RootedObject key(cx, r.front().key()); if (!cx->compartment()->wrap(cx, &key)) return false; if (!NewbornArrayPush(cx, arr, ObjectValue(*key))) return false; } } ret.set(arr); return true; }
bool JSCompartment::getNonWrapperObjectForCurrentCompartment(JSContext* cx, MutableHandleObject obj) { // Ensure that we have entered a compartment. MOZ_ASSERT(cx->global()); // If we have a cross-compartment wrapper, make sure that the cx isn't // associated with the self-hosting global. We don't want to create // wrappers for objects in other runtimes, which may be the case for the // self-hosting global. MOZ_ASSERT(!cx->runtime()->isSelfHostingGlobal(cx->global())); MOZ_ASSERT(!cx->runtime()->isSelfHostingGlobal(&obj->global())); // The object is already in the right compartment. Normally same- // compartment returns the object itself, however, windows are always // wrapped by a proxy, so we have to check for that case here manually. if (obj->compartment() == this) { obj.set(ToWindowProxyIfWindow(obj)); return true; } // Note that if the object is same-compartment, but has been wrapped into a // different compartment, we need to unwrap it and return the bare same- // compartment object. Note again that windows are always wrapped by a // WindowProxy even when same-compartment so take care not to strip this // particular wrapper. RootedObject objectPassedToWrap(cx, obj); obj.set(UncheckedUnwrap(obj, /* stopAtWindowProxy = */ true)); if (obj->compartment() == this) { MOZ_ASSERT(!IsWindow(obj)); return true; } // Invoke the prewrap callback. The prewrap callback is responsible for // doing similar reification as above, but can account for any additional // embedder requirements. // // We're a bit worried about infinite recursion here, so we do a check - // see bug 809295. auto preWrap = cx->runtime()->wrapObjectCallbacks->preWrap; if (!CheckSystemRecursionLimit(cx)) return false; if (preWrap) { preWrap(cx, cx->global(), obj, objectPassedToWrap, obj); if (!obj) return false; } MOZ_ASSERT(!IsWindow(obj)); return true; }
static bool CreateExportObject(JSContext* cx, Handle<WasmModuleObject*> moduleObj, const ExportMap& exportMap, const ExportVector& exports, MutableHandleObject exportObj) { MOZ_ASSERT(exportMap.exportNames.length() == exports.length()); MOZ_ASSERT(exportMap.fieldNames.length() == exportMap.fieldsToExports.length()); for (size_t fieldIndex = 0; fieldIndex < exportMap.fieldNames.length(); fieldIndex++) { const char* fieldName = exportMap.fieldNames[fieldIndex].get(); if (!*fieldName) { MOZ_ASSERT(!exportObj); uint32_t exportIndex = exportMap.fieldsToExports[fieldIndex]; exportObj.set(NewExportedFunction(cx, moduleObj, exportMap, exportIndex)); if (!exportObj) return false; break; } } Rooted<ValueVector> vals(cx, ValueVector(cx)); for (size_t exportIndex = 0; exportIndex < exports.length(); exportIndex++) { JSFunction* fun = NewExportedFunction(cx, moduleObj, exportMap, exportIndex); if (!fun || !vals.append(ObjectValue(*fun))) return false; } if (!exportObj) { exportObj.set(JS_NewPlainObject(cx)); if (!exportObj) return false; } for (size_t fieldIndex = 0; fieldIndex < exportMap.fieldNames.length(); fieldIndex++) { const char* fieldName = exportMap.fieldNames[fieldIndex].get(); if (!*fieldName) continue; JSAtom* atom = AtomizeUTF8Chars(cx, fieldName, strlen(fieldName)); if (!atom) return false; RootedId id(cx, AtomToId(atom)); HandleValue val = vals[exportMap.fieldsToExports[fieldIndex]]; if (!JS_DefinePropertyById(cx, exportObj, id, val, JSPROP_ENUMERATE)) return false; } return true; }
/* * HasInstance hooks need to find an appropriate reflector in order to function * properly. There are two complexities that we need to handle: * * 1 - Cross-compartment wrappers. Chrome uses over 100 compartments, all with * system principal. The success of an instanceof check should not depend * on which compartment an object comes from. At the same time, we want to * make sure we don't unwrap important security wrappers. * CheckedUnwrap does the right thing here. * * 2 - Prototype chains. Suppose someone creates a vanilla JS object |a| and * sets its __proto__ to some WN |b|. If |b instanceof nsIFoo| returns true, * one would expect |a instanceof nsIFoo| to return true as well, since * instanceof is transitive up the prototype chain in ECMAScript. Moreover, * there's chrome code that relies on this. * * This static method handles both complexities, returning either an XPCWN, a * DOM object, or null. The object may well be cross-compartment from |cx|. */ static nsresult FindObjectForHasInstance(JSContext* cx, HandleObject objArg, MutableHandleObject target) { RootedObject obj(cx, objArg), proto(cx); while (obj && !IS_WN_REFLECTOR(obj) && !IsDOMObject(obj) && !mozilla::jsipc::IsCPOW(obj)) { if (js::IsWrapper(obj)) { obj = js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false); continue; } { JSAutoCompartment ac(cx, obj); if (!js::GetObjectProto(cx, obj, &proto)) return NS_ERROR_FAILURE; } obj = proto; } target.set(obj); return NS_OK; }
bool JSCompartment::getTemplateLiteralObject(JSContext* cx, HandleArrayObject rawStrings, MutableHandleObject templateObj) { if (TemplateRegistry::AddPtr p = templateLiteralMap_.lookupForAdd(rawStrings)) { templateObj.set(p->value()); // The template object must have been frozen when it was added to the // registry. MOZ_ASSERT(!templateObj->nonProxyIsExtensible()); } else { MOZ_ASSERT(templateObj->nonProxyIsExtensible()); RootedValue rawValue(cx, ObjectValue(*rawStrings)); if (!DefineDataProperty(cx, templateObj, cx->names().raw, rawValue, 0)) return false; if (!FreezeObject(cx, rawStrings)) return false; if (!FreezeObject(cx, templateObj)) return false; if (!templateLiteralMap_.relookupOrAdd(p, rawStrings, templateObj)) return false; } return true; }
bool OpaqueCrossCompartmentWrapper::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop) const { protop.set(nullptr); return true; }
bool ModuleNamespaceObject::ProxyHandler::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop) const { protop.set(nullptr); return true; }
static bool proxy_LookupProperty(JSContext* cx, HandleObject obj, HandleId id, MutableHandleObject objp, MutableHandle<JS::PropertyResult> propp) { bool found; if (!Proxy::has(cx, obj, id, &found)) return false; if (found) { propp.setNonNativeProperty(); objp.set(obj); } else { propp.setNotFound(); objp.set(nullptr); } return true; }
js::GetOriginalEval(JSContext *cx, HandleObject scope, MutableHandleObject eval) { assertSameCompartment(cx, scope); if (!scope->global().getOrCreateObjectPrototype(cx)) return false; eval.set(&scope->global().getOriginalEval().toObject()); return true; }
JS_NondeterministicGetWeakSetKeys(JSContext* cx, HandleObject objArg, MutableHandleObject ret) { RootedObject obj(cx, UncheckedUnwrap(objArg)); if (!obj || !obj->is<WeakSetObject>()) { ret.set(nullptr); return true; } return WeakCollectionObject::nondeterministicGetKeys(cx, obj.as<WeakCollectionObject>(), ret); }
/* static */ bool GlobalObject::getOrCreateEval(JSContext* cx, Handle<GlobalObject*> global, MutableHandleObject eval) { if (!global->getOrCreateObjectPrototype(cx)) return false; eval.set(&global->getSlot(EVAL).toObject()); return true; }
bool XDRState<mode>::codeFunction(MutableHandleObject objp) { if (mode == XDR_DECODE) objp.set(NULL); if (!VersionCheck(this)) return false; return XDRInterpretedFunction(this, NullPtr(), NullPtr(), objp); }
static bool WrapForSameCompartment(JSContext *cx, MutableHandleObject obj, const JSWrapObjectCallbacks *cb) { JS_ASSERT(cx->compartment() == obj->compartment()); if (!cb->sameCompartmentWrap) return true; RootedObject wrapped(cx, cb->sameCompartmentWrap(cx, obj)); if (!wrapped) return false; obj.set(wrapped); return true; }
bool JSCompartment::getOrCreateWrapper(JSContext* cx, HandleObject existing, MutableHandleObject obj) { // If we already have a wrapper for this value, use it. RootedValue key(cx, ObjectValue(*obj)); if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(CrossCompartmentKey(key))) { obj.set(&p->value().get().toObject()); MOZ_ASSERT(obj->is<CrossCompartmentWrapperObject>()); return true; } // Ensure that the wrappee is exposed in case we are creating a new wrapper // for a gray object. ExposeObjectToActiveJS(obj); // Create a new wrapper for the object. auto wrap = cx->runtime()->wrapObjectCallbacks->wrap; RootedObject wrapper(cx, wrap(cx, existing, obj)); if (!wrapper) return false; // We maintain the invariant that the key in the cross-compartment wrapper // map is always directly wrapped by the value. MOZ_ASSERT(Wrapper::wrappedObject(wrapper) == &key.get().toObject()); if (!putWrapper(cx, CrossCompartmentKey(key), ObjectValue(*wrapper))) { // Enforce the invariant that all cross-compartment wrapper object are // in the map by nuking the wrapper if we couldn't add it. // Unfortunately it's possible for the wrapper to still be marked if we // took this path, for example if the object metadata callback stashes a // reference to it. if (wrapper->is<CrossCompartmentWrapperObject>()) NukeCrossCompartmentWrapper(cx, wrapper); return false; } obj.set(wrapper); return true; }
static bool WrapForSameCompartment(JSContext *cx, MutableHandleObject obj) { JS_ASSERT(cx->compartment() == obj->compartment()); if (!cx->runtime()->sameCompartmentWrapObjectCallback) return true; RootedObject wrapped(cx); wrapped = cx->runtime()->sameCompartmentWrapObjectCallback(cx, obj); if (!wrapped) return false; obj.set(wrapped); return true; }
static JSBool strictargs_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags, MutableHandleObject objp) { objp.set(NULL); Rooted<StrictArgumentsObject*> argsobj(cx, &obj->asStrictArguments()); unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE; PropertyOp getter = StrictArgGetter; StrictPropertyOp setter = StrictArgSetter; if (JSID_IS_INT(id)) { uint32_t arg = uint32_t(JSID_TO_INT(id)); if (arg >= argsobj->initialLength() || argsobj->isElementDeleted(arg)) return true; attrs |= JSPROP_ENUMERATE; } else if (JSID_IS_ATOM(id, cx->names().length)) { if (argsobj->hasOverriddenLength()) return true; } else { if (!JSID_IS_ATOM(id, cx->names().callee) && !JSID_IS_ATOM(id, cx->names().caller)) return true; attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED; getter = CastAsPropertyOp(argsobj->global().getThrowTypeError()); setter = CastAsStrictPropertyOp(argsobj->global().getThrowTypeError()); } RootedValue undef(cx, UndefinedValue()); if (!baseops::DefineGeneric(cx, argsobj, id, undef, getter, setter, attrs)) return false; objp.set(argsobj); return true; }
js::ExecuteInGlobalAndReturnScope(JSContext* cx, HandleObject global, HandleScript scriptArg, MutableHandleObject scopeArg) { CHECK_REQUEST(cx); assertSameCompartment(cx, global); MOZ_ASSERT(global->is<GlobalObject>()); MOZ_RELEASE_ASSERT(scriptArg->hasNonSyntacticScope()); RootedScript script(cx, scriptArg); Rooted<GlobalObject*> globalRoot(cx, &global->as<GlobalObject>()); if (script->compartment() != cx->compartment()) { Rooted<StaticScope*> staticScope(cx, &globalRoot->lexicalScope().staticBlock()); staticScope = StaticNonSyntacticScope::create(cx, staticScope); if (!staticScope) return false; script = CloneGlobalScript(cx, staticScope, script); if (!script) return false; Debugger::onNewScript(cx, script); } Rooted<ClonedBlockObject*> globalLexical(cx, &globalRoot->lexicalScope()); Rooted<ScopeObject*> scope(cx, NonSyntacticVariablesObject::create(cx, globalLexical)); if (!scope) return false; // Unlike the non-syntactic scope chain API used by the subscript loader, // this API creates a fresh block scope each time. Rooted<StaticNonSyntacticScope*> enclosingStaticScope(cx, &script->enclosingStaticScope()->as<StaticNonSyntacticScope>()); scope = ClonedBlockObject::createNonSyntactic(cx, enclosingStaticScope, scope); if (!scope) return false; RootedValue rval(cx); if (!ExecuteKernel(cx, script, *scope, UndefinedValue(), NullFramePtr() /* evalInFrame */, rval.address())) { return false; } scopeArg.set(scope); return true; }
static bool CreateInstance(JSContext* cx, HandleObject exportObj, MutableHandleObject instance) { instance.set(JS_NewPlainObject(cx)); if (!instance) return false; JSAtom* atom = Atomize(cx, ExportField, strlen(ExportField)); if (!atom) return false; RootedId id(cx, AtomToId(atom)); RootedValue val(cx, ObjectValue(*exportObj)); if (!JS_DefinePropertyById(cx, instance, id, val, JSPROP_ENUMERATE)) return false; return true; }
// ES6 (14 October, 2014) 9.5.11 Proxy.[[Enumerate]] bool ScriptedDirectProxyHandler::enumerate(JSContext* cx, HandleObject proxy, MutableHandleObject objp) const { // step 1 RootedObject handler(cx, GetDirectProxyHandlerObject(proxy)); // step 2 if (!handler) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; } // step 3: unnecessary assert // step 4 RootedObject target(cx, proxy->as<ProxyObject>().target()); // step 5-6 RootedValue trap(cx); if (!GetProperty(cx, handler, handler, cx->names().enumerate, &trap)) return false; // step 7 if (trap.isUndefined()) return GetIterator(cx, target, 0, objp); // step 8-9 Value argv[] = { ObjectOrNullValue(target) }; RootedValue trapResult(cx); if (!Invoke(cx, ObjectValue(*handler), trap, ArrayLength(argv), argv, &trapResult)) return false; // step 10 if (trapResult.isPrimitive()) { ReportInvalidTrapResult(cx, proxy, cx->names().enumerate); return false; } // step 11 objp.set(&trapResult.toObject()); return true; }
bool WrapperOwner::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject objp) { ObjectId objId = idOf(proxy); ObjectOrNullVariant val; ReturnStatus status; if (!SendGetPrototype(objId, &status, &val)) return ipcfail(cx); LOG_STACK(); if (!ok(cx, status)) return false; objp.set(fromObjectOrNullVariant(cx, val)); return true; }
bool CrossCompartmentWrapper::getPrototypeOf(JSContext *cx, HandleObject wrapper, MutableHandleObject protop) { if (!wrapper->getTaggedProto().isLazy()) { protop.set(wrapper->getTaggedProto().toObjectOrNull()); return true; } { RootedObject wrapped(cx, wrappedObject(wrapper)); AutoCompartment call(cx, wrapped); if (!JSObject::getProto(cx, wrapped, protop)) return false; if (protop) protop->setDelegate(cx); } return cx->compartment->wrap(cx, protop.address()); }
static bool FindErrorInstanceOrPrototype(JSContext* cx, HandleObject obj, MutableHandleObject result) { // Walk up the prototype chain until we find an error object instance or // prototype object. This allows code like: // Object.create(Error.prototype).stack // or // function NYI() { } // NYI.prototype = new Error; // (new NYI).stack // to continue returning stacks that are useless, but at least don't throw. RootedObject target(cx, CheckedUnwrap(obj)); if (!target) { ReportAccessDenied(cx); return false; } RootedObject proto(cx); while (!IsErrorProtoKey(StandardProtoKeyOrNull(target))) { if (!GetPrototype(cx, target, &proto)) return false; if (!proto) { // We walked the whole prototype chain and did not find an Error // object. JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, js_Error_str, "(get stack)", obj->getClass()->name); return false; } target = CheckedUnwrap(proto); if (!target) { ReportAccessDenied(cx); return false; } } result.set(target); return true; }
js::ExecuteInGlobalAndReturnScope(JSContext* cx, HandleObject global, HandleScript scriptArg, MutableHandleObject scopeArg) { CHECK_REQUEST(cx); assertSameCompartment(cx, global); MOZ_ASSERT(global->is<GlobalObject>()); RootedScript script(cx, scriptArg); if (script->compartment() != cx->compartment()) { script = CloneScript(cx, NullPtr(), NullPtr(), script); if (!script) return false; Debugger::onNewScript(cx, script); } RootedObject scope(cx, JS_NewPlainObject(cx)); if (!scope) return false; if (!scope->setQualifiedVarObj(cx)) return false; if (!scope->setUnqualifiedVarObj(cx)) return false; JSObject* thisobj = GetThisObject(cx, global); if (!thisobj) return false; RootedValue thisv(cx, ObjectValue(*thisobj)); RootedValue rval(cx); if (!ExecuteKernel(cx, script, *scope, thisv, EXECUTE_GLOBAL, NullFramePtr() /* evalInFrame */, rval.address())) { return false; } scopeArg.set(scope); return true; }
js::ExecuteInGlobalAndReturnScope(JSContext* cx, HandleObject global, HandleScript scriptArg, MutableHandleObject scopeArg) { CHECK_REQUEST(cx); assertSameCompartment(cx, global); MOZ_ASSERT(global->is<GlobalObject>()); MOZ_RELEASE_ASSERT(scriptArg->hasNonSyntacticScope()); RootedScript script(cx, scriptArg); if (script->compartment() != cx->compartment()) { Rooted<ScopeObject*> staticScope(cx, StaticNonSyntacticScopeObjects::create(cx, nullptr)); if (!staticScope) return false; script = CloneGlobalScript(cx, staticScope, script); if (!script) return false; Debugger::onNewScript(cx, script); } Rooted<GlobalObject*> globalRoot(cx, &global->as<GlobalObject>()); Rooted<ScopeObject*> scope(cx, NonSyntacticVariablesObject::create(cx, globalRoot)); if (!scope) return false; JSObject* thisobj = GetThisObject(cx, global); if (!thisobj) return false; RootedValue thisv(cx, ObjectValue(*thisobj)); RootedValue rval(cx); if (!ExecuteKernel(cx, script, *scope, thisv, UndefinedValue(), EXECUTE_GLOBAL, NullFramePtr() /* evalInFrame */, rval.address())) { return false; } scopeArg.set(scope); return true; }
bool WeakCollectionObject::nondeterministicGetKeys(JSContext* cx, Handle<WeakCollectionObject*> obj, MutableHandleObject ret) { RootedObject arr(cx, NewDenseEmptyArray(cx)); if (!arr) return false; if (ObjectValueMap* map = obj->getMap()) { // Prevent GC from mutating the weakmap while iterating. AutoSuppressGC suppress(cx); for (ObjectValueMap::Base::Range r = map->all(); !r.empty(); r.popFront()) { JS::ExposeObjectToActiveJS(r.front().key()); RootedObject key(cx, r.front().key()); if (!cx->compartment()->wrap(cx, &key)) return false; if (!NewbornArrayPush(cx, arr, ObjectValue(*key))) return false; } } ret.set(arr); return true; }
bool DeadObjectProxy::getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) { protop.set(NULL); return true; }
bool JSCompartment::wrap(JSContext *cx, MutableHandleObject obj, HandleObject existingArg) { MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(this)); MOZ_ASSERT(cx->compartment() == this); MOZ_ASSERT_IF(existingArg, existingArg->compartment() == cx->compartment()); MOZ_ASSERT_IF(existingArg, IsDeadProxyObject(existingArg)); if (!obj) return true; AutoDisableProxyCheck adpc(cx->runtime()); // Wrappers should really be parented to the wrapped parent of the wrapped // object, but in that case a wrapped global object would have a nullptr // parent without being a proper global object (JSCLASS_IS_GLOBAL). Instead, // we parent all wrappers to the global object in their home compartment. // This loses us some transparency, and is generally very cheesy. HandleObject global = cx->global(); RootedObject objGlobal(cx, &obj->global()); MOZ_ASSERT(global); MOZ_ASSERT(objGlobal); const JSWrapObjectCallbacks *cb = cx->runtime()->wrapObjectCallbacks; if (obj->compartment() == this) { obj.set(GetOuterObject(cx, obj)); return true; } // If we have a cross-compartment wrapper, make sure that the cx isn't // associated with the self-hosting global. We don't want to create // wrappers for objects in other runtimes, which may be the case for the // self-hosting global. MOZ_ASSERT(!cx->runtime()->isSelfHostingGlobal(global) && !cx->runtime()->isSelfHostingGlobal(objGlobal)); // Unwrap the object, but don't unwrap outer windows. RootedObject objectPassedToWrap(cx, obj); obj.set(UncheckedUnwrap(obj, /* stopAtOuter = */ true)); if (obj->compartment() == this) { MOZ_ASSERT(obj == GetOuterObject(cx, obj)); return true; } // Translate StopIteration singleton. if (obj->is<StopIterationObject>()) { // StopIteration isn't a constructor, but it's stored in GlobalObject // as one, out of laziness. Hence the GetBuiltinConstructor call here. RootedObject stopIteration(cx); if (!GetBuiltinConstructor(cx, JSProto_StopIteration, &stopIteration)) return false; obj.set(stopIteration); return true; } // Invoke the prewrap callback. We're a bit worried about infinite // recursion here, so we do a check - see bug 809295. JS_CHECK_SYSTEM_RECURSION(cx, return false); if (cb->preWrap) { obj.set(cb->preWrap(cx, global, obj, objectPassedToWrap)); if (!obj) return false; } MOZ_ASSERT(obj == GetOuterObject(cx, obj)); if (obj->compartment() == this) return true; // If we already have a wrapper for this value, use it. RootedValue key(cx, ObjectValue(*obj)); if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(CrossCompartmentKey(key))) { obj.set(&p->value().get().toObject()); MOZ_ASSERT(obj->is<CrossCompartmentWrapperObject>()); MOZ_ASSERT(obj->getParent() == global); return true; } RootedObject existing(cx, existingArg); if (existing) { // Is it possible to reuse |existing|? if (!existing->getTaggedProto().isLazy() || // Note: Class asserted above, so all that's left to check is callability existing->isCallable() || existing->getParent() != global || obj->isCallable()) { existing = nullptr; } } obj.set(cb->wrap(cx, existing, obj, global)); if (!obj) return false; // We maintain the invariant that the key in the cross-compartment wrapper // map is always directly wrapped by the value. MOZ_ASSERT(Wrapper::wrappedObject(obj) == &key.get().toObject()); return putWrapper(cx, CrossCompartmentKey(key), ObjectValue(*obj)); }
static JSBool exn_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags, MutableHandleObject objp) { JSExnPrivate *priv; const char *prop; jsval v; unsigned attrs; objp.set(NULL); priv = GetExnPrivate(obj); if (priv && JSID_IS_ATOM(id)) { RootedString str(cx, JSID_TO_STRING(id)); RootedAtom atom(cx, cx->names().message); if (str == atom) { prop = js_message_str; /* * Per ES5 15.11.1.1, if Error is called with no argument or with * undefined as the argument, it returns an Error object with no * own message property. */ if (!priv->message) return true; v = STRING_TO_JSVAL(priv->message); attrs = 0; goto define; } atom = cx->names().fileName; if (str == atom) { prop = js_fileName_str; v = STRING_TO_JSVAL(priv->filename); attrs = JSPROP_ENUMERATE; goto define; } atom = cx->names().lineNumber; if (str == atom) { prop = js_lineNumber_str; v = UINT_TO_JSVAL(priv->lineno); attrs = JSPROP_ENUMERATE; goto define; } atom = cx->names().columnNumber; if (str == atom) { prop = js_columnNumber_str; v = UINT_TO_JSVAL(priv->column); attrs = JSPROP_ENUMERATE; goto define; } atom = cx->names().stack; if (str == atom) { RawString stack = StackTraceToString(cx, priv); if (!stack) return false; prop = js_stack_str; v = STRING_TO_JSVAL(stack); attrs = JSPROP_ENUMERATE; goto define; } } return true; define: if (!JS_DefineProperty(cx, obj, prop, v, NULL, NULL, attrs)) return false; objp.set(obj); return true; }
static JSBool global_resolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags, MutableHandleObject objp) { #ifdef LAZY_STANDARD_CLASSES if ((flags & JSRESOLVE_ASSIGNING) == 0) { JSBool resolved; if (!JS_ResolveStandardClass(cx, obj, id, &resolved)) return JS_FALSE; if (resolved) { objp.set(obj); return JS_TRUE; } } #endif #if defined(SHELL_HACK) && defined(DEBUG) && defined(XP_UNIX) if ((flags & (JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING)) == 0) { /* * Do this expensive hack only for unoptimized Unix builds, which are * not used for benchmarking. */ char *path, *comp, *full; const char *name; JSBool ok, found; JSFunction *fun; if (!JSVAL_IS_STRING(id)) return JS_TRUE; path = getenv("PATH"); if (!path) return JS_TRUE; path = JS_strdup(cx, path); if (!path) return JS_FALSE; name = JS_GetStringBytes(JSVAL_TO_STRING(id)); ok = JS_TRUE; for (comp = strtok(path, ":"); comp; comp = strtok(NULL, ":")) { if (*comp != '\0') { full = JS_smprintf("%s/%s", comp, name); if (!full) { JS_ReportOutOfMemory(cx); ok = JS_FALSE; break; } } else { full = (char *)name; } found = (access(full, X_OK) == 0); if (*comp != '\0') free(full); if (found) { fun = JS_DefineFunction(cx, obj, name, Exec, 0, JSPROP_ENUMERATE); ok = (fun != NULL); if (ok) objp.set(obj); break; } } JS_free(cx, path); return ok; } #else return JS_TRUE; #endif }