diff options
author | Moonchild <moonchild@palemoon.org> | 2022-05-24 21:19:51 +0000 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2022-05-24 21:19:51 +0000 |
commit | 46c9f72fc0b85a800d003774d3298c66e56de913 (patch) | |
tree | 0c14990331ec40eadb36d85bdc859d2f7381866f | |
parent | a160e7772a0f3e142b5c50ac4cd9b4f353f9b92d (diff) | |
download | uxp-46c9f72fc0b85a800d003774d3298c66e56de913.tar.gz |
Issue #1742 - Part 3: use JS::PropertyResult instead of Shape*
This is the meat of the issue and switches using raw shape pointers out for
PropertyResult objects where feasible.
33 files changed, 367 insertions, 328 deletions
diff --git a/js/public/Class.h b/js/public/Class.h index 55da324e15..1dd03a1821 100644 --- a/js/public/Class.h +++ b/js/public/Class.h @@ -539,7 +539,7 @@ namespace js { typedef bool (* LookupPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandleObject objp, JS::MutableHandle<Shape*> propp); + JS::MutableHandleObject objp, JS::MutableHandle<JS::PropertyResult> propp); typedef bool (* DefinePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::Handle<JS::PropertyDescriptor> desc, diff --git a/js/src/NamespaceImports.h b/js/src/NamespaceImports.h index de8e3a6f24..2b7a1f0e8b 100644 --- a/js/src/NamespaceImports.h +++ b/js/src/NamespaceImports.h @@ -45,6 +45,7 @@ class MOZ_STACK_CLASS SourceBufferHolder; class HandleValueArray; class ObjectOpResult; +class PropertyResult; class Symbol; enum class SymbolCode: uint32_t; @@ -150,6 +151,7 @@ using JS::FalseHandleValue; using JS::HandleValueArray; using JS::ObjectOpResult; +using JS::PropertyResult; using JS::Zone; diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index 1221d2daf1..d661a222e5 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -69,18 +69,18 @@ js::obj_propertyIsEnumerable(JSContext* cx, unsigned argc, Value* vp) JSObject* obj = &args.thisv().toObject(); /* Step 3. */ - Shape* shape; + PropertyResult prop; if (obj->isNative() && - NativeLookupOwnProperty<NoGC>(cx, &obj->as<NativeObject>(), id, &shape)) + NativeLookupOwnProperty<NoGC>(cx, &obj->as<NativeObject>(), id, &prop)) { /* Step 4. */ - if (!shape) { + if (!prop) { args.rval().setBoolean(false); return true; } /* Step 5. */ - unsigned attrs = GetShapeAttributes(obj, shape); + unsigned attrs = GetPropertyAttributes(obj, prop); args.rval().setBoolean((attrs & JSPROP_ENUMERATE) != 0); return true; } @@ -582,11 +582,11 @@ js::obj_hasOwnProperty(JSContext* cx, unsigned argc, Value* vp) jsid id; if (args.thisv().isObject() && ValueToId<NoGC>(cx, idValue, &id)) { JSObject* obj = &args.thisv().toObject(); - Shape* prop; + PropertyResult prop; if (obj->isNative() && NativeLookupOwnProperty<NoGC>(cx, &obj->as<NativeObject>(), id, &prop)) { - args.rval().setBoolean(!!prop); + args.rval().setBoolean(prop.isFound()); return true; } } @@ -839,7 +839,7 @@ EnumerableOwnProperties(JSContext* cx, const JS::CallArgs& args, EnumerableOwnPr value = nobj->getDenseOrTypedArrayElement(JSID_TO_INT(id)); } else { shape = nobj->lookup(cx, id); - if (!shape || !(GetShapeAttributes(nobj, shape) & JSPROP_ENUMERATE)) + if (!shape || !(shape->attributes() & JSPROP_ENUMERATE)) continue; if (!shape->isAccessorShape()) { if (!NativeGetExistingProperty(cx, nobj, nobj, shape, &value)) diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index 4c938568f0..2796848c02 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -1671,10 +1671,10 @@ TypeDescr::hasProperty(const JSAtomState& names, jsid id) /* static */ bool TypedObject::obj_lookupProperty(JSContext* cx, HandleObject obj, HandleId id, - MutableHandleObject objp, MutableHandleShape propp) + MutableHandleObject objp, MutableHandle<PropertyResult> propp) { if (obj->as<TypedObject>().typeDescr().hasProperty(cx->names(), id)) { - MarkNonNativePropertyFound<CanGC>(propp); + propp.setNonNativeProperty(); objp.set(obj); return true; } @@ -1682,7 +1682,7 @@ TypedObject::obj_lookupProperty(JSContext* cx, HandleObject obj, HandleId id, RootedObject proto(cx, obj->staticPrototype()); if (!proto) { objp.set(nullptr); - propp.set(nullptr); + propp.setNotFound(); return true; } diff --git a/js/src/builtin/TypedObject.h b/js/src/builtin/TypedObject.h index 4fcd30cb0b..83700001d4 100644 --- a/js/src/builtin/TypedObject.h +++ b/js/src/builtin/TypedObject.h @@ -509,7 +509,7 @@ class TypedObject : public ShapedObject static MOZ_MUST_USE bool obj_lookupProperty(JSContext* cx, HandleObject obj, HandleId id, MutableHandleObject objp, - MutableHandleShape propp); + MutableHandle<PropertyResult> propp); static MOZ_MUST_USE bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, Handle<PropertyDescriptor> desc, diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index f5dcd2a106..7dbe239a7e 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -1145,9 +1145,9 @@ TryAttachNativeOrUnboxedGetValueElemStub(JSContext* cx, HandleScript script, jsb return true; bool needsAtomize = checkAtomize<T>(keyVal); - RootedShape shape(cx); + Rooted<PropertyResult> prop(cx); RootedObject holder(cx); - if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape)) + if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &prop)) return false; if (!holder || (holder != obj && !holder->isNative())) return true; @@ -1214,6 +1214,8 @@ TryAttachNativeOrUnboxedGetValueElemStub(JSContext* cx, HandleScript script, jsb if (!holder->isNative()) return true; + RootedShape shape(cx, prop.shape()); + if (IsCacheableGetPropReadSlot(obj, holder, shape)) { bool isFixedSlot; uint32_t offset; @@ -1264,13 +1266,14 @@ TryAttachNativeGetAccessorElemStub(JSContext* cx, HandleScript script, jsbytecod return true; bool needsAtomize = checkAtomize<T>(keyVal); - RootedShape shape(cx); + Rooted<PropertyResult> prop(cx); RootedObject baseHolder(cx); - if (!EffectlesslyLookupProperty(cx, obj, id, &baseHolder, &shape)) + if (!EffectlesslyLookupProperty(cx, obj, id, &baseHolder, &prop)) return false; if (!baseHolder || !baseHolder->isNative()) return true; + RootedShape shape(cx, prop.shape()); HandleNativeObject holder = baseHolder.as<NativeObject>(); bool getterIsScripted = false; @@ -3348,11 +3351,17 @@ TryAttachNativeInStub(JSContext* cx, HandleScript outerScript, ICIn_Fallback* st return true; RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName()); - RootedShape shape(cx); + Rooted<PropertyResult> prop(cx); RootedObject holder(cx); - if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape)) + if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &prop)) return false; + if (prop.isNonNativeProperty()) { + MOZ_ASSERT(!IsCacheableProtoChain(obj, holder, false)); + return true; + } + + RootedShape shape(cx, prop.maybeShape()); if (IsCacheableGetPropReadSlot(obj, holder, shape)) { ICStub::Kind kind = (obj == holder) ? ICStub::In_Native : ICStub::In_NativePrototype; @@ -4259,14 +4268,17 @@ TryAttachSetValuePropStub(JSContext* cx, HandleScript script, jsbytecode* pc, IC { MOZ_ASSERT(!*attached); - RootedShape shape(cx); + Rooted<PropertyResult> prop(cx); RootedObject holder(cx); - if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape)) + if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &prop)) return false; if (obj != holder) return true; - if (!obj->isNative()) { + RootedShape shape(cx); + if (obj->isNative()) { + shape = prop.shape(); + } else { if (obj->is<UnboxedPlainObject>()) { UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando(); if (expando) { @@ -4365,11 +4377,17 @@ TryAttachSetAccessorPropStub(JSContext* cx, HandleScript script, jsbytecode* pc, MOZ_ASSERT(!*attached); MOZ_ASSERT(!*isTemporarilyUnoptimizable); - RootedShape shape(cx); + Rooted<PropertyResult> prop(cx); RootedObject holder(cx); - if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape)) + if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &prop)) return false; + if (prop.isNonNativeProperty()) { + MOZ_ASSERT(!IsCacheableProtoChain(obj, holder)); + return true; + } + + RootedShape shape(cx, prop.maybeShape()); bool isScripted = false; bool cacheableCall = IsCacheableSetPropCall(cx, obj, holder, shape, &isScripted, isTemporarilyUnoptimizable); diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp index fc58bdb98e..9168a344e5 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -109,7 +109,8 @@ CanAttachNativeGetProp(JSContext* cx, HandleObject obj, HandleId id, // only miss out on shape hashification, which is only a temporary perf cost. // The limits were arbitrarily set, anyways. JSObject* baseHolder = nullptr; - if (!LookupPropertyPure(cx, obj, id, &baseHolder, shape.address())) + PropertyResult prop; + if (!LookupPropertyPure(cx, obj, id, &baseHolder, &prop)) return CanAttachNone; MOZ_ASSERT(!holder); @@ -118,8 +119,9 @@ CanAttachNativeGetProp(JSContext* cx, HandleObject obj, HandleId id, return CanAttachNone; holder.set(&baseHolder->as<NativeObject>()); } + shape.set(prop.maybeShape()); - if (IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, shape) || + if (IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, prop) || IsCacheableNoProperty(cx, obj, holder, shape, id, pc)) { return CanAttachReadSlot; diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 0a0c7ac22e..5a7e437285 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -468,11 +468,12 @@ jit::IsCacheableProtoChainForIonOrCacheIR(JSObject* obj, JSObject* holder) } bool -jit::IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder, Shape* shape) +jit::IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder, PropertyResult prop) { - if (!shape || !IsCacheableProtoChainForIonOrCacheIR(obj, holder)) + if (!prop || !IsCacheableProtoChainForIonOrCacheIR(obj, holder)) return false; + Shape* shape = prop.shape(); if (!shape->hasSlot() || !shape->hasDefaultGetter()) return false; @@ -480,10 +481,10 @@ jit::IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder, } static bool -IsCacheableNoProperty(JSObject* obj, JSObject* holder, Shape* shape, jsbytecode* pc, +IsCacheableNoProperty(JSObject* obj, JSObject* holder, PropertyResult prop, jsbytecode* pc, const TypedOrValueRegister& output) { - if (shape) + if (prop) return false; MOZ_ASSERT(!holder); @@ -751,7 +752,7 @@ CheckDOMProxyExpandoDoesNotShadow(JSContext* cx, MacroAssembler& masm, JSObject* static void GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm, IonCache::StubAttacher& attacher, MaybeCheckTDZ checkTDZ, - JSObject* obj, JSObject* holder, Shape* shape, Register object, + JSObject* obj, JSObject* holder, PropertyResult prop, Register object, TypedOrValueRegister output, Label* failures = nullptr) { // If there's a single jump to |failures|, we can patch the shape guard @@ -778,7 +779,7 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm, if (obj != holder || obj->is<UnboxedPlainObject>() || - !holder->as<NativeObject>().isFixedSlot(shape->slot())) + !holder->as<NativeObject>().isFixedSlot(prop.shape()->slot())) { if (output.hasValue()) { scratchReg = output.valueReg().scratchReg(); @@ -793,7 +794,7 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm, // Fast path: single failure jump, no prototype guards. if (!multipleFailureJumps) { - EmitLoadSlot(masm, &holder->as<NativeObject>(), shape, object, output, scratchReg); + EmitLoadSlot(masm, &holder->as<NativeObject>(), prop.shape(), object, output, scratchReg); if (restoreScratch) masm.pop(scratchReg); attacher.jumpRejoin(masm); @@ -848,7 +849,8 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm, // Slot access. if (holder) { - EmitLoadSlot(masm, &holder->as<NativeObject>(), shape, holderReg, output, scratchReg); + EmitLoadSlot(masm, &holder->as<NativeObject>(), prop.shape(), holderReg, output, + scratchReg); if (checkTDZ && output.hasValue()) masm.branchTestMagic(Assembler::Equal, output.valueReg(), failures); } else { @@ -1294,7 +1296,8 @@ CanAttachNativeGetProp(JSContext* cx, const GetPropCache& cache, // only miss out on shape hashification, which is only a temporary perf cost. // The limits were arbitrarily set, anyways. JSObject* baseHolder = nullptr; - if (!LookupPropertyPure(cx, obj, id, &baseHolder, shape.address())) + PropertyResult prop; + if (!LookupPropertyPure(cx, obj, id, &baseHolder, &prop)) return GetPropertyIC::CanAttachNone; MOZ_ASSERT(!holder); @@ -1303,12 +1306,13 @@ CanAttachNativeGetProp(JSContext* cx, const GetPropCache& cache, return GetPropertyIC::CanAttachNone; holder.set(&baseHolder->as<NativeObject>()); } + shape.set(prop.maybeShape()); RootedScript script(cx); jsbytecode* pc; cache.getScriptedLocation(&script, &pc); - if (IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, shape) || - IsCacheableNoProperty(obj, holder, shape, pc, cache.output())) + if (IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, prop) || + IsCacheableNoProperty(obj, holder, prop, pc, cache.output())) { return GetPropertyIC::CanAttachReadSlot; } @@ -1505,7 +1509,7 @@ GetPropertyIC::tryAttachNative(JSContext* cx, HandleScript outerScript, IonScrip switch (type) { case CanAttachReadSlot: GenerateReadSlot(cx, ion, masm, attacher, DontCheckTDZ, obj, holder, - shape, object(), output(), maybeFailures); + PropertyResult(shape), object(), output(), maybeFailures); attachKind = idempotent() ? "idempotent reading" : "non idempotent reading"; outcome = JS::TrackedOutcome::ICGetPropStub_ReadSlot; @@ -1588,7 +1592,7 @@ GetPropertyIC::tryAttachUnboxedExpando(JSContext* cx, HandleScript outerScript, StubAttacher attacher(*this); GenerateReadSlot(cx, ion, masm, attacher, DontCheckTDZ, obj, obj, - shape, object(), output(), maybeFailures); + PropertyResult(shape), object(), output(), maybeFailures); return linkAndAttachStub(cx, masm, attacher, ion, "read unboxed expando", JS::TrackedOutcome::ICGetPropStub_UnboxedReadExpando); } @@ -2927,12 +2931,14 @@ IsCacheableDOMProxyUnshadowedSetterCall(JSContext* cx, HandleObject obj, HandleI if (!checkObj) return false; - if (!LookupPropertyPure(cx, obj, id, holder.address(), shape.address())) + PropertyResult prop; + if (!LookupPropertyPure(cx, obj, id, holder.address(), &prop)) return false; - if (!holder) + if (!holder || !holder->isNative()) return false; + shape.set(prop.shape()); return IsCacheableSetPropCallNative(checkObj, holder, shape) || IsCacheableSetPropCallPropertyOp(checkObj, holder, shape) || IsCacheableSetPropCallScripted(checkObj, holder, shape); @@ -3344,22 +3350,26 @@ CanAttachNativeSetProp(JSContext* cx, HandleObject obj, HandleId id, const Const // If we couldn't find the property on the object itself, do a full, but // still pure lookup for setters. - if (!LookupPropertyPure(cx, obj, id, holder.address(), shape.address())) + Rooted<PropertyResult> prop(cx); + if (!LookupPropertyPure(cx, obj, id, holder.address(), prop.address())) return SetPropertyIC::CanAttachNone; // If the object doesn't have the property, we don't know if we can attach // a stub to add the property until we do the VM call to add. If the // property exists as a data property on the prototype, we should add // a new, shadowing property. - if (obj->isNative() && (!shape || (obj != holder && holder->isNative() && - shape->hasDefaultSetter() && shape->hasSlot()))) + if (obj->isNative() && + (!prop || (obj != holder && holder->isNative() && + prop.shape()->hasDefaultSetter() && prop.shape()->hasSlot()))) { + shape.set(prop.maybeShape()); return SetPropertyIC::MaybeCanAttachAddSlot; } - if (IsImplicitNonNativeProperty(shape)) + if (prop.isNonNativeProperty()) return SetPropertyIC::CanAttachNone; + shape.set(prop.maybeShape()); if (IsCacheableSetPropCallPropertyOp(obj, holder, shape) || IsCacheableSetPropCallNative(obj, holder, shape) || IsCacheableSetPropCallScripted(obj, holder, shape)) @@ -4836,7 +4846,7 @@ BindNameIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex, bool NameIC::attachReadSlot(JSContext* cx, HandleScript outerScript, IonScript* ion, HandleObject envChain, HandleObject holderBase, - HandleNativeObject holder, HandleShape shape) + HandleNativeObject holder, Handle<PropertyResult> prop) { MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_); Label failures; @@ -4854,7 +4864,7 @@ NameIC::attachReadSlot(JSContext* cx, HandleScript outerScript, IonScript* ion, // doesn't generate the extra guard. // // NAME ops must do their own TDZ checks. - GenerateReadSlot(cx, ion, masm, attacher, CheckTDZ, holderBase, holder, shape, scratchReg, + GenerateReadSlot(cx, ion, masm, attacher, CheckTDZ, holderBase, holder, prop, scratchReg, outputReg(), failures.used() ? &failures : nullptr); return linkAndAttachStub(cx, masm, attacher, ion, "generic", @@ -4880,26 +4890,26 @@ IsCacheableEnvironmentChain(JSObject* envChain, JSObject* obj) } static bool -IsCacheableNameReadSlot(HandleObject envChain, HandleObject obj, - HandleObject holder, HandleShape shape, jsbytecode* pc, +IsCacheableNameReadSlot(JSContext* cx, HandleObject envChain, HandleObject obj, + HandleObject holder, Handle<PropertyResult> prop, jsbytecode* pc, const TypedOrValueRegister& output) { - if (!shape) + if (!prop) return false; if (!obj->isNative()) return false; if (obj->is<GlobalObject>()) { // Support only simple property lookups. - if (!IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, shape) && - !IsCacheableNoProperty(obj, holder, shape, pc, output)) + if (!IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, prop) && + !IsCacheableNoProperty(obj, holder, prop, pc, output)) return false; } else if (obj->is<ModuleEnvironmentObject>()) { // We don't yet support lookups in a module environment. return false; } else if (obj->is<CallObject>()) { MOZ_ASSERT(obj == holder); - if (!shape->hasDefaultGetter()) + if (!prop.shape()->hasDefaultGetter()) return false; } else { // We don't yet support lookups on Block or DeclEnv objects. @@ -4942,9 +4952,9 @@ NameIC::attachCallGetter(JSContext* cx, HandleScript outerScript, IonScript* ion static bool IsCacheableNameCallGetter(HandleObject envChain, HandleObject obj, HandleObject holder, - HandleShape shape) + Handle<PropertyResult> prop) { - if (!shape) + if (!prop) return false; if (!obj->is<GlobalObject>()) return false; @@ -4952,6 +4962,10 @@ IsCacheableNameCallGetter(HandleObject envChain, HandleObject obj, HandleObject if (!IsCacheableEnvironmentChain(envChain, obj)) return false; + if (!prop || !IsCacheableProtoChainForIonOrCacheIR(obj, holder)) + return false; + + Shape* shape = prop.shape(); return IsCacheableGetPropCallNative(obj, holder, shape) || IsCacheableGetPropCallPropertyOp(obj, holder, shape) || IsCacheableGetPropCallScripted(obj, holder, shape); @@ -4996,10 +5010,10 @@ NameIC::attachTypeOfNoProperty(JSContext* cx, HandleScript outerScript, IonScrip static bool IsCacheableNameNoProperty(HandleObject envChain, HandleObject obj, - HandleObject holder, HandleShape shape, jsbytecode* pc, + HandleObject holder, Handle<PropertyResult> prop, jsbytecode* pc, NameIC& cache) { - if (cache.isTypeOf() && !shape) { + if (cache.isTypeOf() && !prop) { MOZ_ASSERT(!obj); MOZ_ASSERT(!holder); MOZ_ASSERT(envChain); @@ -5029,34 +5043,35 @@ NameIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex, Handl RootedObject obj(cx); RootedObject holder(cx); - RootedShape shape(cx); - if (!LookupName(cx, name, envChain, &obj, &holder, &shape)) + Rooted<PropertyResult> prop(cx); + if (!LookupName(cx, name, envChain, &obj, &holder, &prop)) return false; // Look first. Don't generate cache entries if the lookup fails. if (cache.isTypeOf()) { - if (!FetchName<true>(cx, obj, holder, name, shape, vp)) + if (!FetchName<true>(cx, obj, holder, name, prop, vp)) return false; } else { - if (!FetchName<false>(cx, obj, holder, name, shape, vp)) + if (!FetchName<false>(cx, obj, holder, name, prop, vp)) return false; } if (cache.canAttachStub()) { - if (IsCacheableNameReadSlot(envChain, obj, holder, shape, pc, cache.outputReg())) { + if (IsCacheableNameReadSlot(cx, envChain, obj, holder, prop, pc, cache.outputReg())) { if (!cache.attachReadSlot(cx, outerScript, ion, envChain, obj, - holder.as<NativeObject>(), shape)) + holder.as<NativeObject>(), prop)) { return false; } - } else if (IsCacheableNameCallGetter(envChain, obj, holder, shape)) { + } else if (IsCacheableNameCallGetter(envChain, obj, holder, prop)) { void* returnAddr = GetReturnAddressToIonCode(cx); + RootedShape shape(cx, prop.shape()); if (!cache.attachCallGetter(cx, outerScript, ion, envChain, obj, holder, shape, returnAddr)) { return false; } - } else if (IsCacheableNameNoProperty(envChain, obj, holder, shape, pc, cache)) { + } else if (IsCacheableNameNoProperty(envChain, obj, holder, prop, pc, cache)) { if (!cache.attachTypeOfNoProperty(cx, outerScript, ion, envChain)) return false; } diff --git a/js/src/jit/IonCaches.h b/js/src/jit/IonCaches.h index a7135000e5..914965055b 100644 --- a/js/src/jit/IonCaches.h +++ b/js/src/jit/IonCaches.h @@ -806,7 +806,7 @@ class NameIC : public IonCache MOZ_MUST_USE bool attachReadSlot(JSContext* cx, HandleScript outerScript, IonScript* ion, HandleObject envChain, HandleObject holderBase, - HandleNativeObject holder, HandleShape shape); + HandleNativeObject holder, Handle<PropertyResult> prop); MOZ_MUST_USE bool attachCallGetter(JSContext* cx, HandleScript outerScript, IonScript* ion, HandleObject envChain, HandleObject obj, @@ -839,7 +839,7 @@ IONCACHE_KIND_LIST(CACHE_CASTS) #undef OPCODE_CASTS bool IsCacheableProtoChainForIonOrCacheIR(JSObject* obj, JSObject* holder); -bool IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder, Shape* shape); +bool IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder, PropertyResult prop); } // namespace jit } // namespace js diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp index 1434894193..f8f4433af7 100644 --- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -2192,12 +2192,12 @@ GetDOMProxyProto(JSObject* obj) // existence of the property on the object. bool EffectlesslyLookupProperty(JSContext* cx, HandleObject obj, HandleId id, - MutableHandleObject holder, MutableHandleShape shape, + MutableHandleObject holder, MutableHandle<PropertyResult> prop, bool* checkDOMProxy, DOMProxyShadowsResult* shadowsResult, bool* domProxyHasGeneration) { - shape.set(nullptr); + prop.setNotFound(); holder.set(nullptr); if (checkDOMProxy) { @@ -2231,11 +2231,11 @@ EffectlesslyLookupProperty(JSContext* cx, HandleObject obj, HandleId id, return true; } - if (LookupPropertyPure(cx, checkObj, id, holder.address(), shape.address())) + if (LookupPropertyPure(cx, checkObj, id, holder.address(), prop.address())) return true; holder.set(nullptr); - shape.set(nullptr); + prop.setNotFound(); return true; } @@ -2421,15 +2421,16 @@ TryAttachNativeGetAccessorPropStub(JSContext* cx, SharedStubInfo* info, bool isDOMProxy; bool domProxyHasGeneration; DOMProxyShadowsResult domProxyShadowsResult; - RootedShape shape(cx); + Rooted<PropertyResult> prop(cx); RootedObject holder(cx); RootedId id(cx, NameToId(name)); - if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape, &isDOMProxy, + if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &prop, &isDOMProxy, &domProxyShadowsResult, &domProxyHasGeneration)) { return false; } + RootedShape shape(cx, prop.maybeShape()); ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub(); bool isScripted = false; @@ -2492,7 +2493,7 @@ TryAttachNativeGetAccessorPropStub(JSContext* cx, SharedStubInfo* info, MOZ_ASSERT(ToWindowIfWindowProxy(obj) == cx->global()); obj = cx->global(); - if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape, &isDOMProxy, + if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &prop, &isDOMProxy, &domProxyShadowsResult, &domProxyHasGeneration)) { return false; diff --git a/js/src/jit/SharedIC.h b/js/src/jit/SharedIC.h index 8ad8fd495b..d0038c9378 100644 --- a/js/src/jit/SharedIC.h +++ b/js/src/jit/SharedIC.h @@ -2249,7 +2249,7 @@ StripPreliminaryObjectStubs(JSContext* cx, ICFallbackStub* stub); MOZ_MUST_USE bool EffectlesslyLookupProperty(JSContext* cx, HandleObject obj, HandleId name, - MutableHandleObject holder, MutableHandleShape shape, + MutableHandleObject holder, MutableHandle<PropertyResult> prop, bool* checkDOMProxy=nullptr, DOMProxyShadowsResult* shadowsResult=nullptr, bool* domProxyHasGeneration=nullptr); diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index fd41f6fbcb..fbe6977bf9 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -583,11 +583,11 @@ GetDynamicName(JSContext* cx, JSObject* envChain, JSString* str, Value* vp) return; } - Shape* shape = nullptr; + PropertyResult prop; JSObject* scope = nullptr; JSObject* pobj = nullptr; - if (LookupNameNoGC(cx, atom->asPropertyName(), envChain, &scope, &pobj, &shape)) { - if (FetchNameNoGC(pobj, shape, MutableHandleValue::fromMarkedLocation(vp))) + if (LookupNameNoGC(cx, atom->asPropertyName(), envChain, &scope, &pobj, &prop)) { + if (FetchNameNoGC(pobj, prop, MutableHandleValue::fromMarkedLocation(vp))) return; } diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index f4b3c98545..3901a0e63c 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -2947,9 +2947,9 @@ JS_AlreadyHasOwnPropertyById(JSContext* cx, HandleObject obj, HandleId id, bool* return js::HasOwnProperty(cx, obj, id, foundp); RootedNativeObject nativeObj(cx, &obj->as<NativeObject>()); - RootedShape prop(cx); + Rooted<PropertyResult> prop(cx); NativeLookupOwnPropertyNoResolve(cx, nativeObj, id, &prop); - *foundp = !!prop; + *foundp = prop.isFound(); return true; } diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 95f49b35e3..494bcb042a 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -331,7 +331,7 @@ extern JS_FRIEND_DATA(const js::ObjectOps) ProxyObjectOps; extern JS_FRIEND_API(bool) proxy_LookupProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleObject objp, - JS::MutableHandle<Shape*> propp); + JS::MutableHandle<JS::PropertyResult> propp); extern JS_FRIEND_API(bool) proxy_DefineProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::Handle<JS::PropertyDescriptor> desc, diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index a243f44681..a23ac63366 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -2116,7 +2116,7 @@ JSObject::constructHook() const bool js::LookupProperty(JSContext* cx, HandleObject obj, js::HandleId id, - MutableHandleObject objp, MutableHandleShape propp) + MutableHandleObject objp, MutableHandle<PropertyResult> propp) { /* NB: The logic of lookupProperty is implicitly reflected in * BaselineIC.cpp's |EffectlesslyLookupProperty| logic. @@ -2129,7 +2129,7 @@ js::LookupProperty(JSContext* cx, HandleObject obj, js::HandleId id, bool js::LookupName(JSContext* cx, HandlePropertyName name, HandleObject envChain, - MutableHandleObject objp, MutableHandleObject pobjp, MutableHandleShape propp) + MutableHandleObject objp, MutableHandleObject pobjp, MutableHandle<PropertyResult> propp) { RootedId id(cx, NameToId(name)); @@ -2144,13 +2144,13 @@ js::LookupName(JSContext* cx, HandlePropertyName name, HandleObject envChain, objp.set(nullptr); pobjp.set(nullptr); - propp.set(nullptr); + propp.setNotFound(); return true; } bool js::LookupNameNoGC(JSContext* cx, PropertyName* name, JSObject* envChain, - JSObject** objp, JSObject** pobjp, Shape** propp) + JSObject** objp, JSObject** pobjp, PropertyResult* propp) { AutoAssertNoException nogc(cx); @@ -2177,13 +2177,13 @@ js::LookupNameWithGlobalDefault(JSContext* cx, HandlePropertyName name, HandleOb RootedId id(cx, NameToId(name)); RootedObject pobj(cx); - RootedShape shape(cx); + Rooted<PropertyResult> prop(cx); RootedObject env(cx, envChain); for (; !env->is<GlobalObject>(); env = env->enclosingEnvironment()) { - if (!LookupProperty(cx, env, id, &pobj, &shape)) + if (!LookupProperty(cx, env, id, &pobj, &prop)) return false; - if (shape) + if (prop) break; } @@ -2198,20 +2198,20 @@ js::LookupNameUnqualified(JSContext* cx, HandlePropertyName name, HandleObject e RootedId id(cx, NameToId(name)); RootedObject pobj(cx); - RootedShape shape(cx); + Rooted<PropertyResult> prop(cx); RootedObject env(cx, envChain); for (; !env->isUnqualifiedVarObj(); env = env->enclosingEnvironment()) { - if (!LookupProperty(cx, env, id, &pobj, &shape)) + if (!LookupProperty(cx, env, id, &pobj, &prop)) return false; - if (shape) + if (prop) break; } // See note above RuntimeLexicalErrorObject. if (pobj == env) { bool isTDZ = false; - if (shape && name != cx->names().dotThis) { + if (prop && name != cx->names().dotThis) { // Treat Debugger environments specially for TDZ checks, as they // look like non-native environments but in fact wrap native // environments. @@ -2222,7 +2222,7 @@ js::LookupNameUnqualified(JSContext* cx, HandlePropertyName name, HandleObject e return false; isTDZ = IsUninitializedLexical(v); } else { - isTDZ = IsUninitializedLexicalSlot(env, shape); + isTDZ = IsUninitializedLexicalSlot(env, prop); } } @@ -2230,7 +2230,7 @@ js::LookupNameUnqualified(JSContext* cx, HandlePropertyName name, HandleObject e env = RuntimeLexicalErrorObject::create(cx, env, JSMSG_UNINITIALIZED_LEXICAL); if (!env) return false; - } else if (env->is<LexicalEnvironmentObject>() && !shape->writable()) { + } else if (env->is<LexicalEnvironmentObject>() && !prop.shape()->writable()) { // Assigning to a named lambda callee name is a no-op in sloppy mode. Rooted<LexicalEnvironmentObject*> lexicalEnv(cx, &env->as<LexicalEnvironmentObject>()); if (lexicalEnv->isExtensible() || @@ -2262,16 +2262,16 @@ js::HasOwnProperty(JSContext* cx, HandleObject obj, HandleId id, bool* result) return true; } - RootedShape shape(cx); - if (!NativeLookupOwnProperty<CanGC>(cx, obj.as<NativeObject>(), id, &shape)) + Rooted<PropertyResult> prop(cx); + if (!NativeLookupOwnProperty<CanGC>(cx, obj.as<NativeObject>(), id, &prop)) return false; - *result = (shape != nullptr); + *result = prop.isFound(); return true; } bool js::LookupPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, JSObject** objp, - Shape** propp) + PropertyResult* propp) { bool isTypedArrayOutOfRange = false; do { @@ -2292,12 +2292,12 @@ js::LookupPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, JSObject** } while (obj); *objp = nullptr; - *propp = nullptr; + propp->setNotFound(); return true; } bool -js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape** propp, +js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, PropertyResult* propp, bool* isTypedArrayOutOfRange /* = nullptr */) { JS::AutoCheckCannotGC nogc; @@ -2308,7 +2308,7 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape** // Search for a native dense element, typed array element, or property. if (JSID_IS_INT(id) && obj->as<NativeObject>().containsDenseElement(JSID_TO_INT(id))) { - MarkDenseOrTypedArrayElementFound<NoGC>(propp); + propp->setDenseOrTypedArrayElement(); return true; } @@ -2316,9 +2316,9 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape** uint64_t index; if (IsTypedArrayIndex(id, &index)) { if (index < obj->as<TypedArrayObject>().length()) { - MarkDenseOrTypedArrayElementFound<NoGC>(propp); + propp->setDenseOrTypedArrayElement(); } else { - *propp = nullptr; + propp->setNotFound(); if (isTypedArrayOutOfRange) *isTypedArrayOutOfRange = true; } @@ -2327,7 +2327,7 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape** } if (Shape* shape = obj->as<NativeObject>().lookupPure(id)) { - *propp = shape; + propp->setNativeProperty(shape); return true; } @@ -2337,31 +2337,31 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape** return false; } else if (obj->is<UnboxedPlainObject>()) { if (obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id)) { - MarkNonNativePropertyFound<NoGC>(propp); + propp->setNonNativeProperty(); return true; } } else if (obj->is<UnboxedArrayObject>()) { if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) { - MarkNonNativePropertyFound<NoGC>(propp); + propp->setNonNativeProperty(); return true; } } else if (obj->is<TypedObject>()) { if (obj->as<TypedObject>().typeDescr().hasProperty(cx->names(), id)) { - MarkNonNativePropertyFound<NoGC>(propp); + propp->setNonNativeProperty(); return true; } } else { return false; } - *propp = nullptr; + propp->setNotFound(); return true; } static inline bool -NativeGetPureInline(NativeObject* pobj, jsid id, Shape* shape, Value* vp) +NativeGetPureInline(NativeObject* pobj, jsid id, PropertyResult prop, Value* vp) { - if (IsImplicitDenseOrTypedArrayElement(shape)) { + if (prop.isDenseOrTypedArrayElement()) { // For simplicity we ignore the TypedArray with string index case. if (!JSID_IS_INT(id)) return false; @@ -2371,6 +2371,7 @@ NativeGetPureInline(NativeObject* pobj, jsid id, Shape* shape, Value* vp) } // Fail if we have a custom getter. + Shape* shape = prop.shape(); if (!shape->hasDefaultGetter()) return false; @@ -2388,22 +2389,23 @@ bool js::GetPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Value* vp) { JSObject* pobj; - Shape* shape; - if (!LookupPropertyPure(cx, obj, id, &pobj, &shape)) + PropertyResult prop; + if (!LookupPropertyPure(cx, obj, id, &pobj, &prop)) return false; - if (!shape) { + if (!prop) { vp->setUndefined(); return true; } - return pobj->isNative() && NativeGetPureInline(&pobj->as<NativeObject>(), id, shape, vp); + return pobj->isNative() && NativeGetPureInline(&pobj->as<NativeObject>(), id, prop, vp); } static inline bool -NativeGetGetterPureInline(Shape* shape, JSFunction** fp) +NativeGetGetterPureInline(PropertyResult prop, JSFunction** fp) { - if (!IsImplicitDenseOrTypedArrayElement(shape) && shape->hasGetterObject()) { + if (!prop.isDenseOrTypedArrayElement() && prop.shape()->hasGetterObject()) { + Shape* shape = prop.shape(); if (shape->getterObject()->is<JSFunction>()) { *fp = &shape->getterObject()->as<JSFunction>(); return true; @@ -2420,32 +2422,32 @@ js::GetGetterPure(ExclusiveContext* cx, JSObject* obj, jsid id, JSFunction** fp) /* Just like GetPropertyPure, but get getter function, without invoking * it. */ JSObject* pobj; - Shape* shape; - if (!LookupPropertyPure(cx, obj, id, &pobj, &shape)) + PropertyResult prop; + if (!LookupPropertyPure(cx, obj, id, &pobj, &prop)) return false; - if (!shape) { + if (!prop) { *fp = nullptr; return true; } - return pobj->isNative() && NativeGetGetterPureInline(shape, fp); + return prop.isNativeProperty() && NativeGetGetterPureInline(prop, fp); } bool js::GetOwnGetterPure(ExclusiveContext* cx, JSObject* obj, jsid id, JSFunction** fp) { JS::AutoCheckCannotGC nogc; - Shape* shape; - if (!LookupOwnPropertyPure(cx, obj, id, &shape)) + PropertyResult prop; + if (!LookupOwnPropertyPure(cx, obj, id, &prop)) return false; - if (!shape) { + if (!prop) { *fp = nullptr; return true; } - return NativeGetGetterPureInline(shape, fp); + return prop.isNativeProperty() && NativeGetGetterPureInline(prop, fp); } bool @@ -2453,14 +2455,14 @@ js::GetOwnNativeGetterPure(JSContext* cx, JSObject* obj, jsid id, JSNative* nati { JS::AutoCheckCannotGC nogc; *native = nullptr; - Shape* shape; - if (!LookupOwnPropertyPure(cx, obj, id, &shape)) + PropertyResult prop; + if (!LookupOwnPropertyPure(cx, obj, id, &prop)) return false; - if (!shape || IsImplicitDenseOrTypedArrayElement(shape) || !shape->hasGetterObject()) + if (!prop || prop.isDenseOrTypedArrayElement() || !prop.shape()->hasGetterObject()) return true; - JSObject* getterObj = shape->getterObject(); + JSObject* getterObj = prop.shape()->getterObject(); if (!getterObj->is<JSFunction>()) return true; @@ -2475,12 +2477,12 @@ js::GetOwnNativeGetterPure(JSContext* cx, JSObject* obj, jsid id, JSNative* nati bool js::HasOwnDataPropertyPure(JSContext* cx, JSObject* obj, jsid id, bool* result) { - Shape* shape = nullptr; - if (!LookupOwnPropertyPure(cx, obj, id, &shape)) + PropertyResult prop; + if (!LookupOwnPropertyPure(cx, obj, id, &prop)) return false; - *result = shape && !IsImplicitDenseOrTypedArrayElement(shape) && shape->hasDefaultGetter() && - shape->hasSlot(); + *result = prop && !prop.isDenseOrTypedArrayElement() && prop.shape()->hasDefaultGetter() && + prop.shape()->hasSlot(); return true; } diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 52be7e8188..68491a1aa9 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -999,11 +999,11 @@ GetPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, */ extern bool LookupProperty(JSContext* cx, HandleObject obj, HandleId id, - MutableHandleObject objp, MutableHandleShape propp); + MutableHandleObject objp, MutableHandle<PropertyResult> propp); inline bool LookupProperty(JSContext* cx, HandleObject obj, PropertyName* name, - MutableHandleObject objp, MutableHandleShape propp) + MutableHandleObject objp, MutableHandle<PropertyResult> propp) { RootedId id(cx, NameToId(name)); return LookupProperty(cx, obj, id, objp, propp); @@ -1195,11 +1195,11 @@ ReadPropertyDescriptors(JSContext* cx, HandleObject props, bool checkAccessors, /* Read the name using a dynamic lookup on the scopeChain. */ extern bool LookupName(JSContext* cx, HandlePropertyName name, HandleObject scopeChain, - MutableHandleObject objp, MutableHandleObject pobjp, MutableHandleShape propp); + MutableHandleObject objp, MutableHandleObject pobjp, MutableHandle<PropertyResult> propp); extern bool LookupNameNoGC(JSContext* cx, PropertyName* name, JSObject* scopeChain, - JSObject** objp, JSObject** pobjp, Shape** propp); + JSObject** objp, JSObject** pobjp, PropertyResult* propp); /* * Like LookupName except returns the global object if 'name' is not found in @@ -1233,10 +1233,10 @@ FindVariableScope(JSContext* cx, JSFunction** funp); bool LookupPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, JSObject** objp, - Shape** propp); + PropertyResult* propp); bool -LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape** propp, +LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, PropertyResult* propp, bool* isTypedArrayOutOfRange = nullptr); bool diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 8a55cd435c..07eeff655e 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -585,11 +585,11 @@ HasNoToPrimitiveMethodPure(JSObject* obj, JSContext* cx) { jsid id = SYMBOL_TO_JSID(cx->wellKnownSymbols().toPrimitive); JSObject* pobj; - Shape* shape; - if (!LookupPropertyPure(cx, obj, id, &pobj, &shape)) + PropertyResult prop; + if (!LookupPropertyPure(cx, obj, id, &pobj, &prop)) return false; - return !shape; + return !prop; } /* ES6 draft rev 28 (2014 Oct 14) 7.1.14 */ diff --git a/js/src/json.cpp b/js/src/json.cpp index e32994e908..f3cf22dac9 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -445,9 +445,9 @@ JO(JSContext* cx, HandleObject obj, StringifyContext* scx) #ifdef DEBUG if (scx->maybeSafely) { RootedNativeObject nativeObj(cx, &obj->as<NativeObject>()); - RootedShape prop(cx); + Rooted<PropertyResult> prop(cx); NativeLookupOwnPropertyNoResolve(cx, nativeObj, id, &prop); - MOZ_ASSERT(prop && prop->isDataDescriptor()); + MOZ_ASSERT(prop && prop.isNativeProperty() && prop.shape()->isDataDescriptor()); } #endif // DEBUG if (!GetProperty(cx, obj, obj, id, &outputValue)) diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp index 376bbcdda7..6f91dfb106 100644 --- a/js/src/proxy/Proxy.cpp +++ b/js/src/proxy/Proxy.cpp @@ -530,18 +530,18 @@ Proxy::trace(JSTracer* trc, JSObject* proxy) bool js::proxy_LookupProperty(JSContext* cx, HandleObject obj, HandleId id, - MutableHandleObject objp, MutableHandleShape propp) + MutableHandleObject objp, MutableHandle<JS::PropertyResult> propp) { bool found; if (!Proxy::has(cx, obj, id, &found)) return false; if (found) { - MarkNonNativePropertyFound<CanGC>(propp); + propp.setNonNativeProperty(); objp.set(obj); } else { + propp.setNotFound(); objp.set(nullptr); - propp.set(nullptr); } return true; } diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 1c875c606f..0c021ff0e9 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -10098,12 +10098,14 @@ DebuggerObject::forceLexicalInitializationByName(JSContext* cx, HandleDebuggerOb RootedObject globalLexical(cx, &referent->lexicalEnvironment()); RootedObject pobj(cx); - RootedShape shape(cx); - if (!LookupProperty(cx, globalLexical, id, &pobj, &shape)) + Rooted<PropertyResult> prop(cx); + if (!LookupProperty(cx, globalLexical, id, &pobj, &prop)) return false; result = false; - if (shape) { + if (prop) { + MOZ_ASSERT(prop.isNativeProperty()); + Shape* shape = prop.shape(); Value v = globalLexical->as<NativeObject>().getSlot(shape->slot()); if (shape->hasSlot() && v.isMagic() && v.whyMagic() == JS_UNINITIALIZED_LEXICAL) { globalLexical->as<NativeObject>().setSlot(shape->slot(), UndefinedValue()); diff --git a/js/src/vm/EnvironmentObject.cpp b/js/src/vm/EnvironmentObject.cpp index bffa32f6bf..4e74b95ab2 100644 --- a/js/src/vm/EnvironmentObject.cpp +++ b/js/src/vm/EnvironmentObject.cpp @@ -518,14 +518,14 @@ ModuleEnvironmentObject::fixEnclosingEnvironmentAfterCompartmentMerge(GlobalObje /* static */ bool ModuleEnvironmentObject::lookupProperty(JSContext* cx, HandleObject obj, HandleId id, - MutableHandleObject objp, MutableHandleShape propp) + MutableHandleObject objp, MutableHandle<PropertyResult> propp) { const IndirectBindingMap& bindings = obj->as<ModuleEnvironmentObject>().importBindings(); Shape* shape; ModuleEnvironmentObject* env; if (bindings.lookup(id, &env, &shape)) { objp.set(env); - propp.set(shape); + propp.setNativeProperty(shape); return true; } @@ -688,13 +688,13 @@ CheckUnscopables(JSContext *cx, HandleObject obj, HandleId id, bool *scopable) static bool with_LookupProperty(JSContext* cx, HandleObject obj, HandleId id, - MutableHandleObject objp, MutableHandleShape propp) + MutableHandleObject objp, MutableHandle<PropertyResult> propp) { // SpiderMonkey-specific: consider internal '.generator' and '.this' names // to be unscopable. if (IsUnscopableDotName(cx, id)) { objp.set(nullptr); - propp.set(nullptr); + propp.setNotFound(); return true; } @@ -708,7 +708,7 @@ with_LookupProperty(JSContext* cx, HandleObject obj, HandleId id, return false; if (!scopable) { objp.set(nullptr); - propp.set(nullptr); + propp.setNotFound(); } } return true; @@ -1104,7 +1104,7 @@ ReportRuntimeLexicalErrorId(JSContext* cx, unsigned errorNumber, HandleId id) static bool lexicalError_LookupProperty(JSContext* cx, HandleObject obj, HandleId id, - MutableHandleObject objp, MutableHandleShape propp) + MutableHandleObject objp, MutableHandle<PropertyResult> propp) { ReportRuntimeLexicalErrorId(cx, obj->as<RuntimeLexicalErrorObject>().errorNumber(), id); return false; diff --git a/js/src/vm/EnvironmentObject.h b/js/src/vm/EnvironmentObject.h index 0277e7c65c..752eb5c65c 100644 --- a/js/src/vm/EnvironmentObject.h +++ b/js/src/vm/EnvironmentObject.h @@ -407,7 +407,7 @@ class ModuleEnvironmentObject : public EnvironmentObject private: static bool lookupProperty(JSContext* cx, HandleObject obj, HandleId id, - MutableHandleObject objp, MutableHandleShape propp); + MutableHandleObject objp, MutableHandle<PropertyResult> propp); static bool hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp); static bool getProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id, MutableHandleValue vp); diff --git a/js/src/vm/GeneratorObject.cpp b/js/src/vm/GeneratorObject.cpp index 018e5a4819..9265a1b628 100644 --- a/js/src/vm/GeneratorObject.cpp +++ b/js/src/vm/GeneratorObject.cpp @@ -363,12 +363,14 @@ js::CheckStarGeneratorResumptionValue(JSContext* cx, HandleValue v) // It should have `value` data property, but the type doesn't matter JSObject* ignored; - Shape* shape; - if (!LookupPropertyPure(cx, obj, NameToId(cx->names().value), &ignored, &shape)) + PropertyResult prop; + if (!LookupPropertyPure(cx, obj, NameToId(cx->names().value), &ignored, &prop)) return false; - if (!shape) + if (!prop) return false; - if (!shape->hasDefaultGetter()) + if (!prop.isNativeProperty()) + return false; + if (!prop.shape()->hasDefaultGetter()) return false; return true; diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h index 2e94a2ab22..5c2320d3fb 100644 --- a/js/src/vm/Interpreter-inl.h +++ b/js/src/vm/Interpreter-inl.h @@ -78,17 +78,18 @@ IsUninitializedLexical(const Value& val) } static inline bool -IsUninitializedLexicalSlot(HandleObject obj, HandleShape shape) +IsUninitializedLexicalSlot(HandleObject obj, Handle<PropertyResult> prop) { - MOZ_ASSERT(shape); + MOZ_ASSERT(prop); if (obj->is<WithEnvironmentObject>()) return false; - // We check for IsImplicitDenseOrTypedArrayElement even though the shape - // is always a non-indexed property because proxy hooks may return a - // "non-native property found" shape, which happens to be encoded in the - // same way as the "dense element" shape. See MarkNonNativePropertyFound. - if (IsImplicitDenseOrTypedArrayElement(shape) || - !shape->hasSlot() || + + // Proxy hooks may return a non-native property. + if (prop.isNonNativeProperty()) + return false; + + Shape* shape = prop.shape(); + if (!shape->hasSlot() || !shape->hasDefaultGetter() || !shape->hasDefaultSetter()) { @@ -174,9 +175,9 @@ GetLengthProperty(const Value& lval, MutableHandleValue vp) template <bool TypeOf> inline bool FetchName(JSContext* cx, HandleObject obj, HandleObject obj2, HandlePropertyName name, - HandleShape shape, MutableHandleValue vp) + Handle<PropertyResult> prop, MutableHandleValue vp) { - if (!shape) { + if (!prop) { if (TypeOf) { vp.setUndefined(); return true; @@ -190,6 +191,7 @@ FetchName(JSContext* cx, HandleObject obj, HandleObject obj2, HandlePropertyName if (!GetProperty(cx, obj, obj, id, vp)) return false; } else { + RootedShape shape(cx, prop.shape()); RootedObject normalized(cx, obj); if (normalized->is<WithEnvironmentObject>() && !shape->hasDefaultGetter()) normalized = &normalized->as<WithEnvironmentObject>().object(); @@ -213,9 +215,13 @@ FetchName(JSContext* cx, HandleObject obj, HandleObject obj2, HandlePropertyName } inline bool -FetchNameNoGC(JSObject* pobj, Shape* shape, MutableHandleValue vp) +FetchNameNoGC(JSObject* pobj, PropertyResult prop, MutableHandleValue vp) { - if (!shape || !pobj->isNative() || !shape->isDataDescriptor() || !shape->hasDefaultGetter()) + if (!prop || !pobj->isNative()) + return false; + + Shape* shape = prop.shape(); + if (!shape->isDataDescriptor() || !shape->hasDefaultGetter()) return false; vp.set(pobj->as<NativeObject>().getSlot(shape->slot())); @@ -361,7 +367,7 @@ DefVarOperation(JSContext* cx, HandleObject varobj, HandlePropertyName dn, unsig } #endif - RootedShape prop(cx); + Rooted<PropertyResult> prop(cx); RootedObject obj2(cx); if (!LookupProperty(cx, varobj, dn, &obj2, &prop)) return false; diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 7e3f2a7f1b..cf58e2d608 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -210,27 +210,27 @@ GetNameOperation(JSContext* cx, InterpreterFrame* fp, jsbytecode* pc, MutableHan if (IsGlobalOp(JSOp(*pc)) && !fp->script()->hasNonSyntacticScope()) obj = &obj->global().lexicalEnvironment(); - Shape* shape = nullptr; + PropertyResult prop; JSObject* env = nullptr; JSObject* pobj = nullptr; - if (LookupNameNoGC(cx, name, obj, &env, &pobj, &shape)) { - if (FetchNameNoGC(pobj, shape, vp)) + if (LookupNameNoGC(cx, name, obj, &env, &pobj, &prop)) { + if (FetchNameNoGC(pobj, prop, vp)) return true; } RootedObject objRoot(cx, obj), envRoot(cx), pobjRoot(cx); RootedPropertyName nameRoot(cx, name); - RootedShape shapeRoot(cx); + Rooted<PropertyResult> propRoot(cx); - if (!LookupName(cx, nameRoot, objRoot, &envRoot, &pobjRoot, &shapeRoot)) + if (!LookupName(cx, nameRoot, objRoot, &envRoot, &pobjRoot, &propRoot)) return false; /* Kludge to allow (typeof foo == "undefined") tests. */ JSOp op2 = JSOp(pc[JSOP_GETNAME_LENGTH]); if (op2 == JSOP_TYPEOF) - return FetchName<true>(cx, envRoot, pobjRoot, nameRoot, shapeRoot, vp); + return FetchName<true>(cx, envRoot, pobjRoot, nameRoot, propRoot, vp); - return FetchName<false>(cx, envRoot, pobjRoot, nameRoot, shapeRoot, vp); + return FetchName<false>(cx, envRoot, pobjRoot, nameRoot, propRoot, vp); } static inline bool @@ -238,12 +238,12 @@ GetImportOperation(JSContext* cx, InterpreterFrame* fp, jsbytecode* pc, MutableH { RootedObject obj(cx, fp->environmentChain()), env(cx), pobj(cx); RootedPropertyName name(cx, fp->script()->getName(pc)); - RootedShape shape(cx); + Rooted<PropertyResult> prop(cx); - MOZ_ALWAYS_TRUE(LookupName(cx, name, obj, &env, &pobj, &shape)); + MOZ_ALWAYS_TRUE(LookupName(cx, name, obj, &env, &pobj, &prop)); MOZ_ASSERT(env && env->is<ModuleEnvironmentObject>()); MOZ_ASSERT(env->as<ModuleEnvironmentObject>().hasImportBinding(name)); - return FetchName<false>(cx, env, pobj, name, shape, vp); + return FetchName<false>(cx, env, pobj, name, prop, vp); } static bool @@ -4388,12 +4388,12 @@ bool js::GetEnvironmentName(JSContext* cx, HandleObject envChain, HandlePropertyName name, MutableHandleValue vp) { - RootedShape shape(cx); + Rooted<PropertyResult> prop(cx); RootedObject obj(cx), pobj(cx); - if (!LookupName(cx, name, envChain, &obj, &pobj, &shape)) + if (!LookupName(cx, name, envChain, &obj, &pobj, &prop)) return false; - if (!shape) + if (!prop) return ReportIsNotDefined(cx, name); if (!GetProperty(cx, obj, obj, name, vp)) @@ -4415,12 +4415,12 @@ bool js::GetEnvironmentNameForTypeOf(JSContext* cx, HandleObject envChain, HandlePropertyName name, MutableHandleValue vp) { - RootedShape shape(cx); + Rooted<PropertyResult> prop(cx); RootedObject obj(cx), pobj(cx); - if (!LookupName(cx, name, envChain, &obj, &pobj, &shape)) + if (!LookupName(cx, name, envChain, &obj, &pobj, &prop)) return false; - if (!shape) { + if (!prop) { vp.set(UndefinedValue()); return true; } @@ -4478,9 +4478,9 @@ js::DefFunOperation(JSContext* cx, HandleScript script, HandleObject envChain, /* ES5 10.5 (NB: with subsequent errata). */ RootedPropertyName name(cx, fun->explicitName()->asPropertyName()); - RootedShape shape(cx); + Rooted<PropertyResult> prop(cx); RootedObject pobj(cx); - if (!LookupProperty(cx, parent, name, &pobj, &shape)) + if (!LookupProperty(cx, parent, name, &pobj, &prop)) return false; RootedValue rval(cx, ObjectValue(*fun)); @@ -4494,7 +4494,7 @@ js::DefFunOperation(JSContext* cx, HandleScript script, HandleObject envChain, : JSPROP_ENUMERATE | JSPROP_PERMANENT; /* Steps 5d, 5f. */ - if (!shape || pobj != parent) { + if (!prop || pobj != parent) { if (!DefineProperty(cx, parent, name, rval, nullptr, nullptr, attrs)) return false; @@ -4512,6 +4512,7 @@ js::DefFunOperation(JSContext* cx, HandleScript script, HandleObject envChain, */ MOZ_ASSERT(parent->isNative() || parent->is<DebugEnvironmentProxy>()); if (parent->is<GlobalObject>()) { + Shape* shape = prop.shape(); if (shape->configurable()) { if (!DefineProperty(cx, parent, name, rval, nullptr, nullptr, attrs)) return false; @@ -4716,8 +4717,8 @@ js::DeleteNameOperation(JSContext* cx, HandlePropertyName name, HandleObject sco MutableHandleValue res) { RootedObject scope(cx), pobj(cx); - RootedShape shape(cx); - if (!LookupName(cx, name, scopeObj, &scope, &pobj, &shape)) + Rooted<PropertyResult> prop(cx); + if (!LookupName(cx, name, scopeObj, &scope, &pobj, &prop)) return false; if (!scope) { diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h index 2bb70b7d90..67dff24b7b 100644 --- a/js/src/vm/NativeObject-inl.h +++ b/js/src/vm/NativeObject-inl.h @@ -382,8 +382,8 @@ NewNativeObjectWithClassProto(ExclusiveContext* cx, const Class* clasp, HandleOb * *recursedp = false and return true. */ static MOZ_ALWAYS_INLINE bool -CallResolveOp(JSContext* cx, HandleNativeObject obj, HandleId id, MutableHandleShape propp, - bool* recursedp) +CallResolveOp(JSContext* cx, HandleNativeObject obj, HandleId id, + MutableHandle<PropertyResult> propp, bool* recursedp) { // Avoid recursion on (obj, id) already being resolved on cx. AutoResolving resolving(cx, obj, id); @@ -407,13 +407,18 @@ CallResolveOp(JSContext* cx, HandleNativeObject obj, HandleId id, MutableHandleS obj->getClass()->getMayResolve()(cx->names(), id, obj)); if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) { - MarkDenseOrTypedArrayElementFound<CanGC>(propp); + propp.setDenseOrTypedArrayElement(); return true; } MOZ_ASSERT(!obj->is<TypedArrayObject>()); - propp.set(obj->lookup(cx, id)); + RootedShape shape(cx, obj->lookup(cx, id)); + if (shape) + propp.setNativeProperty(shape); + else + propp.setNotFound(); + return true; } @@ -444,12 +449,12 @@ static MOZ_ALWAYS_INLINE bool LookupOwnPropertyInline(ExclusiveContext* cx, typename MaybeRooted<NativeObject*, allowGC>::HandleType obj, typename MaybeRooted<jsid, allowGC>::HandleType id, - typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp, + typename MaybeRooted<PropertyResult, allowGC>::MutableHandleType propp, bool* donep) { // Check for a native dense element. if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) { - MarkDenseOrTypedArrayElementFound<allowGC>(propp); + propp.setDenseOrTypedArrayElement(); *donep = true; return true; } @@ -460,11 +465,10 @@ LookupOwnPropertyInline(ExclusiveContext* cx, if (obj->template is<TypedArrayObject>()) { uint64_t index; if (IsTypedArrayIndex(id, &index)) { - if (index < obj->template as<TypedArrayObject>().length()) { - MarkDenseOrTypedArrayElementFound<allowGC>(propp); - } else { - propp.set(nullptr); - } + if (index < obj->template as<TypedArrayObject>().length()) + propp.setDenseOrTypedArrayElement(); + else + propp.setNotFound(); *donep = true; return true; } @@ -472,7 +476,7 @@ LookupOwnPropertyInline(ExclusiveContext* cx, // Check for a native property. if (Shape* shape = obj->lookup(cx, id)) { - propp.set(shape); + propp.setNativeProperty(shape); *donep = true; return true; } @@ -486,14 +490,14 @@ LookupOwnPropertyInline(ExclusiveContext* cx, if (!CallResolveOp(cx->asJSContext(), MaybeRooted<NativeObject*, allowGC>::toHandle(obj), MaybeRooted<jsid, allowGC>::toHandle(id), - MaybeRooted<Shape*, allowGC>::toMutableHandle(propp), + MaybeRooted<PropertyResult, allowGC>::toMutableHandle(propp), &recursed)) { return false; } if (recursed) { - propp.set(nullptr); + propp.setNotFound(); *donep = true; return true; } @@ -504,7 +508,7 @@ LookupOwnPropertyInline(ExclusiveContext* cx, } } - propp.set(nullptr); + propp.setNotFound(); *donep = false; return true; } @@ -515,11 +519,11 @@ LookupOwnPropertyInline(ExclusiveContext* cx, */ static inline void NativeLookupOwnPropertyNoResolve(ExclusiveContext* cx, HandleNativeObject obj, HandleId id, - MutableHandleShape result) + MutableHandle<PropertyResult> result) { // Check for a native dense element. if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) { - MarkDenseOrTypedArrayElementFound<CanGC>(result); + result.setDenseOrTypedArrayElement(); return; } @@ -528,15 +532,18 @@ NativeLookupOwnPropertyNoResolve(ExclusiveContext* cx, HandleNativeObject obj, H uint64_t index; if (IsTypedArrayIndex(id, &index)) { if (index < obj->as<TypedArrayObject>().length()) - MarkDenseOrTypedArrayElementFound<CanGC>(result); + result.setDenseOrTypedArrayElement(); else - result.set(nullptr); + result.setNotFound(); return; } } // Check for a native property. - result.set(obj->lookup(cx, id)); + if (Shape* shape = obj->lookup(cx, id)) + result.setNativeProperty(shape); + else + result.setNotFound(); } template <AllowGC allowGC> @@ -545,7 +552,7 @@ LookupPropertyInline(ExclusiveContext* cx, typename MaybeRooted<NativeObject*, allowGC>::HandleType obj, typename MaybeRooted<jsid, allowGC>::HandleType id, typename MaybeRooted<JSObject*, allowGC>::MutableHandleType objp, - typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp) + typename MaybeRooted<PropertyResult, allowGC>::MutableHandleType propp) { /* NB: The logic of this procedure is implicitly reflected in * BaselineIC.cpp's |EffectlesslyLookupProperty| logic. @@ -578,14 +585,14 @@ LookupPropertyInline(ExclusiveContext* cx, MaybeRooted<JSObject*, allowGC>::toHandle(proto), MaybeRooted<jsid, allowGC>::toHandle(id), MaybeRooted<JSObject*, allowGC>::toMutableHandle(objp), - MaybeRooted<Shape*, allowGC>::toMutableHandle(propp)); + MaybeRooted<PropertyResult, allowGC>::toMutableHandle(propp)); } current = &proto->template as<NativeObject>(); } objp.set(nullptr); - propp.set(nullptr); + propp.setNotFound(); return true; } diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index 3625d86f54..53f7c0bfac 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -1044,7 +1044,7 @@ bool js::NativeLookupOwnProperty(ExclusiveContext* cx, typename MaybeRooted<NativeObject*, allowGC>::HandleType obj, typename MaybeRooted<jsid, allowGC>::HandleType id, - typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp) + typename MaybeRooted<PropertyResult, allowGC>::MutableHandleType propp) { bool done; return LookupOwnPropertyInline<allowGC>(cx, obj, id, propp, &done); @@ -1052,11 +1052,11 @@ js::NativeLookupOwnProperty(ExclusiveContext* cx, template bool js::NativeLookupOwnProperty<CanGC>(ExclusiveContext* cx, HandleNativeObject obj, HandleId id, - MutableHandleShape propp); + MutableHandle<PropertyResult> propp); template bool js::NativeLookupOwnProperty<NoGC>(ExclusiveContext* cx, NativeObject* const& obj, const jsid& id, - FakeMutableHandle<Shape*> propp); + FakeMutableHandle<PropertyResult> propp); /*** [[DefineOwnProperty]] ***********************************************************************/ @@ -1279,19 +1279,20 @@ GetExistingProperty(JSContext* cx, static bool GetExistingPropertyValue(ExclusiveContext* cx, HandleNativeObject obj, HandleId id, - HandleShape shape, MutableHandleValue vp) + Handle<PropertyResult> prop, MutableHandleValue vp) { - if (IsImplicitDenseOrTypedArrayElement(shape)) { + if (prop.isDenseOrTypedArrayElement()) { vp.set(obj->getDenseOrTypedArrayElement(JSID_TO_INT(id))); return true; } if (!cx->shouldBeJSContext()) return false; - MOZ_ASSERT(shape->propid() == id); - MOZ_ASSERT(obj->contains(cx, shape)); + MOZ_ASSERT(prop.shape()->propid() == id); + MOZ_ASSERT(obj->contains(cx, prop.shape())); RootedValue receiver(cx, ObjectValue(*obj)); + RootedShape shape(cx, prop.shape()); return GetExistingProperty<CanGC>(cx->asJSContext(), receiver, obj, shape, vp); } @@ -1302,7 +1303,7 @@ GetExistingPropertyValue(ExclusiveContext* cx, HandleNativeObject obj, HandleId */ static bool DefinePropertyIsRedundant(ExclusiveContext* cx, HandleNativeObject obj, HandleId id, - HandleShape shape, unsigned shapeAttrs, + Handle<PropertyResult> prop, unsigned shapeAttrs, Handle<PropertyDescriptor> desc, bool *redundant) { *redundant = false; @@ -1319,16 +1320,16 @@ DefinePropertyIsRedundant(ExclusiveContext* cx, HandleNativeObject obj, HandleId if (desc.hasValue()) { // Get the current value of the existing property. RootedValue currentValue(cx); - if (!IsImplicitDenseOrTypedArrayElement(shape) && - shape->hasSlot() && - shape->hasDefaultGetter()) + if (!prop.isDenseOrTypedArrayElement() && + prop.shape()->hasSlot() && + prop.shape()->hasDefaultGetter()) { // Inline GetExistingPropertyValue in order to omit a type // correctness assertion that's too strict for this particular // call site. For details, see bug 1125624 comments 13-16. - currentValue.set(obj->getSlot(shape->slot())); + currentValue.set(obj->getSlot(prop.shape()->slot())); } else { - if (!GetExistingPropertyValue(cx, obj, id, shape, ¤tValue)) + if (!GetExistingPropertyValue(cx, obj, id, prop, ¤tValue)) return false; } @@ -1339,22 +1340,24 @@ DefinePropertyIsRedundant(ExclusiveContext* cx, HandleNativeObject obj, HandleId } GetterOp existingGetterOp = - IsImplicitDenseOrTypedArrayElement(shape) ? nullptr : shape->getter(); + prop.isDenseOrTypedArrayElement() ? nullptr : prop.shape()->getter(); if (desc.getter() != existingGetterOp) return true; SetterOp existingSetterOp = - IsImplicitDenseOrTypedArrayElement(shape) ? nullptr : shape->setter(); + prop.isDenseOrTypedArrayElement() ? nullptr : prop.shape()->setter(); if (desc.setter() != existingSetterOp) return true; } else { - if (desc.hasGetterObject()) { - if (!(shapeAttrs & JSPROP_GETTER) || desc.getterObject() != shape->getterObject()) - return true; + if (desc.hasGetterObject() && + (!(shapeAttrs & JSPROP_GETTER) || desc.getterObject() != prop.shape()->getterObject())) + { + return true; } - if (desc.hasSetterObject()) { - if (!(shapeAttrs & JSPROP_SETTER) || desc.setterObject() != shape->setterObject()) - return true; + if (desc.hasSetterObject() && + (!(shapeAttrs & JSPROP_SETTER) || desc.setterObject() != prop.shape()->setterObject())) + { + return true; } } @@ -1421,14 +1424,14 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId } // 9.1.6.1 OrdinaryDefineOwnProperty steps 1-2. - RootedShape shape(cx); + Rooted<PropertyResult> prop(cx); if (desc_.attributes() & JSPROP_RESOLVING) { // We are being called from a resolve or enumerate hook to reify a // lazily-resolved property. To avoid reentering the resolve hook and // recursing forever, skip the resolve hook when doing this lookup. - NativeLookupOwnPropertyNoResolve(cx, obj, id, &shape); + NativeLookupOwnPropertyNoResolve(cx, obj, id, &prop); } else { - if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &shape)) + if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &prop)) return false; } @@ -1443,7 +1446,7 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId Rooted<PropertyDescriptor> desc(cx, desc_); // Step 2. - if (!shape) { + if (!prop) { if (!obj->nonProxyIsExtensible()) return result.fail(JSMSG_CANT_DEFINE_PROP_OBJECT_NOT_EXTENSIBLE); @@ -1455,21 +1458,20 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId return result.succeed(); } - MOZ_ASSERT(shape); - // Steps 3-4. (Step 3 is a special case of step 4.) We use shapeAttrs as a // stand-in for shape in many places below, since shape might not be a // pointer to a real Shape (see IsImplicitDenseOrTypedArrayElement). - unsigned shapeAttrs = GetShapeAttributes(obj, shape); + unsigned shapeAttrs = GetPropertyAttributes(obj, prop); bool redundant; - if (!DefinePropertyIsRedundant(cx, obj, id, shape, shapeAttrs, desc, &redundant)) + if (!DefinePropertyIsRedundant(cx, obj, id, prop, shapeAttrs, desc, &redundant)) return false; if (redundant) { // In cases involving JSOP_NEWOBJECT and JSOP_INITPROP, obj can have a // type for this property that doesn't match the value in the slot. // Update the type here, even though this DefineProperty call is // otherwise a no-op. (See bug 1125624 comment 13.) - if (!IsImplicitDenseOrTypedArrayElement(shape) && desc.hasValue()) { + if (!prop.isDenseOrTypedArrayElement() && desc.hasValue()) { + RootedShape shape(cx, prop.shape()); if (!UpdateShapeTypeAndValue(cx, obj, shape, desc.value())) return false; } @@ -1512,24 +1514,24 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId MOZ_ASSERT(!desc.hasSetterObject()); if (IsDataDescriptor(shapeAttrs)) { RootedValue currentValue(cx); - if (!GetExistingPropertyValue(cx, obj, id, shape, ¤tValue)) + if (!GetExistingPropertyValue(cx, obj, id, prop, ¤tValue)) return false; desc.setValue(currentValue); desc.setWritable(IsWritable(shapeAttrs)); } else { - desc.setGetterObject(shape->getterObject()); - desc.setSetterObject(shape->setterObject()); + desc.setGetterObject(prop.shape()->getterObject()); + desc.setSetterObject(prop.shape()->setterObject()); } } else if (desc.isDataDescriptor() != IsDataDescriptor(shapeAttrs)) { // Step 7. if (!IsConfigurable(shapeAttrs) && !skipRedefineChecks) return result.fail(JSMSG_CANT_REDEFINE_PROP); - if (IsImplicitDenseOrTypedArrayElement(shape)) { + if (prop.isDenseOrTypedArrayElement()) { MOZ_ASSERT(!obj->is<TypedArrayObject>()); if (!NativeObject::sparsifyDenseElement(cx, obj, JSID_TO_INT(id))) return false; - shape = obj->lookup(cx, id); + prop.setNativeProperty(obj->lookup(cx, id)); } // Fill in desc fields with default values (steps 7.b.i and 7.c.i). @@ -1541,15 +1543,15 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId return result.fail(JSMSG_CANT_REDEFINE_PROP); if (frozen || !desc.hasValue()) { - if (IsImplicitDenseOrTypedArrayElement(shape)) { + if (prop.isDenseOrTypedArrayElement()) { MOZ_ASSERT(!obj->is<TypedArrayObject>()); if (!NativeObject::sparsifyDenseElement(cx, obj, JSID_TO_INT(id))) return false; - shape = obj->lookup(cx, id); + prop.setNativeProperty(obj->lookup(cx, id)); } RootedValue currentValue(cx); - if (!GetExistingPropertyValue(cx, obj, id, shape, ¤tValue)) + if (!GetExistingPropertyValue(cx, obj, id, prop, ¤tValue)) return false; if (!desc.hasValue()) { @@ -1571,32 +1573,32 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId desc.setWritable(IsWritable(shapeAttrs)); } else { // Step 9. - MOZ_ASSERT(shape->isAccessorDescriptor()); + MOZ_ASSERT(prop.shape()->isAccessorDescriptor()); MOZ_ASSERT(desc.isAccessorDescriptor()); // The spec says to use SameValue, but since the values in // question are objects, we can just compare pointers. if (desc.hasSetterObject()) { if (!IsConfigurable(shapeAttrs) && - desc.setterObject() != shape->setterObject() && + desc.setterObject() != prop.shape()->setterObject() && !skipRedefineChecks) { return result.fail(JSMSG_CANT_REDEFINE_PROP); } } else { // Fill in desc.[[Set]] from shape. - desc.setSetterObject(shape->setterObject()); + desc.setSetterObject(prop.shape()->setterObject()); } if (desc.hasGetterObject()) { if (!IsConfigurable(shapeAttrs) && - desc.getterObject() != shape->getterObject() && + desc.getterObject() != prop.shape()->getterObject() && !skipRedefineChecks) { return result.fail(JSMSG_CANT_REDEFINE_PROP); } } else { // Fill in desc.[[Get]] from shape. - desc.setGetterObject(shape->getterObject()); + desc.setGetterObject(prop.shape()->getterObject()); } } @@ -1681,18 +1683,18 @@ bool js::NativeHasProperty(JSContext* cx, HandleNativeObject obj, HandleId id, bool* foundp) { RootedNativeObject pobj(cx, obj); - RootedShape shape(cx); + Rooted<PropertyResult> prop(cx); // This loop isn't explicit in the spec algorithm. See the comment on step // 7.a. below. for (;;) { // Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.) bool done; - if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &shape, &done)) + if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &prop, &done)) return false; // Step 4. - if (shape) { + if (prop) { *foundp = true; return true; } @@ -1733,15 +1735,15 @@ bool js::NativeGetOwnPropertyDescriptor(JSContext* cx, HandleNativeObject obj, HandleId id, MutableHandle<PropertyDescriptor> desc) { - RootedShape shape(cx); - if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &shape)) + Rooted<PropertyResult> prop(cx); + if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &prop)) return false; - if (!shape) { + if (!prop) { desc.object().set(nullptr); return true; } - desc.setAttributes(GetShapeAttributes(obj, shape)); + desc.setAttributes(GetPropertyAttributes(obj, prop)); if (desc.isAccessorDescriptor()) { MOZ_ASSERT(desc.isShared()); @@ -1754,13 +1756,13 @@ js::NativeGetOwnPropertyDescriptor(JSContext* cx, HandleNativeObject obj, Handle // than return true with desc incomplete, we fill out the missing // getter or setter with a null, following CompletePropertyDescriptor. if (desc.hasGetterObject()) { - desc.setGetterObject(shape->getterObject()); + desc.setGetterObject(prop.shape()->getterObject()); } else { desc.setGetterObject(nullptr); desc.attributesRef() |= JSPROP_GETTER; } if (desc.hasSetterObject()) { - desc.setSetterObject(shape->setterObject()); + desc.setSetterObject(prop.shape()->setterObject()); } else { desc.setSetterObject(nullptr); desc.attributesRef() |= JSPROP_SETTER; @@ -1776,9 +1778,10 @@ js::NativeGetOwnPropertyDescriptor(JSContext* cx, HandleNativeObject obj, Handle desc.setSetter(nullptr); desc.attributesRef() &= ~JSPROP_SHARED; - if (IsImplicitDenseOrTypedArrayElement(shape)) { + if (prop.isDenseOrTypedArrayElement()) { desc.value().set(obj->getDenseOrTypedArrayElement(JSID_TO_INT(id))); } else { + RootedShape shape(cx, prop.shape()); if (!NativeGetExistingProperty(cx, obj, obj, shape, desc.value())) return false; } @@ -2058,23 +2061,25 @@ NativeGetPropertyInline(JSContext* cx, typename MaybeRooted<Value, allowGC>::MutableHandleType vp) { typename MaybeRooted<NativeObject*, allowGC>::RootType pobj(cx, obj); - typename MaybeRooted<Shape*, allowGC>::RootType shape(cx); + typename MaybeRooted<PropertyResult, allowGC>::RootType prop(cx); // This loop isn't explicit in the spec algorithm. See the comment on step // 4.d below. for (;;) { // Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.) bool done; - if (!LookupOwnPropertyInline<allowGC>(cx, pobj, id, &shape, &done)) + if (!LookupOwnPropertyInline<allowGC>(cx, pobj, id, &prop, &done)) return false; - if (shape) { + if (prop) { // Steps 5-8. Special case for dense elements because // GetExistingProperty doesn't support those. - if (IsImplicitDenseOrTypedArrayElement(shape)) { + if (prop.isDenseOrTypedArrayElement()) { vp.set(pobj->getDenseOrTypedArrayElement(JSID_TO_INT(id))); return true; } + + typename MaybeRooted<Shape*, allowGC>::RootType shape(cx, prop.shape()); return GetExistingProperty<allowGC>(cx, receiver, pobj, shape, vp); } @@ -2366,11 +2371,11 @@ SetDenseOrTypedArrayElement(JSContext* cx, HandleNativeObject obj, uint32_t inde */ static bool SetExistingProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue v, - HandleValue receiver, HandleNativeObject pobj, HandleShape shape, + HandleValue receiver, HandleNativeObject pobj, Handle<PropertyResult> prop, ObjectOpResult& result) { // Step 5 for dense elements. - if (IsImplicitDenseOrTypedArrayElement(shape)) { + if (prop.isDenseOrTypedArrayElement()) { // Step 5.a. if (pobj->getElementsHeader()->isFrozen()) return result.fail(JSMSG_READ_ONLY); @@ -2384,6 +2389,7 @@ SetExistingProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleVa } // Step 5 for all other properties. + RootedShape shape(cx, prop.shape()); if (shape->isDataDescriptor()) { // Step 5.a. if (!shape->writable()) @@ -2441,7 +2447,7 @@ js::NativeSetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, Handle // Step numbers below reference ES6 rev 27 9.1.9, the [[Set]] internal // method for ordinary objects. We substitute our own names for these names // used in the spec: O -> pobj, P -> id, ownDesc -> shape. - RootedShape shape(cx); + Rooted<PropertyResult> prop(cx); RootedNativeObject pobj(cx, obj); // This loop isn't explicit in the spec algorithm. See the comment on step @@ -2450,12 +2456,12 @@ js::NativeSetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, Handle for (;;) { // Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.) bool done; - if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &shape, &done)) + if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &prop, &done)) return false; - if (shape) { + if (prop) { // Steps 5-6. - return SetExistingProperty(cx, obj, id, v, receiver, pobj, shape, result); + return SetExistingProperty(cx, obj, id, v, receiver, pobj, prop, result); } // Steps 4.a-b. The check for 'done' on this next line is tricky. @@ -2513,12 +2519,12 @@ js::NativeDeleteProperty(JSContext* cx, HandleNativeObject obj, HandleId id, ObjectOpResult& result) { // Steps 2-3. - RootedShape shape(cx); - if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &shape)) + Rooted<PropertyResult> prop(cx); + if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &prop)) return false; // Step 4. - if (!shape) { + if (!prop) { // If no property call the class's delProperty hook, passing succeeded // as the result parameter. This always succeeds when there is no hook. return CallJSDeletePropertyOp(cx, obj->getClass()->getDelProperty(), obj, id, result); @@ -2527,7 +2533,7 @@ js::NativeDeleteProperty(JSContext* cx, HandleNativeObject obj, HandleId id, cx->runtime()->gc.poke(); // Step 6. Non-configurable property. - if (GetShapeAttributes(obj, shape) & JSPROP_PERMANENT) + if (GetPropertyAttributes(obj, prop) & JSPROP_PERMANENT) return result.failCantDelete(); if (!CallJSDeletePropertyOp(cx, obj->getClass()->getDelProperty(), obj, id, result)) @@ -2536,7 +2542,7 @@ js::NativeDeleteProperty(JSContext* cx, HandleNativeObject obj, HandleId id, return true; // Step 5. - if (IsImplicitDenseOrTypedArrayElement(shape)) { + if (prop.isDenseOrTypedArrayElement()) { // Typed array elements are non-configurable. MOZ_ASSERT(!obj->is<TypedArrayObject>()); diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index 657fc8d57c..abc84c9fd1 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -1459,7 +1459,7 @@ extern bool NativeLookupOwnProperty(ExclusiveContext* cx, typename MaybeRooted<NativeObject*, allowGC>::HandleType obj, typename MaybeRooted<jsid, allowGC>::HandleType id, - typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp); + typename MaybeRooted<PropertyResult, allowGC>::MutableHandleType propp); /* * Get a property from `receiver`, after having already done a lookup and found diff --git a/js/src/vm/Shape-inl.h b/js/src/vm/Shape-inl.h index 32754740a5..ab16bfb192 100644 --- a/js/src/vm/Shape-inl.h +++ b/js/src/vm/Shape-inl.h @@ -191,17 +191,17 @@ AutoRooterGetterSetter::AutoRooterGetterSetter(ExclusiveContext* cx, uint8_t att } static inline uint8_t -GetShapeAttributes(JSObject* obj, Shape* shape) +GetPropertyAttributes(JSObject* obj, PropertyResult prop) { MOZ_ASSERT(obj->isNative()); - if (IsImplicitDenseOrTypedArrayElement(shape)) { + if (prop.isDenseOrTypedArrayElement()) { if (obj->is<TypedArrayObject>()) return JSPROP_ENUMERATE | JSPROP_PERMANENT; return obj->as<NativeObject>().getElementsHeader()->elementAttributes(); } - return shape->attributes(); + return prop.shape()->attributes(); } } /* namespace js */ diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 7cdf382ed6..c71cef5a7e 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -1771,3 +1771,10 @@ JS::ubi::Concrete<js::BaseShape>::size(mozilla::MallocSizeOf mallocSizeOf) const { return js::gc::Arena::thingSize(get().asTenured().getAllocKind()); } + +void +PropertyResult::trace(JSTracer* trc) +{ + if (isNativeProperty()) + TraceRoot(trc, &shape_, "PropertyResult::shape_"); +} diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h index b292bd58f2..bb813997f0 100644 --- a/js/src/vm/Shape.h +++ b/js/src/vm/Shape.h @@ -1541,38 +1541,6 @@ Shape::matches(const StackShape& other) const other.rawGetter, other.rawSetter); } -// Property lookup hooks on objects are required to return a non-nullptr shape -// to signify that the property has been found. For cases where the property is -// not actually represented by a Shape, use a dummy value. This includes all -// properties of non-native objects, and dense elements for native objects. -// Use separate APIs for these two cases. - -template <AllowGC allowGC> -static inline void -MarkNonNativePropertyFound(typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp) -{ - propp.set(reinterpret_cast<Shape*>(1)); -} - -template <AllowGC allowGC> -static inline void -MarkDenseOrTypedArrayElementFound(typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp) -{ - propp.set(reinterpret_cast<Shape*>(1)); -} - -static inline bool -IsImplicitDenseOrTypedArrayElement(Shape* prop) -{ - return prop == reinterpret_cast<Shape*>(1); -} - -static inline bool -IsImplicitNonNativeProperty(Shape* prop) -{ - return prop == reinterpret_cast<Shape*>(1); -} - Shape* ReshapeForAllocKind(JSContext* cx, Shape* shape, TaggedProto proto, gc::AllocKind allocKind); diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index 4912e65db9..a28f6a95ad 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -720,10 +720,10 @@ UnboxedPlainObject::createWithProperties(ExclusiveContext* cx, HandleObjectGroup /* static */ bool UnboxedPlainObject::obj_lookupProperty(JSContext* cx, HandleObject obj, HandleId id, MutableHandleObject objp, - MutableHandleShape propp) + MutableHandle<PropertyResult> propp) { if (obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id)) { - MarkNonNativePropertyFound<CanGC>(propp); + propp.setNonNativeProperty(); objp.set(obj); return true; } @@ -731,7 +731,7 @@ UnboxedPlainObject::obj_lookupProperty(JSContext* cx, HandleObject obj, RootedObject proto(cx, obj->staticPrototype()); if (!proto) { objp.set(nullptr); - propp.set(nullptr); + propp.setNotFound(); return true; } @@ -1411,10 +1411,10 @@ UnboxedArrayObject::containsProperty(ExclusiveContext* cx, jsid id) /* static */ bool UnboxedArrayObject::obj_lookupProperty(JSContext* cx, HandleObject obj, HandleId id, MutableHandleObject objp, - MutableHandleShape propp) + MutableHandle<PropertyResult> propp) { if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) { - MarkNonNativePropertyFound<CanGC>(propp); + propp.setNonNativeProperty(); objp.set(obj); return true; } @@ -1422,7 +1422,7 @@ UnboxedArrayObject::obj_lookupProperty(JSContext* cx, HandleObject obj, RootedObject proto(cx, obj->staticPrototype()); if (!proto) { objp.set(nullptr); - propp.set(nullptr); + propp.setNotFound(); return true; } diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h index 8622be8a70..6fc482ec71 100644 --- a/js/src/vm/UnboxedObject.h +++ b/js/src/vm/UnboxedObject.h @@ -242,7 +242,7 @@ class UnboxedPlainObject : public JSObject static bool obj_lookupProperty(JSContext* cx, HandleObject obj, HandleId id, MutableHandleObject objp, - MutableHandleShape propp); + MutableHandle<PropertyResult> propp); static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, Handle<PropertyDescriptor> desc, @@ -378,7 +378,7 @@ class UnboxedArrayObject : public JSObject static bool obj_lookupProperty(JSContext* cx, HandleObject obj, HandleId id, MutableHandleObject objp, - MutableHandleShape propp); + MutableHandle<PropertyResult> propp); static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, Handle<PropertyDescriptor> desc, |