summaryrefslogtreecommitdiff
path: root/js/src/jit/IonCaches.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit/IonCaches.cpp')
-rw-r--r--js/src/jit/IonCaches.cpp93
1 files changed, 54 insertions, 39 deletions
diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp
index 0a0c7ac22..5a7e43728 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;
}