--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -1203,38 +1203,37 @@ DoInFallback(JSContext* cx, BaselineFram
FallbackICSpew(cx, stub, "In");
if (!objValue.isObject()) {
ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, objValue, nullptr);
return false;
}
- RootedObject obj(cx, &objValue.toObject());
-
if (stub->state().maybeTransition())
stub->discardStubs(cx);
if (stub->state().canAttachStub()) {
RootedScript script(cx, frame->script());
jsbytecode* pc = stub->icEntry()->pc(script);
ICStubEngine engine = ICStubEngine::Baseline;
- InIRGenerator gen(cx, script, pc, stub->state().mode(), key, obj);
+ HasPropIRGenerator gen(cx, script, pc, CacheKind::In, stub->state().mode(), key, objValue);
bool attached = false;
if (gen.tryAttachStub()) {
ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
engine, script, stub, &attached);
if (newStub)
JitSpew(JitSpew_BaselineIC, " Attached CacheIR stub");
}
if (!attached)
stub->state().trackNotAttached();
}
+ RootedObject obj(cx, &objValue.toObject());
bool cond = false;
if (!OperatorIn(cx, key, obj, &cond))
return false;
res.setBoolean(cond);
return true;
}
@@ -1279,17 +1278,18 @@ DoHasOwnFallback(JSContext* cx, Baseline
if (stub->state().maybeTransition())
stub->discardStubs(cx);
if (stub->state().canAttachStub()) {
RootedScript script(cx, frame->script());
jsbytecode* pc = stub->icEntry()->pc(script);
ICStubEngine engine = ICStubEngine::Baseline;
- HasOwnIRGenerator gen(cx, script, pc, stub->state().mode(), keyValue, objValue);
+ HasPropIRGenerator gen(cx, script, pc, CacheKind::HasOwn,
+ stub->state().mode(), keyValue, objValue);
bool attached = false;
if (gen.tryAttachStub()) {
ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
engine, script, stub, &attached);
if (newStub)
JitSpew(JitSpew_BaselineIC, " Attached CacheIR stub");
}
if (!attached)
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -435,17 +435,17 @@ EmitReadSlotGuard(CacheIRWriter& writer,
ObjOperandId lastObjId = objId;
while (proto) {
ObjOperandId protoId = writer.loadProto(lastObjId);
writer.guardShape(protoId, proto->as<NativeObject>().lastProperty());
proto = proto->staticPrototype();
lastObjId = protoId;
}
}
- } else if (obj->is<UnboxedPlainObject>()) {
+ } else if (obj->is<UnboxedPlainObject>() && expandoId.isSome()) {
holderId->emplace(*expandoId);
} else {
holderId->emplace(objId);
}
}
static void
EmitReadSlotResult(CacheIRWriter& writer, JSObject* obj, JSObject* holder,
@@ -2051,348 +2051,249 @@ BindNameIRGenerator::trackNotAttached()
sp.beginCache(guard, *this);
sp.valueProperty(guard, "base", ObjectValue(*env_));
sp.valueProperty(guard, "property", StringValue(name_));
sp.endCache(guard);
}
#endif
}
-InIRGenerator::InIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
- ICState::Mode mode, HandleValue key, HandleObject obj)
- : IRGenerator(cx, script, pc, CacheKind::In, mode),
- key_(key), obj_(obj)
+HasPropIRGenerator::HasPropIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
+ CacheKind cacheKind, ICState::Mode mode,
+ HandleValue idVal, HandleValue val)
+ : IRGenerator(cx, script, pc, cacheKind, mode),
+ val_(val),
+ idVal_(idVal)
{ }
bool
-InIRGenerator::tryAttachDenseIn(uint32_t index, Int32OperandId indexId,
- HandleObject obj, ObjOperandId objId)
+HasPropIRGenerator::tryAttachDense(HandleObject obj, ObjOperandId objId,
+ uint32_t index, Int32OperandId indexId)
{
if (!obj->isNative())
return false;
if (!obj->as<NativeObject>().containsDenseElement(index))
return false;
+ // Guard shape to ensure object class is NativeObject.
writer.guardShape(objId, obj->as<NativeObject>().lastProperty());
+
writer.loadDenseElementExistsResult(objId, indexId);
writer.returnFromIC();
- trackAttached("DenseIn");
+ trackAttached("DenseHasProp");
return true;
}
bool
-InIRGenerator::tryAttachDenseInHole(uint32_t index, Int32OperandId indexId,
- HandleObject obj, ObjOperandId objId)
+HasPropIRGenerator::tryAttachDenseHole(HandleObject obj, ObjOperandId objId,
+ uint32_t index, Int32OperandId indexId)
{
+ bool hasOwn = (cacheKind_ == CacheKind::HasOwn);
+
if (!obj->isNative())
return false;
-
if (obj->as<NativeObject>().containsDenseElement(index))
return false;
-
- if (!CanAttachDenseElementHole(obj, false))
+ if (!CanAttachDenseElementHole(obj, hasOwn))
return false;
- // Guard on the shape, to prevent non-dense elements from appearing.
+ // Guard shape to ensure class is NativeObject and to prevent non-dense
+ // elements being added. Also ensures prototype doesn't change if dynamic
+ // checks aren't emitted.
writer.guardShape(objId, obj->as<NativeObject>().lastProperty());
- GeneratePrototypeHoleGuards(writer, obj, objId);
+ // Generate prototype guards if needed. This includes monitoring that
+ // properties were not added in the chain.
+ if (!hasOwn)
+ GeneratePrototypeHoleGuards(writer, obj, objId);
+
writer.loadDenseElementHoleExistsResult(objId, indexId);
writer.returnFromIC();
- trackAttached("DenseInHole");
+ trackAttached("DenseHasPropHole");
+ return true;
+}
+
+bool
+HasPropIRGenerator::tryAttachNative(HandleObject obj, ObjOperandId objId,
+ HandleId key, ValOperandId keyId)
+{
+ bool hasOwn = (cacheKind_ == CacheKind::HasOwn);
+
+ JSObject* holder = nullptr;
+ PropertyResult prop;
+
+ if (hasOwn) {
+ if (!LookupOwnPropertyPure(cx_, obj, key, &prop))
+ return false;
+
+ holder = obj;
+ } else {
+ if (!LookupPropertyPure(cx_, obj, key, &holder, &prop))
+ return false;
+ }
+ if (!prop.isFound())
+ return false;
+
+ // Use MegamorphicHasOwnResult if applicable
+ if (hasOwn && mode_ == ICState::Mode::Megamorphic) {
+ writer.megamorphicHasOwnResult(objId, keyId);
+ writer.returnFromIC();
+ trackAttached("MegamorphicHasProp");
+ return true;
+ }
+
+ Maybe<ObjOperandId> tempId;
+ emitIdGuard(keyId, key);
+ EmitReadSlotGuard(writer, obj, holder, objId, &tempId);
+ writer.loadBooleanResult(true);
+ writer.returnFromIC();
+
+ trackAttached("NativeHasProp");
return true;
}
bool
-InIRGenerator::tryAttachNativeIn(HandleId key, ValOperandId keyId,
- HandleObject obj, ObjOperandId objId)
+HasPropIRGenerator::tryAttachNativeDoesNotExist(HandleObject obj, ObjOperandId objId,
+ HandleId key, ValOperandId keyId)
{
- PropertyResult prop;
- JSObject* holder;
- if (!LookupPropertyPure(cx_, obj, key, &holder, &prop))
- return false;
-
- if (!prop.isNativeProperty())
- return false;
-
- Maybe<ObjOperandId> holderId;
+ bool hasOwn = (cacheKind_ == CacheKind::HasOwn);
+
+ if (hasOwn) {
+ if (!CheckHasNoSuchOwnProperty(cx_, obj, key))
+ return false;
+ } else {
+ if (!CheckHasNoSuchProperty(cx_, obj, key))
+ return false;
+ }
+
+ // Use MegamorphicHasOwnResult if applicable
+ if (hasOwn && mode_ == ICState::Mode::Megamorphic) {
+ writer.megamorphicHasOwnResult(objId, keyId);
+ writer.returnFromIC();
+ trackAttached("MegamorphicHasOwn");
+ return true;
+ }
+
+ Maybe<ObjOperandId> tempId;
emitIdGuard(keyId, key);
- EmitReadSlotGuard(writer, obj, holder, objId, &holderId);
- writer.loadBooleanResult(true);
+ if (hasOwn) {
+ TestMatchingReceiver(writer, obj, objId, &tempId);
+ } else {
+ EmitReadSlotGuard(writer, obj, nullptr, objId, &tempId);
+ }
+ writer.loadBooleanResult(false);
writer.returnFromIC();
- trackAttached("NativeIn");
+ trackAttached("NativeDoesNotExist");
return true;
}
bool
-InIRGenerator::tryAttachNativeInDoesNotExist(HandleId key, ValOperandId keyId,
- HandleObject obj, ObjOperandId objId)
+HasPropIRGenerator::tryAttachProxyElement(HandleObject obj, ObjOperandId objId,
+ ValOperandId keyId)
{
- if (!CheckHasNoSuchProperty(cx_, obj, key))
+ MOZ_ASSERT(cacheKind_ == CacheKind::HasOwn);
+
+ if (!obj->is<ProxyObject>())
return false;
- Maybe<ObjOperandId> holderId;
- emitIdGuard(keyId, key);
- EmitReadSlotGuard(writer, obj, nullptr, objId, &holderId);
- writer.loadBooleanResult(false);
+ writer.guardIsProxy(objId);
+ writer.callProxyHasOwnResult(objId, keyId);
writer.returnFromIC();
- trackAttached("NativeInDoesNotExist");
+ trackAttached("ProxyHasProp");
return true;
}
bool
-InIRGenerator::tryAttachStub()
+HasPropIRGenerator::tryAttachStub()
{
- MOZ_ASSERT(cacheKind_ == CacheKind::In);
+ MOZ_ASSERT(cacheKind_ == CacheKind::In ||
+ cacheKind_ == CacheKind::HasOwn);
AutoAssertNoPendingException aanpe(cx_);
+ // NOTE: Argument order is PROPERTY, OBJECT
ValOperandId keyId(writer.setInputOperandId(0));
ValOperandId valId(writer.setInputOperandId(1));
+
+ if (!val_.isObject()) {
+ trackNotAttached();
+ return false;
+ }
+ RootedObject obj(cx_, &val_.toObject());
ObjOperandId objId = writer.guardIsObject(valId);
+ // Optimize DOM Proxies for JSOP_HASOWN
+ if (cacheKind_ == CacheKind::HasOwn) {
+ if (tryAttachProxyElement(obj, objId, keyId))
+ return true;
+ }
+
RootedId id(cx_);
bool nameOrSymbol;
- if (!ValueToNameOrSymbolId(cx_, key_, &id, &nameOrSymbol)) {
+ if (!ValueToNameOrSymbolId(cx_, idVal_, &id, &nameOrSymbol)) {
cx_->clearPendingException();
return false;
}
if (nameOrSymbol) {
- if (tryAttachNativeIn(id, keyId, obj_, objId))
+ if (tryAttachNative(obj, objId, id, keyId))
return true;
- if (tryAttachNativeInDoesNotExist(id, keyId, obj_, objId))
+ if (tryAttachNativeDoesNotExist(obj, objId, id, keyId))
return true;
trackNotAttached();
return false;
}
uint32_t index;
Int32OperandId indexId;
- if (maybeGuardInt32Index(key_, keyId, &index, &indexId)) {
- if (tryAttachDenseIn(index, indexId, obj_, objId))
+ if (maybeGuardInt32Index(idVal_, keyId, &index, &indexId)) {
+ if (tryAttachDense(obj, objId, index, indexId))
return true;
- if (tryAttachDenseInHole(index, indexId, obj_, objId))
+ if (tryAttachDenseHole(obj, objId, index, indexId))
return true;
trackNotAttached();
return false;
}
trackNotAttached();
return false;
}
void
-InIRGenerator::trackAttached(const char* name)
+HasPropIRGenerator::trackAttached(const char* name)
{
#ifdef JS_CACHEIR_SPEW
CacheIRSpewer& sp = CacheIRSpewer::singleton();
if (sp.enabled()) {
LockGuard<Mutex> guard(sp.lock());
sp.beginCache(guard, *this);
- sp.valueProperty(guard, "base", ObjectValue(*obj_));
- sp.valueProperty(guard, "property", key_);
+ sp.valueProperty(guard, "base", val_);
+ sp.valueProperty(guard, "property", idVal_);
sp.attached(guard, name);
sp.endCache(guard);
}
#endif
}
void
-InIRGenerator::trackNotAttached()
-{
-#ifdef JS_CACHEIR_SPEW
- CacheIRSpewer& sp = CacheIRSpewer::singleton();
- if (sp.enabled()) {
- LockGuard<Mutex> guard(sp.lock());
- sp.beginCache(guard, *this);
- sp.valueProperty(guard, "base", ObjectValue(*obj_));
- sp.valueProperty(guard, "property", key_);
- sp.endCache(guard);
- }
-#endif
-}
-
-HasOwnIRGenerator::HasOwnIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
- ICState::Mode mode, HandleValue key, HandleValue value)
- : IRGenerator(cx, script, pc, CacheKind::HasOwn, mode),
- key_(key), val_(value)
-{ }
-
-
-bool
-HasOwnIRGenerator::tryAttachNativeHasOwn(HandleId key, ValOperandId keyId,
- HandleObject obj, ObjOperandId objId)
-{
- PropertyResult prop;
- if (!LookupOwnPropertyPure(cx_, obj, key, &prop))
- return false;
-
- if (!prop.isFound())
- return false;
-
- if (!obj->isNative() && !obj->is<UnboxedPlainObject>())
- return false;
-
- if (mode_ == ICState::Mode::Megamorphic) {
- writer.megamorphicHasOwnResult(objId, keyId);
- writer.returnFromIC();
- trackAttached("MegamorphicHasOwn");
- return true;
- }
-
- Maybe<ObjOperandId> expandoId;
- emitIdGuard(keyId, key);
- TestMatchingReceiver(writer, obj, objId, &expandoId);
- writer.loadBooleanResult(true);
- writer.returnFromIC();
-
- trackAttached("NativeHasOwn");
- return true;
-}
-
-bool
-HasOwnIRGenerator::tryAttachNativeHasOwnDoesNotExist(HandleId key, ValOperandId keyId,
- HandleObject obj, ObjOperandId objId)
-{
- if (!CheckHasNoSuchOwnProperty(cx_, obj, key))
- return false;
-
- if (mode_ == ICState::Mode::Megamorphic) {
- writer.megamorphicHasOwnResult(objId, keyId);
- writer.returnFromIC();
- trackAttached("MegamorphicHasOwn");
- return true;
- }
-
- Maybe<ObjOperandId> expandoId;
- emitIdGuard(keyId, key);
- TestMatchingReceiver(writer, obj, objId, &expandoId);
- writer.loadBooleanResult(false);
- writer.returnFromIC();
-
- trackAttached("NativeHasOwnDoesNotExist");
- return true;
-}
-
-bool
-HasOwnIRGenerator::tryAttachProxyElement(ValOperandId keyId, HandleObject obj, ObjOperandId objId)
-{
- if (!obj->is<ProxyObject>())
- return false;
-
- writer.guardIsProxy(objId);
- writer.callProxyHasOwnResult(objId, keyId);
- writer.returnFromIC();
-
- trackAttached("ProxyHasOwn");
- return true;
-}
-
-bool
-HasOwnIRGenerator::tryAttachDenseHasOwn(uint32_t index, Int32OperandId indexId,
- HandleObject obj, ObjOperandId objId)
-{
- if (!obj->isNative())
- return false;
- if (!obj->as<NativeObject>().containsDenseElement(index))
- return false;
-
- writer.guardShape(objId, obj->as<NativeObject>().lastProperty());
- writer.loadDenseElementExistsResult(objId, indexId);
- writer.returnFromIC();
-
- trackAttached("DenseHasOwn");
- return true;
-}
-
-bool
-HasOwnIRGenerator::tryAttachStub()
-{
- MOZ_ASSERT(cacheKind_ == CacheKind::HasOwn);
-
- AutoAssertNoPendingException aanpe(cx_);
-
- ValOperandId keyId(writer.setInputOperandId(0));
- ValOperandId valId(writer.setInputOperandId(1));
-
- if (!val_.isObject()) {
- trackNotAttached();
- return false;
- }
- RootedObject obj(cx_, &val_.toObject());
-
- ObjOperandId objId = writer.guardIsObject(valId);
-
- if (tryAttachProxyElement(keyId, obj, objId))
- return true;
-
- RootedId id(cx_);
- bool nameOrSymbol;
- if (!ValueToNameOrSymbolId(cx_, key_, &id, &nameOrSymbol)) {
- cx_->clearPendingException();
- return false;
- }
-
- if (nameOrSymbol) {
- if (tryAttachNativeHasOwn(id, keyId, obj, objId))
- return true;
- if (tryAttachNativeHasOwnDoesNotExist(id, keyId, obj, objId))
- return true;
-
- trackNotAttached();
- return false;
- }
-
- uint32_t index;
- Int32OperandId indexId;
- if (maybeGuardInt32Index(key_, keyId, &index, &indexId)) {
- if (tryAttachDenseHasOwn(index, indexId, obj, objId))
- return true;
-
- trackNotAttached();
- return false;
- }
-
- trackNotAttached();
- return false;
-}
-
-void
-HasOwnIRGenerator::trackAttached(const char* name)
+HasPropIRGenerator::trackNotAttached()
{
#ifdef JS_CACHEIR_SPEW
CacheIRSpewer& sp = CacheIRSpewer::singleton();
if (sp.enabled()) {
LockGuard<Mutex> guard(sp.lock());
sp.beginCache(guard, *this);
sp.valueProperty(guard, "base", val_);
- sp.valueProperty(guard, "property", key_);
- sp.attached(guard, name);
- sp.endCache(guard);
- }
-#endif
-}
-
-void
-HasOwnIRGenerator::trackNotAttached()
-{
-#ifdef JS_CACHEIR_SPEW
- CacheIRSpewer& sp = CacheIRSpewer::singleton();
- if (sp.enabled()) {
- LockGuard<Mutex> guard(sp.lock());
- sp.beginCache(guard, *this);
- sp.valueProperty(guard, "base", val_);
- sp.valueProperty(guard, "property", key_);
+ sp.valueProperty(guard, "property", idVal_);
sp.endCache(guard);
}
#endif
}
bool
IRGenerator::maybeGuardInt32Index(const Value& index, ValOperandId indexId,
uint32_t* int32Index, Int32OperandId* int32IndexId)
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -1271,61 +1271,41 @@ class MOZ_RAII SetPropIRGenerator : publ
return &typeCheckInfo_;
}
bool attachedTypedArrayOOBStub() const {
return attachedTypedArrayOOBStub_;
}
};
-// InIRGenerator generates CacheIR for a In IC.
-class MOZ_RAII InIRGenerator : public IRGenerator
+// HasPropIRGenerator generates CacheIR for a HasProp IC. Used for
+// CacheKind::In / CacheKind::HasOwn.
+class MOZ_RAII HasPropIRGenerator : public IRGenerator
{
- HandleValue key_;
- HandleObject obj_;
+ HandleValue val_;
+ HandleValue idVal_;
- bool tryAttachDenseIn(uint32_t index, Int32OperandId indexId,
- HandleObject obj, ObjOperandId objId);
- bool tryAttachDenseInHole(uint32_t index, Int32OperandId indexId,
- HandleObject obj, ObjOperandId objId);
- bool tryAttachNativeIn(HandleId key, ValOperandId keyId,
- HandleObject obj, ObjOperandId objId);
- bool tryAttachNativeInDoesNotExist(HandleId key, ValOperandId keyId,
- HandleObject obj, ObjOperandId objId);
+ bool tryAttachDense(HandleObject obj, ObjOperandId objId,
+ uint32_t index, Int32OperandId indexId);
+ bool tryAttachDenseHole(HandleObject obj, ObjOperandId objId,
+ uint32_t index, Int32OperandId indexId);
+ bool tryAttachNative(HandleObject obj, ObjOperandId objId,
+ HandleId key, ValOperandId keyId);
+ bool tryAttachNativeDoesNotExist(HandleObject obj, ObjOperandId objId,
+ HandleId key, ValOperandId keyId);
+ bool tryAttachProxyElement(HandleObject obj, ObjOperandId objId,
+ ValOperandId keyId);
void trackAttached(const char* name);
void trackNotAttached();
public:
- InIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc, ICState::Mode mode, HandleValue key,
- HandleObject obj);
-
- bool tryAttachStub();
-};
-
-// HasOwnIRGenerator generates CacheIR for a HasOwn IC.
-class MOZ_RAII HasOwnIRGenerator : public IRGenerator
-{
- HandleValue key_;
- HandleValue val_;
-
- bool tryAttachProxyElement(ValOperandId keyId, HandleObject obj, ObjOperandId objId);
- bool tryAttachDenseHasOwn(uint32_t index, Int32OperandId indexId,
- HandleObject obj, ObjOperandId objId);
- bool tryAttachNativeHasOwn(HandleId key, ValOperandId keyId,
- HandleObject obj, ObjOperandId objId);
- bool tryAttachNativeHasOwnDoesNotExist(HandleId key, ValOperandId keyId,
- HandleObject obj, ObjOperandId objId);
-
- void trackAttached(const char* name);
- void trackNotAttached();
-
- public:
- HasOwnIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc, ICState::Mode mode, HandleValue key,
- HandleValue value);
+ // NOTE: Argument order is PROPERTY, OBJECT
+ HasPropIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, CacheKind cacheKind,
+ ICState::Mode mode, HandleValue idVal, HandleValue val);
bool tryAttachStub();
};
class MOZ_RAII TypeOfIRGenerator : public IRGenerator
{
HandleValue val_;