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 373201 06c9ca99d4618e2d3316218249cc5672dbf70119
parent 373200 19ed20aa5c3e0962b8ed6746660cb6a5a4f14e68
child 373202 9c41f1c5bcb8e0c855b7862300317f5a3e326322
child 373255 65507616792c990b1230888612dd7ffc13ed32b4
push id93468
push userevilpies@gmail.com
push dateMon, 07 Aug 2017 16:33:34 +0000
treeherdermozilla-inbound@06c9ca99d461 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1385278
milestone57.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 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