Bug 1357759 - Cleanup HasPropIRGenerator unboxed cases r=jandem
authorTed Campbell <tcampbell@mozilla.com>
Tue, 26 Sep 2017 10:12:01 -0400
changeset 383770 d394ed31deb48572df7ec2b18eaa6e273bf807f7
parent 383769 aa0a7cd0d56a755422f7ca2592ed370b0f347ffb
child 383771 fdab9ee631951ecb5448492177bab7a696e0b102
push id52371
push usertcampbell@mozilla.com
push dateFri, 29 Sep 2017 15:24:43 +0000
treeherderautoland@9db13c9ff60e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1357759
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1357759 - Cleanup HasPropIRGenerator unboxed cases r=jandem 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
@@ -565,17 +565,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,
@@ -2229,88 +2229,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);
 
@@ -2353,19 +2458,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
@@ -1407,20 +1407,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