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.
This commit is contained in:
Moonchild 2022-05-24 21:19:51 +00:00 • committed by roytam1
commit 574b295d15
33 changed files with 367 additions and 328 deletions

View file

@ -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;
}