Bug 1357759 - Cleanup HasPropIRGenerator unboxed cases draft
authorTed Campbell <tcampbell@mozilla.com>
Tue, 26 Sep 2017 10:12:01 -0400
changeset 670880 116000a837a3526b9b465ab4130da9103402876f
parent 669742 5f3f19824efa14cc6db546baf59c54a0fc15ddc9
child 670881 0a27e0dbe99f8490ae6fc1d25e6ae6467b0c94fb
child 672654 945135f3ffb793c4433808c8ced4b19d452186a0
push id81746
push userbmo:tcampbell@mozilla.com
push dateWed, 27 Sep 2017 01:12:04 +0000
bugs1357759
milestone58.0a1
Bug 1357759 - Cleanup HasPropIRGenerator unboxed cases This cleans up the HasPropIRGenerator to support unboxed, expando unboxed, and typed object cases, as well cleaning up the megamorphic handling. MozReview-Commit-ID: D2uZWrmENiz
js/src/jit/CacheIR.cpp
js/src/jit/CacheIR.h
--- 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