--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -570,17 +570,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>() && expandoId.isSome()) {
+ } else if (obj->is<UnboxedPlainObject>()) {
holderId->emplace(*expandoId);
} else {
holderId->emplace(objId);
}
}
static void
EmitReadSlotResult(CacheIRWriter& writer, JSObject* obj, JSObject* holder,
@@ -2377,88 +2377,193 @@ HasPropIRGenerator::tryAttachDenseHole(H
writer.loadDenseElementHoleExistsResult(objId, indexId);
writer.returnFromIC();
trackAttached("DenseHasPropHole");
return true;
}
bool
-HasPropIRGenerator::tryAttachNative(HandleObject obj, ObjOperandId objId,
- HandleId key, ValOperandId keyId)
+HasPropIRGenerator::tryAttachNamedProp(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())
+ if (!prop)
return false;
- // Use MegamorphicHasOwnResult if applicable
- if (hasOwn && mode_ == ICState::Mode::Megamorphic) {
- writer.megamorphicHasOwnResult(objId, keyId);
- writer.returnFromIC();
- trackAttached("MegamorphicHasProp");
+ if (tryAttachMegamorphic(objId, keyId))
+ return true;
+ if (tryAttachNative(obj, objId, key, keyId, prop, holder))
+ return true;
+ if (tryAttachUnboxed(obj, objId, key, keyId))
+ return true;
+ if (tryAttachTypedObject(obj, objId, key, keyId))
+ return true;
+ if (tryAttachUnboxedExpando(obj, objId, key, keyId))
return true;
- }
+
+ return false;
+}
+
+bool
+HasPropIRGenerator::tryAttachMegamorphic(ObjOperandId objId, ValOperandId keyId)
+{
+ if (mode_ != ICState::Mode::Megamorphic)
+ return false;
+
+ if (cacheKind_ != CacheKind::HasOwn)
+ return false;
+
+ writer.megamorphicHasOwnResult(objId, keyId);
+ writer.returnFromIC();
+ trackAttached("MegamorphicHasProp");
+ return true;
+}
+
+bool
+HasPropIRGenerator::tryAttachNative(JSObject* obj, ObjOperandId objId, jsid key,
+ ValOperandId keyId, PropertyResult prop, JSObject* holder)
+{
+ if (!prop.isNativeProperty())
+ return false;
+
+ if (!IsCacheableProtoChain(obj, holder))
+ return false;
Maybe<ObjOperandId> tempId;
emitIdGuard(keyId, key);
EmitReadSlotGuard(writer, obj, holder, objId, &tempId);
writer.loadBooleanResult(true);
writer.returnFromIC();
trackAttached("NativeHasProp");
return true;
}
bool
-HasPropIRGenerator::tryAttachNativeDoesNotExist(HandleObject obj, ObjOperandId objId,
- HandleId key, ValOperandId keyId)
+HasPropIRGenerator::tryAttachUnboxed(JSObject* obj, ObjOperandId objId,
+ jsid key, ValOperandId keyId)
+{
+ if (!obj->is<UnboxedPlainObject>())
+ return false;
+
+ const UnboxedLayout::Property* prop = obj->as<UnboxedPlainObject>().layout().lookup(key);
+ if (!prop)
+ return false;
+
+ emitIdGuard(keyId, key);
+ writer.guardGroup(objId, obj->group());
+ writer.loadBooleanResult(true);
+ writer.returnFromIC();
+
+ trackAttached("UnboxedHasProp");
+ return true;
+}
+
+bool
+HasPropIRGenerator::tryAttachUnboxedExpando(JSObject* obj, ObjOperandId objId,
+ jsid key, ValOperandId keyId)
+{
+ if (!obj->is<UnboxedPlainObject>())
+ return false;
+
+ UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando();
+ if (!expando)
+ return false;
+
+ Shape* shape = expando->lookup(cx_, key);
+ if (!shape)
+ return false;
+
+ Maybe<ObjOperandId> tempId;
+ emitIdGuard(keyId, key);
+ EmitReadSlotGuard(writer, obj, obj, objId, &tempId);
+ writer.loadBooleanResult(true);
+ writer.returnFromIC();
+
+ trackAttached("UnboxedExpandoHasProp");
+ return true;
+}
+
+bool
+HasPropIRGenerator::tryAttachTypedObject(JSObject* obj, ObjOperandId objId,
+ jsid key, ValOperandId keyId)
+{
+ if (!obj->is<TypedObject>())
+ return false;
+
+ if (!obj->as<TypedObject>().typeDescr().hasProperty(cx_->names(), key))
+ return false;
+
+ emitIdGuard(keyId, key);
+ writer.guardGroup(objId, obj->group());
+ writer.loadBooleanResult(true);
+ writer.returnFromIC();
+
+ trackAttached("TypedObjectHasProp");
+ return true;
+}
+
+bool
+HasPropIRGenerator::tryAttachSlotDoesNotExist(JSObject* obj, ObjOperandId objId,
+ jsid key, ValOperandId keyId)
{
bool hasOwn = (cacheKind_ == CacheKind::HasOwn);
+ emitIdGuard(keyId, key);
+ if (hasOwn) {
+ Maybe<ObjOperandId> tempId;
+ TestMatchingReceiver(writer, obj, objId, &tempId);
+ } else {
+ Maybe<ObjOperandId> tempId;
+ EmitReadSlotGuard(writer, obj, nullptr, objId, &tempId);
+ }
+ writer.loadBooleanResult(false);
+ writer.returnFromIC();
+
+ trackAttached("DoesNotExist");
+ return true;
+}
+
+bool
+HasPropIRGenerator::tryAttachDoesNotExist(HandleObject obj, ObjOperandId objId,
+ HandleId key, ValOperandId keyId)
+{
+ bool hasOwn = (cacheKind_ == CacheKind::HasOwn);
+
+ // Check that property doesn't exist on |obj| or it's prototype chain. These
+ // checks allow Native/Unboxed/Typed objects with a NativeObject prototype
+ // chain. They return false if unknown such as resolve hooks or proxies.
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");
+ if (tryAttachMegamorphic(objId, keyId))
return true;
- }
-
- Maybe<ObjOperandId> tempId;
- emitIdGuard(keyId, key);
- if (hasOwn) {
- TestMatchingReceiver(writer, obj, objId, &tempId);
- } else {
- EmitReadSlotGuard(writer, obj, nullptr, objId, &tempId);
- }
- writer.loadBooleanResult(false);
- writer.returnFromIC();
-
- trackAttached("NativeDoesNotExist");
- return true;
+ if (tryAttachSlotDoesNotExist(obj, objId, key, keyId))
+ return true;
+
+ return false;
}
bool
HasPropIRGenerator::tryAttachProxyElement(HandleObject obj, ObjOperandId objId,
ValOperandId keyId)
{
MOZ_ASSERT(cacheKind_ == CacheKind::HasOwn);
@@ -2501,19 +2606,19 @@ HasPropIRGenerator::tryAttachStub()
RootedId id(cx_);
bool nameOrSymbol;
if (!ValueToNameOrSymbolId(cx_, idVal_, &id, &nameOrSymbol)) {
cx_->clearPendingException();
return false;
}
if (nameOrSymbol) {
- if (tryAttachNative(obj, objId, id, keyId))
+ if (tryAttachNamedProp(obj, objId, id, keyId))
return true;
- if (tryAttachNativeDoesNotExist(obj, objId, id, keyId))
+ if (tryAttachDoesNotExist(obj, objId, id, keyId))
return true;
trackNotAttached();
return false;
}
uint32_t index;
Int32OperandId indexId;
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -1467,20 +1467,32 @@ class MOZ_RAII HasPropIRGenerator : publ
{
HandleValue val_;
HandleValue idVal_;
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 tryAttachNamedProp(HandleObject obj, ObjOperandId objId,
+ HandleId key, ValOperandId keyId);
+ bool tryAttachMegamorphic(ObjOperandId objId, ValOperandId keyId);
+ bool tryAttachNative(JSObject* obj, ObjOperandId objId,
+ jsid key, ValOperandId keyId,
+ PropertyResult prop, JSObject* holder);
+ bool tryAttachUnboxed(JSObject* obj, ObjOperandId objId,
+ jsid key, ValOperandId keyId);
+ bool tryAttachUnboxedExpando(JSObject* obj, ObjOperandId objId,
+ jsid key, ValOperandId keyId);
+ bool tryAttachTypedObject(JSObject* obj, ObjOperandId objId,
+ jsid key, ValOperandId keyId);
+ bool tryAttachSlotDoesNotExist(JSObject* obj, ObjOperandId objId,
+ jsid key, ValOperandId keyId);
+ bool tryAttachDoesNotExist(HandleObject obj, ObjOperandId objId,
+ HandleId key, ValOperandId keyId);
bool tryAttachProxyElement(HandleObject obj, ObjOperandId objId,
ValOperandId keyId);
void trackAttached(const char* name);
void trackNotAttached();
public:
// NOTE: Argument order is PROPERTY, OBJECT