Bug 932875 - Fix logic annotating type object -> function maps in callprop caches, r=jandem a=bajaj.
authorBrian Hackett <bhackett1024@gmail.com>
Wed, 13 Nov 2013 20:06:22 -0700
changeset 167461 b353e78ee8e725d800918e7a1ae9a3db5c291179
parent 167460 6c7eb9d6e528a4bdf0156bc43016820ba41408bb
child 167462 615f1fcd0c01e8c833aeec350a258a5538b7de9f
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem, bajaj
bugs932875
milestone27.0a2
Bug 932875 - Fix logic annotating type object -> function maps in callprop caches, r=jandem a=bajaj.
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -5961,33 +5961,32 @@ IonBuilder::maybeInsertResume()
 
     MNop *ins = MNop::New();
     current->add(ins);
 
     return resumeAfter(ins);
 }
 
 bool
-IonBuilder::testSingletonProperty(JSObject *obj, JSObject *singleton,
-                                  PropertyName *name, bool *isKnownConstant)
+IonBuilder::testSingletonProperty(JSObject *obj, PropertyName *name, JSObject **psingleton)
 {
     // We would like to completely no-op property/global accesses which can
     // produce only a particular JSObject. When indicating the access result is
     // definitely an object, type inference does not account for the
     // possibility that the property is entirely missing from the input object
     // and its prototypes (if this happens, a semantic trigger would be hit and
     // the pushed types updated, even if there is no type barrier).
     //
     // If the access definitely goes through obj, either directly or on the
     // prototype chain, then if obj has a defined property now, and the
     // property has a default or method shape, then the property is not missing
     // and the only way it can become missing in the future is if it is deleted.
     // Deletion causes type properties to be explicitly marked with undefined.
 
-    *isKnownConstant = false;
+    *psingleton = nullptr;
 
     if (!CanEffectlesslyCallLookupGenericOnObject(cx, obj, name))
         return true;
 
     RootedObject objRoot(cx, obj);
     RootedId idRoot(cx, NameToId(name));
     RootedObject holder(cx);
     RootedShape shape(cx);
@@ -6011,25 +6010,23 @@ IonBuilder::testSingletonProperty(JSObje
         if (objType->unknownProperties())
             return true;
 
         types::HeapTypeSetKey property = objType->property(NameToId(name), context());
         if (obj != holder) {
             if (property.notEmpty(constraints()))
                 return true;
         } else {
-            if (property.singleton(constraints()) != singleton)
-                return true;
+            *psingleton = property.singleton(constraints());
             break;
         }
 
         obj = obj->getProto();
     }
 
-    *isKnownConstant = true;
     return true;
 }
 
 bool
 IonBuilder::testSingletonPropertyTypes(MDefinition *obj, JSObject *singleton,
                                        JSObject *globalObj, PropertyName *name,
                                        bool *isKnownConstant, bool *testObject,
                                        bool *testString)
@@ -6046,18 +6043,23 @@ IonBuilder::testSingletonPropertyTypes(M
 
     if (!types && obj->type() != MIRType_String)
         return true;
 
     if (types && types->unknownObject())
         return true;
 
     JSObject *objectSingleton = types ? types->getSingleton() : nullptr;
-    if (objectSingleton)
-        return testSingletonProperty(objectSingleton, singleton, name, isKnownConstant);
+    if (objectSingleton) {
+        JSObject *nsingleton;
+        if (!testSingletonProperty(objectSingleton, name, &nsingleton))
+            return false;
+        *isKnownConstant = (nsingleton == singleton);
+        return true;
+    }
 
     if (!globalObj)
         return true;
 
     JSProtoKey key;
     switch (obj->type()) {
       case MIRType_String:
         key = JSProto_String;
@@ -6094,20 +6096,20 @@ IonBuilder::testSingletonPropertyTypes(M
             if (object->unknownProperties())
                 return true;
             types::HeapTypeSetKey property = object->property(NameToId(name), context());
             if (property.notEmpty(constraints()))
                 return true;
 
             if (JSObject *proto = object->proto().toObjectOrNull()) {
                 // Test this type.
-                bool thoughtConstant = false;
-                if (!testSingletonProperty(proto, singleton, name, &thoughtConstant))
+                JSObject *nsingleton;
+                if (!testSingletonProperty(proto, name, &nsingleton))
                     return false;
-                if (!thoughtConstant)
+                if (nsingleton != singleton)
                     return true;
             } else {
                 // Can't be on the prototype chain with no prototypes...
                 return true;
             }
         }
         // If this is not a known object, a test will be needed.
         *testObject = (obj->type() != MIRType_Object);
@@ -6117,17 +6119,22 @@ IonBuilder::testSingletonPropertyTypes(M
       default:
         return true;
     }
 
     RootedObject proto(cx);
     if (!js_GetClassPrototype(cx, key, &proto, nullptr))
         return false;
 
-    return testSingletonProperty(proto, singleton, name, isKnownConstant);
+    JSObject *nsingleton;
+    if (!testSingletonProperty(proto, name, &nsingleton))
+        return false;
+
+    *isKnownConstant = (nsingleton == singleton);
+    return true;
 }
 
 // Given an observed type set, annotates the IR as much as possible:
 // (1) If no type information is provided, the value on the top of the stack is
 //     left in place.
 // (2) If a single type definitely exists, and no type barrier is needed,
 //     then an infallible unbox instruction replaces the value on the top of
 //     the stack.
@@ -6246,20 +6253,20 @@ IonBuilder::getStaticName(JSObject *stat
     // If the property is permanent, a shape guard isn't necessary.
 
     JSObject *singleton = types->getSingleton();
 
     JSValueType knownType = types->getKnownTypeTag();
     if (!barrier) {
         if (singleton) {
             // Try to inline a known constant value.
-            bool isKnownConstant;
-            if (!testSingletonProperty(staticObject, singleton, name, &isKnownConstant))
+            JSObject *nsingleton;
+            if (!testSingletonProperty(staticObject, name, &nsingleton))
                 return false;
-            if (isKnownConstant)
+            if (singleton == nsingleton)
                 return pushConstant(ObjectValue(*singleton));
         }
         if (knownType == JSVAL_TYPE_UNDEFINED)
             return pushConstant(UndefinedValue());
         if (knownType == JSVAL_TYPE_NULL)
             return pushConstant(NullValue());
     }
 
@@ -7909,42 +7916,22 @@ IonBuilder::annotateGetPropertyCache(JSC
         types::TypeObjectKey *typeObj = types::TypeObjectKey::get(baseTypeObj);
         if (typeObj->unknownProperties() || !typeObj->proto().isObject())
             continue;
 
         types::HeapTypeSetKey ownTypes = typeObj->property(NameToId(name));
         if (ownTypes.notEmpty(constraints()))
             continue;
 
-        JSObject *singleton = nullptr;
-        JSObject *proto = typeObj->proto().toObject();
-        while (true) {
-            types::TypeObjectKey *protoType = types::TypeObjectKey::get(proto);
-            if (!protoType->unknownProperties()) {
-                types::HeapTypeSetKey property = protoType->property(NameToId(name));
-
-                singleton = property.singleton(constraints());
-                if (singleton) {
-                    if (singleton->is<JSFunction>())
-                        break;
-                    singleton = nullptr;
-                }
-            }
-            TaggedProto taggedProto = proto->getTaggedProto();
-            if (!taggedProto.isObject())
-                break;
-            proto = taggedProto.toObject();
-        }
+        JSObject *singleton;
+        if (!testSingletonProperty(typeObj->proto().toObject(), name, &singleton))
+            return false;
         if (!singleton)
             continue;
 
-        bool knownConstant = false;
-        if (!testSingletonProperty(proto, singleton, name, &knownConstant))
-            return false;
-
         // Don't add cases corresponding to non-observed pushes
         if (!pushedTypes->hasType(types::Type::ObjectType(singleton)))
             continue;
 
         if (!inlinePropTable->addEntry(baseTypeObj, &singleton->as<JSFunction>()))
             return false;
     }
 
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -626,18 +626,17 @@ class IonBuilder : public MIRGenerator
                                    bool isGetter, bool *isDOM,
                                    MDefinition **guardOut);
 
     bool annotateGetPropertyCache(JSContext *cx, MDefinition *obj, MGetPropertyCache *getPropCache,
                                   types::TemporaryTypeSet *objTypes, types::TemporaryTypeSet *pushedTypes);
 
     MGetPropertyCache *getInlineableGetPropertyCache(CallInfo &callInfo);
 
-    bool testSingletonProperty(JSObject *obj, JSObject *singleton, PropertyName *name,
-                               bool *isKnownConstant);
+    bool testSingletonProperty(JSObject *obj, PropertyName *name, JSObject **psingleton);
     bool testSingletonPropertyTypes(MDefinition *obj, JSObject *singleton,
                                     JSObject *globalObj, PropertyName *name,
                                     bool *isKnownConstant, bool *testObject,
                                     bool *testString);
     bool getDefiniteSlot(types::TemporaryTypeSet *types, PropertyName *name,
                          types::HeapTypeSetKey *property);
     bool freezePropTypeSets(types::TemporaryTypeSet *types,
                             JSObject *foundProto, PropertyName *name);