Bug 1385278 - Move IsCacheable* functions to CacheIR from Ion. r=jandem
authorTom Schuster <evilpies@gmail.com>
Mon, 07 Aug 2017 18:33:19 +0200
changeset 642171 06c9ca99d4618e2d3316218249cc5672dbf70119
parent 642170 19ed20aa5c3e0962b8ed6746660cb6a5a4f14e68
child 642172 c86f1b0cdbdc5d2af59cda42510329632f41c753
child 642204 65507616792c990b1230888612dd7ffc13ed32b4
child 642260 9c41f1c5bcb8e0c855b7862300317f5a3e326322
child 642790 4d98fdc8a90eccd6a5e3f48aebe72c42783997ee
child 643400 3e9783a0e10f9a964e2e6ece1f9ef7052960e537
push id72668
push userbmo:tchiovoloni@mozilla.com
push dateMon, 07 Aug 2017 20:01:43 +0000
reviewersjandem
bugs1385278
milestone57.0a1
Bug 1385278 - Move IsCacheable* functions to CacheIR from Ion. r=jandem
js/src/jit/CacheIR.cpp
js/src/jit/IonCaches.cpp
js/src/jit/IonCaches.h
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -122,16 +122,43 @@ GetProxyStubType(JSContext* cx, HandleOb
             return ProxyStubType::DOMExpando;
         return ProxyStubType::DOMShadowed;
     }
 
     MOZ_ASSERT(shadows == DoesntShadow || shadows == DoesntShadowUnique);
     return ProxyStubType::DOMUnshadowed;
 }
 
+static bool
+ValueToNameOrSymbolId(JSContext* cx, HandleValue idval, MutableHandleId id,
+                      bool* nameOrSymbol)
+{
+    *nameOrSymbol = false;
+
+    if (!idval.isString() && !idval.isSymbol())
+        return true;
+
+    if (!ValueToId<CanGC>(cx, idval, id))
+        return false;
+
+    if (!JSID_IS_STRING(id) && !JSID_IS_SYMBOL(id)) {
+        id.set(JSID_VOID);
+        return true;
+    }
+
+    uint32_t dummy;
+    if (JSID_IS_STRING(id) && JSID_TO_ATOM(id)->isIndex(&dummy)) {
+        id.set(JSID_VOID);
+        return true;
+    }
+
+    *nameOrSymbol = true;
+    return true;
+}
+
 bool
 GetPropIRGenerator::tryAttachStub()
 {
     // Idempotent ICs should call tryAttachIdempotentStub instead.
     MOZ_ASSERT(!idempotent());
 
     AutoAssertNoPendingException aanpe(cx_);
 
@@ -268,16 +295,109 @@ GetPropIRGenerator::tryAttachIdempotentS
     // Also support native data properties on DOMProxy prototypes.
     if (GetProxyStubType(cx_, obj, id) == ProxyStubType::DOMUnshadowed)
         return tryAttachDOMProxyUnshadowed(obj, objId, id);
 
     return false;
 }
 
 static bool
+IsCacheableProtoChain(JSObject* obj, JSObject* holder)
+{
+    while (obj != holder) {
+        /*
+         * We cannot assume that we find the holder object on the prototype
+         * chain and must check for null proto. The prototype chain can be
+         * altered during the lookupProperty call.
+         */
+        JSObject* proto = obj->staticPrototype();
+        if (!proto || !proto->isNative())
+            return false;
+        obj = proto;
+    }
+    return true;
+}
+
+static bool
+IsCacheableGetPropReadSlot(JSObject* obj, JSObject* holder, PropertyResult prop)
+{
+    if (!prop || !IsCacheableProtoChain(obj, holder))
+        return false;
+
+    Shape* shape = prop.shape();
+    if (!shape->hasSlot() || !shape->hasDefaultGetter())
+        return false;
+
+    return true;
+}
+
+static bool
+IsCacheableGetPropCallNative(JSObject* obj, JSObject* holder, Shape* shape)
+{
+    if (!shape || !IsCacheableProtoChain(obj, holder))
+        return false;
+
+    if (!shape->hasGetterValue() || !shape->getterValue().isObject())
+        return false;
+
+    if (!shape->getterValue().toObject().is<JSFunction>())
+        return false;
+
+    JSFunction& getter = shape->getterValue().toObject().as<JSFunction>();
+    if (!getter.isNative())
+        return false;
+
+    if (getter.isClassConstructor())
+        return false;
+
+    // Check for a getter that has jitinfo and whose jitinfo says it's
+    // OK with both inner and outer objects.
+    if (getter.jitInfo() && !getter.jitInfo()->needsOuterizedThisObject())
+        return true;
+
+    // For getters that need the WindowProxy (instead of the Window) as this
+    // object, don't cache if obj is the Window, since our cache will pass that
+    // instead of the WindowProxy.
+    return !IsWindow(obj);
+}
+
+static bool
+IsCacheableGetPropCallScripted(JSObject* obj, JSObject* holder, Shape* shape,
+                               bool* isTemporarilyUnoptimizable = nullptr)
+{
+    if (!shape || !IsCacheableProtoChain(obj, holder))
+        return false;
+
+    if (!shape->hasGetterValue() || !shape->getterValue().isObject())
+        return false;
+
+    if (!shape->getterValue().toObject().is<JSFunction>())
+        return false;
+
+    // See IsCacheableGetPropCallNative.
+    if (IsWindow(obj))
+        return false;
+
+    JSFunction& getter = shape->getterValue().toObject().as<JSFunction>();
+    if (getter.isNative())
+        return false;
+
+    if (!getter.hasJITCode()) {
+        if (isTemporarilyUnoptimizable)
+            *isTemporarilyUnoptimizable = true;
+        return false;
+    }
+
+    if (getter.isClassConstructor())
+        return false;
+
+    return true;
+}
+
+static bool
 IsCacheableNoProperty(JSContext* cx, JSObject* obj, JSObject* holder, Shape* shape, jsid id,
                       jsbytecode* pc, GetPropertyResultFlags resultFlags)
 {
     if (shape)
         return false;
 
     MOZ_ASSERT(!holder);
 
@@ -322,17 +442,17 @@ CanAttachNativeGetProp(JSContext* cx, Ha
     MOZ_ASSERT(!holder);
     if (baseHolder) {
         if (!baseHolder->isNative())
             return CanAttachNone;
         holder.set(&baseHolder->as<NativeObject>());
     }
     shape.set(prop.maybeShape());
 
-    if (IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, prop))
+    if (IsCacheableGetPropReadSlot(obj, holder, prop))
         return CanAttachReadSlot;
 
     if (IsCacheableNoProperty(cx, obj, holder, shape, id, pc, resultFlags))
         return CanAttachReadSlot;
 
     // Idempotent ICs cannot call getters, see tryAttachIdempotentStub.
     if (pc && (resultFlags & GetPropertyResultFlags::Monitored)) {
         if (IsCacheableGetPropCallScripted(obj, holder, shape, isTemporarilyUnoptimizable))
@@ -1861,18 +1981,17 @@ GetNameIRGenerator::tryAttachGlobalNameV
         // non-configurable, and this stub cannot be shared across globals.
         size_t dynamicSlotOffset = holder->dynamicSlotIndex(shape->slot()) * sizeof(Value);
         writer.loadDynamicSlotResult(objId, dynamicSlotOffset);
     } else {
         // Check the prototype chain from the global to the holder
         // prototype. Ignore the global lexical scope as it doesn't figure
         // into the prototype chain. We guard on the global lexical
         // scope's shape independently.
-        if (!IsCacheableGetPropReadSlotForIonOrCacheIR(&globalLexical->global(), holder,
-                                                       PropertyResult(shape)))
+        if (!IsCacheableGetPropReadSlot(&globalLexical->global(), holder, PropertyResult(shape)))
             return false;
 
         // Shape guard for global lexical.
         writer.guardShape(objId, globalLexical->lastProperty());
 
         // Guard on the shape of the GlobalObject.
         ObjOperandId globalId = writer.loadEnclosingEnvironment(objId);
         writer.guardShape(globalId, globalLexical->global().lastProperty());
@@ -1982,17 +2101,17 @@ GetNameIRGenerator::tryAttachEnvironment
         shape = env->as<NativeObject>().lookup(cx_, id);
         if (shape)
             break;
 
         env = env->enclosingEnvironment();
     }
 
     holder = &env->as<NativeObject>();
-    if (!IsCacheableGetPropReadSlotForIonOrCacheIR(holder, holder, PropertyResult(shape)))
+    if (!IsCacheableGetPropReadSlot(holder, holder, PropertyResult(shape)))
         return false;
     if (holder->getSlot(shape->slot()).isMagic())
         return false;
 
     ObjOperandId lastObjId = objId;
     env = env_;
     while (env) {
         if (NeedEnvironmentShapeGuard(env))
@@ -2823,16 +2942,73 @@ SetPropIRGenerator::trackNotAttached()
         sp.valueProperty(guard, "property", idVal_);
         sp.valueProperty(guard, "value", rhsVal_);
         sp.endCache(guard);
     }
 #endif
 }
 
 static bool
+IsCacheableSetPropCallNative(JSObject* obj, JSObject* holder, Shape* shape)
+{
+    if (!shape || !IsCacheableProtoChain(obj, holder))
+        return false;
+
+    if (!shape->hasSetterValue())
+        return false;
+
+    if (!shape->setterObject() || !shape->setterObject()->is<JSFunction>())
+        return false;
+
+    JSFunction& setter = shape->setterObject()->as<JSFunction>();
+    if (!setter.isNative())
+        return false;
+
+    if (setter.isClassConstructor())
+        return false;
+
+    if (setter.jitInfo() && !setter.jitInfo()->needsOuterizedThisObject())
+        return true;
+
+    return !IsWindow(obj);
+}
+
+static bool
+IsCacheableSetPropCallScripted(JSObject* obj, JSObject* holder, Shape* shape,
+                               bool* isTemporarilyUnoptimizable = nullptr)
+{
+    if (!shape || !IsCacheableProtoChain(obj, holder))
+        return false;
+
+    if (IsWindow(obj))
+        return false;
+
+    if (!shape->hasSetterValue())
+        return false;
+
+    if (!shape->setterObject() || !shape->setterObject()->is<JSFunction>())
+        return false;
+
+    JSFunction& setter = shape->setterObject()->as<JSFunction>();
+    if (setter.isNative())
+        return false;
+
+    if (!setter.hasJITCode()) {
+        if (isTemporarilyUnoptimizable)
+            *isTemporarilyUnoptimizable = true;
+        return false;
+    }
+
+    if (setter.isClassConstructor())
+        return false;
+
+    return true;
+}
+
+static bool
 CanAttachSetter(JSContext* cx, jsbytecode* pc, HandleObject obj, HandleId id,
                 MutableHandleObject holder, MutableHandleShape propShape,
                 bool* isTemporarilyUnoptimizable)
 {
     // Don't attach a setter stub for ops like JSOP_INITELEM.
     MOZ_ASSERT(IsPropertySetOp(JSOp(*pc)));
 
     PropertyResult prop;
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -96,196 +96,16 @@ jit::GetReturnAddressToIonCode(JSContext
     void* returnAddr = iter.returnAddress();
 #ifdef DEBUG
     ++iter;
     MOZ_ASSERT(iter.isIonJS());
 #endif
     return returnAddr;
 }
 
-// Note: This differs from IsCacheableProtoChain in BaselineIC.cpp in that
-// Ion caches can deal with objects on the proto chain that have uncacheable
-// prototypes.
-bool
-jit::IsCacheableProtoChainForIonOrCacheIR(JSObject* obj, JSObject* holder)
-{
-    while (obj != holder) {
-        /*
-         * We cannot assume that we find the holder object on the prototype
-         * chain and must check for null proto. The prototype chain can be
-         * altered during the lookupProperty call.
-         */
-        JSObject* proto = obj->staticPrototype();
-        if (!proto || !proto->isNative())
-            return false;
-        obj = proto;
-    }
-    return true;
-}
-
-bool
-jit::IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder, PropertyResult prop)
-{
-    if (!prop || !IsCacheableProtoChainForIonOrCacheIR(obj, holder))
-        return false;
-
-    Shape* shape = prop.shape();
-    if (!shape->hasSlot() || !shape->hasDefaultGetter())
-        return false;
-
-    return true;
-}
-
-bool
-jit::IsCacheableGetPropCallNative(JSObject* obj, JSObject* holder, Shape* shape)
-{
-    if (!shape || !IsCacheableProtoChainForIonOrCacheIR(obj, holder))
-        return false;
-
-    if (!shape->hasGetterValue() || !shape->getterValue().isObject())
-        return false;
-
-    if (!shape->getterValue().toObject().is<JSFunction>())
-        return false;
-
-    JSFunction& getter = shape->getterValue().toObject().as<JSFunction>();
-    if (!getter.isNative())
-        return false;
-
-    if (getter.isClassConstructor())
-        return false;
-
-    // Check for a getter that has jitinfo and whose jitinfo says it's
-    // OK with both inner and outer objects.
-    if (getter.jitInfo() && !getter.jitInfo()->needsOuterizedThisObject())
-        return true;
-
-    // For getters that need the WindowProxy (instead of the Window) as this
-    // object, don't cache if obj is the Window, since our cache will pass that
-    // instead of the WindowProxy.
-    return !IsWindow(obj);
-}
-
-bool
-jit::IsCacheableGetPropCallScripted(JSObject* obj, JSObject* holder, Shape* shape,
-                                    bool* isTemporarilyUnoptimizable)
-{
-    if (!shape || !IsCacheableProtoChainForIonOrCacheIR(obj, holder))
-        return false;
-
-    if (!shape->hasGetterValue() || !shape->getterValue().isObject())
-        return false;
-
-    if (!shape->getterValue().toObject().is<JSFunction>())
-        return false;
-
-    // See IsCacheableGetPropCallNative.
-    if (IsWindow(obj))
-        return false;
-
-    JSFunction& getter = shape->getterValue().toObject().as<JSFunction>();
-    if (getter.isNative())
-        return false;
-
-    if (!getter.hasJITCode()) {
-        if (isTemporarilyUnoptimizable)
-            *isTemporarilyUnoptimizable = true;
-        return false;
-    }
-
-    if (getter.isClassConstructor())
-        return false;
-
-    return true;
-}
-
-bool
-jit::ValueToNameOrSymbolId(JSContext* cx, HandleValue idval, MutableHandleId id,
-                           bool* nameOrSymbol)
-{
-    *nameOrSymbol = false;
-
-    if (!idval.isString() && !idval.isSymbol())
-        return true;
-
-    if (!ValueToId<CanGC>(cx, idval, id))
-        return false;
-
-    if (!JSID_IS_STRING(id) && !JSID_IS_SYMBOL(id)) {
-        id.set(JSID_VOID);
-        return true;
-    }
-
-    uint32_t dummy;
-    if (JSID_IS_STRING(id) && JSID_TO_ATOM(id)->isIndex(&dummy)) {
-        id.set(JSID_VOID);
-        return true;
-    }
-
-    *nameOrSymbol = true;
-    return true;
-}
-
-bool
-jit::IsCacheableSetPropCallNative(JSObject* obj, JSObject* holder, Shape* shape)
-{
-    if (!shape || !IsCacheableProtoChainForIonOrCacheIR(obj, holder))
-        return false;
-
-    if (!shape->hasSetterValue())
-        return false;
-
-    if (!shape->setterObject() || !shape->setterObject()->is<JSFunction>())
-        return false;
-
-    JSFunction& setter = shape->setterObject()->as<JSFunction>();
-    if (!setter.isNative())
-        return false;
-
-    if (setter.isClassConstructor())
-        return false;
-
-    if (setter.jitInfo() && !setter.jitInfo()->needsOuterizedThisObject())
-        return true;
-
-    return !IsWindow(obj);
-}
-
-bool
-jit::IsCacheableSetPropCallScripted(JSObject* obj, JSObject* holder, Shape* shape,
-                                    bool* isTemporarilyUnoptimizable)
-{
-    if (!shape || !IsCacheableProtoChainForIonOrCacheIR(obj, holder))
-        return false;
-
-    if (IsWindow(obj))
-        return false;
-
-    if (!shape->hasSetterValue())
-        return false;
-
-    if (!shape->setterObject() || !shape->setterObject()->is<JSFunction>())
-        return false;
-
-    JSFunction& setter = shape->setterObject()->as<JSFunction>();
-    if (setter.isNative())
-        return false;
-
-    if (!setter.hasJITCode()) {
-        if (isTemporarilyUnoptimizable)
-            *isTemporarilyUnoptimizable = true;
-        return false;
-    }
-
-    if (setter.isClassConstructor())
-        return false;
-
-    return true;
-}
-
 void
 jit::EmitIonStoreDenseElement(MacroAssembler& masm, const ConstantOrRegister& value,
                               Register elements, BaseObjectElementIndex target)
 {
     // If the ObjectElements::CONVERT_DOUBLE_ELEMENTS flag is set, int32 values
     // have to be converted to double first. If the value is not int32, it can
     // always be stored directly.
 
--- a/js/src/jit/IonCaches.h
+++ b/js/src/jit/IonCaches.h
@@ -21,31 +21,16 @@
 #include "jit/shared/Assembler-shared.h"
 #include "js/TrackedOptimizationInfo.h"
 
 #include "vm/TypedArrayObject.h"
 
 namespace js {
 namespace jit {
 
-bool IsCacheableProtoChainForIonOrCacheIR(JSObject* obj, JSObject* holder);
-bool IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder,
-                                               PropertyResult prop);
-
-bool IsCacheableGetPropCallScripted(JSObject* obj, JSObject* holder, Shape* shape,
-                                    bool* isTemporarilyUnoptimizable = nullptr);
-bool IsCacheableGetPropCallNative(JSObject* obj, JSObject* holder, Shape* shape);
-
-bool IsCacheableSetPropCallScripted(JSObject* obj, JSObject* holder, Shape* shape,
-                                    bool* isTemporarilyUnoptimizable = nullptr);
-bool IsCacheableSetPropCallNative(JSObject* obj, JSObject* holder, Shape* shape);
-
-bool ValueToNameOrSymbolId(JSContext* cx, HandleValue idval, MutableHandleId id,
-                           bool* nameOrSymbol);
-
 void* GetReturnAddressToIonCode(JSContext* cx);
 
 void EmitIonStoreDenseElement(MacroAssembler& masm, const ConstantOrRegister& value,
                               Register elements, BaseObjectElementIndex target);
 
 } // namespace jit
 } // namespace js