bool CreateThis(JSContext *cx, HandleObject callee, MutableHandleValue rval) { rval.set(MagicValue(JS_IS_CONSTRUCTING)); if (callee->isFunction()) { JSFunction *fun = callee->toFunction(); if (fun->isInterpreted()) { JSScript *script = fun->getOrCreateScript(cx); if (!script || !script->ensureHasTypes(cx)) return false; JSObject *thisObj = CreateThisForFunction(cx, callee, false); if (!thisObj) return false; rval.set(ObjectValue(*thisObj)); } } return true; }
JS_SplicePrototype(JSContext* cx, HandleObject obj, HandleObject proto) { /* * Change the prototype of an object which hasn't been used anywhere * and does not share its type with another object. Unlike JS_SetPrototype, * does not nuke type information for the object. */ CHECK_REQUEST(cx); if (!obj->isSingleton()) { /* * We can see non-singleton objects when trying to splice prototypes * due to mutable __proto__ (ugh). */ return JS_SetPrototype(cx, obj, proto); } Rooted<TaggedProto> tagged(cx, TaggedProto(proto)); return obj->splicePrototype(cx, obj->getClass(), tagged); }
bool jit::SetPropertyPar(ForkJoinSlice *slice, HandleObject obj, HandlePropertyName name, HandleValue value, bool strict, jsbytecode *pc) { JS_ASSERT(slice->isThreadLocal(obj)); if (*pc == JSOP_SETALIASEDVAR) { // See comment in jit::SetProperty. Shape *shape = obj->nativeLookupPure(name); JS_ASSERT(shape && shape->hasSlot()); return obj->nativeSetSlotIfHasType(shape, value); } // Fail early on hooks. if (obj->getOps()->setProperty) return TP_RETRY_SEQUENTIALLY; RootedValue v(slice, value); RootedId id(slice, NameToId(name)); return baseops::SetPropertyHelper<ParallelExecution>(slice, obj, obj, id, 0, &v, strict); }
static RawObject CloneDenseArray(JSContext *cx, HandleObject obj, CloneMemory &clonedObjects) { uint32_t len = obj->getArrayLength(); RootedObject clone(cx, NewDenseAllocatedArray(cx, len)); clone->setDenseArrayInitializedLength(len); for (uint32_t i = 0; i < len; i++) JSObject::initDenseArrayElementWithType(cx, clone, i, UndefinedValue()); RootedValue elt(cx); for (uint32_t i = 0; i < len; i++) { bool present; if (!obj->getElementIfPresent(cx, obj, obj, i, &elt, &present)) return NULL; if (present) { if (!CloneValue(cx, &elt, clonedObjects)) return NULL; JSObject::setDenseArrayElementWithType(cx, clone, i, elt); } } return clone; }
static JSBool fun_enumerate(JSContext *cx, HandleObject obj) { JS_ASSERT(obj->isFunction()); RootedId id(cx); bool found; if (!obj->isBoundFunction()) { id = NameToId(cx->runtime->atomState.classPrototypeAtom); if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED)) return false; } id = NameToId(cx->runtime->atomState.lengthAtom); if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED)) return false; id = NameToId(cx->runtime->atomState.nameAtom); if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED)) return false; for (unsigned i = 0; i < ArrayLength(poisonPillProps); i++) { const uint16_t offset = poisonPillProps[i]; id = NameToId(OFFSET_TO_NAME(cx->runtime, offset)); if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED)) return false; } return true; }
static inline bool Enumerate(JSContext* cx, HandleObject pobj, jsid id, bool enumerable, unsigned flags, Maybe<IdSet>& ht, AutoIdVector* props) { if (CheckForDuplicates) { if (!ht) { ht.emplace(cx); // Most of the time there are only a handful of entries. if (!ht->init(5)) return false; } // If we've already seen this, we definitely won't add it. IdSet::AddPtr p = ht->lookupForAdd(id); if (MOZ_UNLIKELY(!!p)) return true; // It's not necessary to add properties to the hash table at the end of // the prototype chain, but custom enumeration behaviors might return // duplicated properties, so always add in such cases. if (pobj->is<ProxyObject>() || pobj->staticPrototype() || pobj->getClass()->getNewEnumerate()) { if (!ht->add(p, id)) return false; } } if (!enumerable && !(flags & JSITER_HIDDEN)) return true; // Symbol-keyed properties and nonenumerable properties are skipped unless // the caller specifically asks for them. A caller can also filter out // non-symbols by asking for JSITER_SYMBOLSONLY. if (JSID_IS_SYMBOL(id) ? !(flags & JSITER_SYMBOLS) : (flags & JSITER_SYMBOLSONLY)) return true; return props->append(id); }
static JSBool ArgSetter(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Value *vp) { if (!obj->isNormalArguments()) return true; NormalArgumentsObject &argsobj = obj->asNormalArguments(); if (JSID_IS_INT(id)) { unsigned arg = unsigned(JSID_TO_INT(id)); if (arg < argsobj.initialLength()) { if (StackFrame *fp = argsobj.maybeStackFrame()) { JSScript *script = fp->functionScript(); JS_ASSERT(script->needsArgsObj()); if (arg < fp->numFormalArgs()) { JS_ASSERT(fp->script()->formalIsAliased(arg)); types::TypeScript::SetArgument(cx, script, arg, *vp); } fp->canonicalActualArg(arg) = *vp; return true; } } } else { JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) || JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)); } /* * For simplicity we use delete/define to replace the property with one * backed by the default Object getter and setter. Note that we rely on * args_delProperty to clear the corresponding reserved slot so the GC can * collect its value. Note also that we must define the property instead * of setting it in case the user has changed the prototype to an object * that has a setter for this id. */ RootedVarValue value(cx); return baseops::DeleteGeneric(cx, obj, id, value.address(), false) && baseops::DefineProperty(cx, obj, id, vp, NULL, NULL, JSPROP_ENUMERATE); }
bool ArrayPushDense(JSContext *cx, HandleObject obj, HandleValue v, uint32_t *length) { JS_ASSERT(obj->isArray()); Value argv[] = { UndefinedValue(), ObjectValue(*obj), v }; AutoValueArray ava(cx, argv, 3); if (!js::array_push(cx, 1, argv)) return false; *length = argv[0].toInt32(); return true; }
/* static */ void ArgumentsObject::MaybeForwardToCallObject(jit::JitFrameLayout* frame, HandleObject callObj, ArgumentsObject* obj, ArgumentsData* data) { JSFunction* callee = jit::CalleeTokenToFunction(frame->calleeToken()); JSScript* script = callee->nonLazyScript(); if (callee->needsCallObject() && script->argsObjAliasesFormals()) { MOZ_ASSERT(callObj && callObj->is<CallObject>()); obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(*callObj.get())); for (AliasedFormalIter fi(script); fi; fi++) data->args[fi.frameIndex()] = MagicScopeSlotValue(fi.scopeSlot()); } }
/* static */ void ArgumentsObject::MaybeForwardToCallObject(ion::IonJSFrameLayout *frame, HandleObject callObj, JSObject *obj, ArgumentsData *data) { JSFunction *callee = ion::CalleeTokenToFunction(frame->calleeToken()); JSScript *script = callee->nonLazyScript(); if (callee->isHeavyweight() && script->argsObjAliasesFormals()) { JS_ASSERT(callObj && callObj->is<CallObject>()); obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(*callObj.get())); for (AliasedFormalIter fi(script); fi; fi++) data->args[fi.frameIndex()] = MagicValue(JS_FORWARD_TO_CALL_OBJECT); } }
bool SetDenseElement(JSContext *cx, HandleObject obj, int32_t index, HandleValue value, bool strict) { // This function is called from Ion code for StoreElementHole's OOL path. // In this case we know the object is native, has no indexed properties // and we can use setDenseElement instead of setDenseElementWithType. MOZ_ASSERT(obj->isNative()); MOZ_ASSERT(!obj->isIndexed()); JSObject::EnsureDenseResult result = JSObject::ED_SPARSE; do { if (index < 0) break; bool isArray = obj->is<ArrayObject>(); if (isArray && !obj->as<ArrayObject>().lengthIsWritable()) break; uint32_t idx = uint32_t(index); result = obj->ensureDenseElements(cx, idx, 1); if (result != JSObject::ED_OK) break; if (isArray) { ArrayObject &arr = obj->as<ArrayObject>(); if (idx >= arr.length()) arr.setLengthInt32(idx + 1); } obj->setDenseElement(idx, value); return true; } while (false); if (result == JSObject::ED_FAILED) return false; MOZ_ASSERT(result == JSObject::ED_SPARSE); RootedValue indexVal(cx, Int32Value(index)); return SetObjectElement(cx, obj, indexVal, value, strict); }
bool GetPropIRGenerator::tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId) { MOZ_ASSERT(IsCacheableDOMProxy(obj)); writer.guardShape(objId, obj->maybeShape()); // No need for more guards: we know this is a DOM proxy, since the shape // guard enforces a given JSClass, so just go ahead and emit the call to // ProxyGet. writer.callProxyGetResult(objId, NameToId(name_)); writer.typeMonitorResult(); return true; }
static JSBool StrictArgGetter(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp) { if (!obj->isStrictArguments()) return true; StrictArgumentsObject &argsobj = obj->asStrictArguments(); if (JSID_IS_INT(id)) { /* * arg can exceed the number of arguments if a script changed the * prototype to point to another Arguments object with a bigger argc. */ unsigned arg = unsigned(JSID_TO_INT(id)); if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) vp.set(argsobj.element(arg)); } else { JS_ASSERT(JSID_IS_ATOM(id, cx->names().length)); if (!argsobj.hasOverriddenLength()) vp.setInt32(argsobj.initialLength()); } return true; }
bool SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value, bool strict, int jsop) { RootedValue v(cx, value); RootedId id(cx, NameToId(name)); if (jsop == JSOP_SETALIASEDVAR) { // Aliased var assigns ignore readonly attributes on the property, as // required for initializing 'const' closure variables. Shape *shape = obj->nativeLookup(cx, name); JS_ASSERT(shape && shape->hasSlot()); JSObject::nativeSetSlotWithType(cx, obj, shape, value); return true; } if (JS_LIKELY(!obj->getOps()->setProperty)) { unsigned defineHow = (jsop == JSOP_SETNAME || jsop == JSOP_SETGNAME) ? DNP_UNQUALIFIED : 0; return baseops::SetPropertyHelper(cx, obj, obj, id, defineHow, &v, strict); } return JSObject::setGeneric(cx, obj, obj, id, &v, strict); }
bool SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value, bool strict, bool isSetName) { RootedValue v(cx, value); RootedId id(cx, NameToId(name)); if (JS_LIKELY(!obj->getOps()->setProperty)) { unsigned defineHow = isSetName ? DNP_UNQUALIFIED : 0; return baseops::SetPropertyHelper(cx, obj, obj, id, defineHow, &v, strict); } return JSObject::setGeneric(cx, obj, obj, id, &v, strict); }
static bool GetUnclonedValue(JSContext *cx, HandleObject selfHostedObject, HandleId id, MutableHandleValue vp) { vp.setUndefined(); if (JSID_IS_INT(id)) { size_t index = JSID_TO_INT(id); if (index < selfHostedObject->getDenseInitializedLength() && !selfHostedObject->getDenseElement(index).isMagic(JS_ELEMENTS_HOLE)) { vp.set(selfHostedObject->getDenseElement(JSID_TO_INT(id))); return true; } } // Since all atoms used by self hosting are marked as permanent, any // attempt to look up a non-permanent atom will fail. We should only // see such atoms when code is looking for properties on the self // hosted global which aren't present. if (JSID_IS_STRING(id) && !JSID_TO_STRING(id)->isPermanentAtom()) { JS_ASSERT(selfHostedObject->is<GlobalObject>()); RootedValue value(cx, IdToValue(id)); return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NO_SUCH_SELF_HOSTED_PROP, JSDVG_IGNORE_STACK, value, NullPtr(), nullptr, nullptr); } RootedShape shape(cx, selfHostedObject->nativeLookupPure(id)); if (!shape) { RootedValue value(cx, IdToValue(id)); return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NO_SUCH_SELF_HOSTED_PROP, JSDVG_IGNORE_STACK, value, NullPtr(), nullptr, nullptr); } JS_ASSERT(shape->hasSlot() && shape->hasDefaultGetter()); vp.set(selfHostedObject->getSlot(shape->slot())); return true; }
static MOZ_ALWAYS_INLINE bool SetWeakMapEntryInternal(JSContext* cx, Handle<WeakMapObject*> mapObj, HandleObject key, HandleValue value) { ObjectValueMap* map = mapObj->getMap(); if (!map) { AutoInitGCManagedObject<ObjectValueMap> newMap( cx->make_unique<ObjectValueMap>(cx, mapObj.get())); if (!newMap) return false; if (!newMap->init()) { JS_ReportOutOfMemory(cx); return false; } map = newMap.release(); mapObj->setPrivate(map); } // Preserve wrapped native keys to prevent wrapper optimization. if (!TryPreserveReflector(cx, key)) return false; if (JSWeakmapKeyDelegateOp op = key->getClass()->ext.weakmapKeyDelegateOp) { RootedObject delegate(cx, op(key)); if (delegate && !TryPreserveReflector(cx, delegate)) return false; } MOZ_ASSERT(key->compartment() == mapObj->compartment()); MOZ_ASSERT_IF(value.isObject(), value.toObject().compartment() == mapObj->compartment()); if (!map->put(key, value)) { JS_ReportOutOfMemory(cx); return false; } WeakMapPostWriteBarrier(cx->runtime(), map, key.get()); return true; }
/* static */ bool GlobalObject::warnOnceAbout(JSContext *cx, HandleObject obj, uint32_t slot, unsigned errorNumber) { Rooted<GlobalObject*> global(cx, &obj->global()); HeapSlot &v = global->getSlotRef(slot); if (v.isUndefined()) { if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, js_GetErrorMessage, nullptr, errorNumber)) { return false; } v.init(global, HeapSlot::Slot, slot, BooleanValue(true)); } return true; }
/* static */ void ArgumentsObject::MaybeForwardToCallObject(jit::JitFrameLayout* frame, HandleObject callObj, ArgumentsObject* obj, ArgumentsData* data) { JSFunction* callee = jit::CalleeTokenToFunction(frame->calleeToken()); JSScript* script = callee->nonLazyScript(); if (callee->needsCallObject() && script->argumentsAliasesFormals()) { MOZ_ASSERT(callObj && callObj->is<CallObject>()); obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(*callObj.get())); for (PositionalFormalParameterIter fi(script); fi; fi++) { if (fi.closedOver()) data->args[fi.argumentSlot()] = MagicEnvSlotValue(fi.location().slot()); } } }
static JSBool args_delProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp) { ArgumentsObject &argsobj = obj->asArguments(); if (JSID_IS_INT(id)) { unsigned arg = unsigned(JSID_TO_INT(id)); if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) argsobj.markElementDeleted(arg); } else if (JSID_IS_ATOM(id, cx->names().length)) { argsobj.markLengthOverridden(); } else if (JSID_IS_ATOM(id, cx->names().callee)) { argsobj.asNormalArguments().clearCallee(); } return true; }
static bool WrapForSameCompartment(JSContext *cx, HandleObject obj, MutableHandleValue vp) { JS_ASSERT(cx->compartment == obj->compartment()); if (!cx->runtime->sameCompartmentWrapObjectCallback) { vp.setObject(*obj); return true; } JSObject *wrapped = cx->runtime->sameCompartmentWrapObjectCallback(cx, obj); if (!wrapped) return false; vp.setObject(*wrapped); return true; }
/* static */ bool GlobalObject::warnOnceAboutWatch(JSContext *cx, HandleObject obj) { Rooted<GlobalObject*> global(cx, &obj->global()); HeapSlot &v = global->getSlotRef(WARNED_WATCH_DEPRECATED); if (v.isUndefined()) { // Warn only once per global object. if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, js_GetErrorMessage, nullptr, JSMSG_OBJECT_WATCH_DEPRECATED)) { return false; } v.init(global, HeapSlot::Slot, WARNED_WATCH_DEPRECATED, BooleanValue(true)); } return true; }
static JSBool args_delProperty(JSContext *cx, HandleObject obj, HandleId id, Value *vp) { ArgumentsObject &argsobj = obj->asArguments(); if (JSID_IS_INT(id)) { unsigned arg = unsigned(JSID_TO_INT(id)); if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) { argsobj.setElement(arg, UndefinedValue()); argsobj.markElementDeleted(arg); } } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { argsobj.markLengthOverridden(); } else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) { argsobj.asNormalArguments().clearCallee(); } return true; }
bool WatchpointMap::watch(JSContext *cx, HandleObject obj, HandleId id, JSWatchPointHandler handler, HandleObject closure) { JS_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id)); if (!obj->setWatched(cx)) return false; Watchpoint w; w.handler = handler; w.closure = closure; w.held = false; if (!map.put(WatchKey(obj, id), w)) { js_ReportOutOfMemory(cx); return false; } return true; }
bool GetPropIRGenerator::tryAttachDenseElement(HandleObject obj, ObjOperandId objId, ValOperandId indexId) { MOZ_ASSERT(idVal_.isInt32()); if (!obj->isNative()) return false; if (!obj->as<NativeObject>().containsDenseElement(uint32_t(idVal_.toInt32()))) return false; writer.guardShape(objId, obj->as<NativeObject>().lastProperty()); Int32OperandId int32IndexId = writer.guardIsInt32(indexId); writer.loadDenseElementResult(objId, int32IndexId); writer.typeMonitorResult(); return true; }
bool GetPropIRGenerator::tryAttachWindowProxy(HandleObject obj, ObjOperandId objId, HandleId id) { // Attach a stub when the receiver is a WindowProxy and we are calling some // kinds of JSNative getters on the Window object (the global object). if (!IsWindowProxy(obj)) return false; // This must be a WindowProxy for the current Window/global. Else it would // be a cross-compartment wrapper and IsWindowProxy returns false for // those. MOZ_ASSERT(obj->getClass() == cx_->maybeWindowProxyClass()); MOZ_ASSERT(ToWindowIfWindowProxy(obj) == cx_->global()); // Now try to do the lookup on the Window (the current global) and see if // it's a native getter. HandleObject windowObj = cx_->global(); RootedShape shape(cx_); RootedNativeObject holder(cx_); NativeGetPropCacheability type = CanAttachNativeGetProp(cx_, windowObj, id, &holder, &shape, pc_, engine_, isTemporarilyUnoptimizable_); if (type != CanAttachCallGetter || !IsCacheableGetPropCallNative(windowObj, holder, shape)) { return false; } // Make sure the native getter is okay with the IC passing the Window // instead of the WindowProxy as |this| value. JSFunction* callee = &shape->getterObject()->as<JSFunction>(); MOZ_ASSERT(callee->isNative()); if (!callee->jitInfo() || callee->jitInfo()->needsOuterizedThisObject()) return false; // Guard the incoming object is a WindowProxy and inline a getter call based // on the Window object. maybeEmitIdGuard(id); writer.guardClass(objId, GuardClassKind::WindowProxy); ObjOperandId windowObjId = writer.loadObject(windowObj); EmitCallGetterResult(writer, windowObj, holder, shape, windowObjId); return true; }
bool ArrayShiftDense(JSContext *cx, HandleObject obj, MutableHandleValue rval) { JS_ASSERT(obj->isArray()); AutoDetectInvalidation adi(cx, rval.address()); Value argv[] = { UndefinedValue(), ObjectValue(*obj) }; AutoValueArray ava(cx, argv, 2); if (!js::array_shift(cx, 0, argv)) return false; // If the result is |undefined|, the array was probably empty and we // have to monitor the return value. rval.set(argv[0]); if (rval.isUndefined()) types::TypeScript::Monitor(cx, rval); return true; }
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; }
bool WatchpointMap::watch(JSContext* cx, HandleObject obj, HandleId id, JSWatchPointHandler handler, HandleObject closure) { MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id) || JSID_IS_SYMBOL(id)); if (!obj->setWatched(cx)) return false; Watchpoint w(handler, closure, false); if (!map.put(WatchKey(obj, id), w)) { ReportOutOfMemory(cx); return false; } /* * For generational GC, we don't need to post-barrier writes to the * hashtable here because we mark all watchpoints as part of root marking in * markAll(). */ return true; }
/* static */ bool GlobalObject::warnOnceAbout(JSContext* cx, HandleObject obj, WarnOnceFlag flag, unsigned errorNumber) { Rooted<GlobalObject*> global(cx, &obj->global()); HeapSlot& v = global->getSlotRef(WARNED_ONCE_FLAGS); MOZ_ASSERT_IF(!v.isUndefined(), v.toInt32()); int32_t flags = v.isUndefined() ? 0 : v.toInt32(); if (!(flags & flag)) { if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, GetErrorMessage, nullptr, errorNumber)) { return false; } if (v.isUndefined()) v.init(global, HeapSlot::Slot, WARNED_ONCE_FLAGS, Int32Value(flags | flag)); else v.set(global, HeapSlot::Slot, WARNED_ONCE_FLAGS, Int32Value(flags | flag)); } return true; }