Bug 1022736 - Allow cacheing of GlobalObject getters on non-global scopechains. (r=jandem)
authorEric Faust <efaustbmo@gmail.com>
Wed, 18 Jun 2014 13:00:17 -0700
changeset 189464 157947d5fe31b8028f3d7c160d0e8f6aebb85841
parent 189463 7a45df366ec881993defb75e8574f8c6e0758d11
child 189465 81af21d6b216003f943e6e394a36f13f60d067e4
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersjandem
bugs1022736
milestone33.0a1
Bug 1022736 - Allow cacheing of GlobalObject getters on non-global scopechains. (r=jandem)
js/src/jit/IonCaches.cpp
js/src/jit/IonCaches.h
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -4127,17 +4127,17 @@ BindNameIC::attachNonGlobal(JSContext *c
         masm.bind(&failures);
         attacher.jumpNextStub(masm);
     }
 
     return linkAndAttachStub(cx, masm, attacher, ion, "non-global");
 }
 
 static bool
-IsCacheableScopeChain(JSObject *scopeChain, JSObject *holder)
+IsCacheableNonGlobalScopeChain(JSObject *scopeChain, JSObject *holder)
 {
     while (true) {
         if (!IsCacheableNonGlobalScope(scopeChain)) {
             IonSpew(IonSpew_InlineCaches, "Non-cacheable object on scope chain");
             return false;
         }
 
         if (scopeChain == holder)
@@ -4170,17 +4170,17 @@ BindNameIC::update(JSContext *cx, size_t
     }
 
     // Stop generating new stubs once we hit the stub count limit, see
     // GetPropertyCache.
     if (cache.canAttachStub()) {
         if (scopeChain->is<GlobalObject>()) {
             if (!cache.attachGlobal(cx, outerScript, ion, scopeChain))
                 return nullptr;
-        } else if (IsCacheableScopeChain(scopeChain, holder)) {
+        } else if (IsCacheableNonGlobalScopeChain(scopeChain, holder)) {
             if (!cache.attachNonGlobal(cx, outerScript, ion, scopeChain, holder))
                 return nullptr;
         } else {
             IonSpew(IonSpew_InlineCaches, "BINDNAME uncacheable scope chain");
         }
     }
 
     return holder;
@@ -4198,26 +4198,44 @@ NameIC::attachReadSlot(JSContext *cx, Ha
     Register scratchReg = outputReg().valueReg().scratchReg();
 
     // Don't guard the base of the proto chain the name was found on. It will be guarded
     // by GenerateReadSlot().
     masm.mov(scopeChainReg(), scratchReg);
     GenerateScopeChainGuards(masm, scopeChain, holderBase, scratchReg, &failures,
                              /* skipLastGuard = */true);
 
-    // GenerateScopeChain leaves the last scope chain in scrachReg, even though it
+    // GenerateScopeChain leaves the last scope chain in scratchReg, even though it
     // doesn't generate the extra guard.
     GenerateReadSlot(cx, ion, masm, attacher, holderBase, holder, shape, scratchReg,
                      outputReg(), failures.used() ? &failures : nullptr);
 
     return linkAndAttachStub(cx, masm, attacher, ion, "generic");
 }
 
 static bool
-IsCacheableNameReadSlot(JSContext *cx, HandleObject scopeChain, HandleObject obj,
+IsCacheableScopeChain(JSObject *scopeChain, JSObject *obj)
+{
+    JSObject *obj2 = scopeChain;
+    while (obj2) {
+        if (!IsCacheableNonGlobalScope(obj2) && !obj2->is<GlobalObject>())
+            return false;
+
+        // Stop once we hit the global or target obj.
+        if (obj2->is<GlobalObject>() || obj2 == obj)
+            break;
+
+        obj2 = obj2->enclosingScope();
+    }
+
+    return obj == obj2;
+}
+
+static bool
+IsCacheableNameReadSlot(HandleObject scopeChain, HandleObject obj,
                         HandleObject holder, HandleShape shape, jsbytecode *pc,
                         const TypedOrValueRegister &output)
 {
     if (!shape)
         return false;
     if (!obj->isNative())
         return false;
 
@@ -4230,58 +4248,61 @@ IsCacheableNameReadSlot(JSContext *cx, H
         JS_ASSERT(obj == holder);
         if (!shape->hasDefaultGetter())
             return false;
     } else {
         // We don't yet support lookups on Block or DeclEnv objects.
         return false;
     }
 
-    RootedObject obj2(cx, scopeChain);
-    while (obj2) {
-        if (!IsCacheableNonGlobalScope(obj2) && !obj2->is<GlobalObject>())
-            return false;
-
-        // Stop once we hit the global or target obj.
-        if (obj2->is<GlobalObject>() || obj2 == obj)
-            break;
-
-        obj2 = obj2->enclosingScope();
-    }
-
-    return obj == obj2;
+    return IsCacheableScopeChain(scopeChain, obj);
 }
 
 bool
 NameIC::attachCallGetter(JSContext *cx, HandleScript outerScript, IonScript *ion,
-                         HandleObject obj, HandleObject holder, HandleShape shape,
-                         void *returnAddr)
+                         HandleObject scopeChain, HandleObject obj, HandleObject holder,
+                         HandleShape shape, void *returnAddr)
 {
     MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
-
     RepatchStubAppender attacher(*this);
+
+    Label failures;
+    Register scratchReg = outputReg().valueReg().scratchReg();
+
+    // Don't guard the base of the proto chain the name was found on. It will be guarded
+    // by GenerateCallGetter().
+    masm.mov(scopeChainReg(), scratchReg);
+    GenerateScopeChainGuards(masm, scopeChain, obj, scratchReg, &failures,
+                             /* skipLastGuard = */true);
+
+    // GenerateScopeChain leaves the last scope chain in scratchReg, even though it
+    // doesn't generate the extra guard.
     if (!GenerateCallGetter(cx, ion, masm, attacher, obj, name(), holder, shape, liveRegs_,
-                            scopeChainReg(), outputReg(), returnAddr))
+                            scratchReg, outputReg(), returnAddr,
+                            failures.used() ? &failures : nullptr))
     {
          return false;
     }
 
     const char *attachKind = "name getter";
     return linkAndAttachStub(cx, masm, attacher, ion, attachKind);
 }
 
 static bool
-IsCacheableNameCallGetter(JSObject *scopeChain, JSObject *obj, JSObject *holder, Shape *shape)
+IsCacheableNameCallGetter(HandleObject scopeChain, HandleObject obj, HandleObject holder,
+                          HandleShape shape)
 {
-    if (obj != scopeChain)
+    if (!shape)
         return false;
-
     if (!obj->is<GlobalObject>())
         return false;
 
+    if (!IsCacheableScopeChain(scopeChain, obj))
+        return false;
+
     return IsCacheableGetPropCallNative(obj, holder, shape) ||
         IsCacheableGetPropCallPropertyOp(obj, holder, shape);
 }
 
 bool
 NameIC::update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain,
                MutableHandleValue vp)
 {
@@ -4298,21 +4319,21 @@ NameIC::update(JSContext *cx, size_t cac
 
     RootedObject obj(cx);
     RootedObject holder(cx);
     RootedShape shape(cx);
     if (!LookupName(cx, name, scopeChain, &obj, &holder, &shape))
         return false;
 
     if (cache.canAttachStub()) {
-        if (IsCacheableNameReadSlot(cx, scopeChain, obj, holder, shape, pc, cache.outputReg())) {
+        if (IsCacheableNameReadSlot(scopeChain, obj, holder, shape, pc, cache.outputReg())) {
             if (!cache.attachReadSlot(cx, outerScript, ion, scopeChain, obj, holder, shape))
                 return false;
         } else if (IsCacheableNameCallGetter(scopeChain, obj, holder, shape)) {
-            if (!cache.attachCallGetter(cx, outerScript, ion, obj, holder, shape, returnAddr))
+            if (!cache.attachCallGetter(cx, outerScript, ion, scopeChain, obj, holder, shape, returnAddr))
                 return false;
         }
     }
 
     if (cache.isTypeOf()) {
         if (!FetchName<true>(cx, obj, holder, name, shape, vp))
             return false;
     } else {
--- a/js/src/jit/IonCaches.h
+++ b/js/src/jit/IonCaches.h
@@ -999,18 +999,18 @@ class NameIC : public RepatchIonCache
         return typeOf_;
     }
 
     bool attachReadSlot(JSContext *cx, HandleScript outerScript, IonScript *ion,
                         HandleObject scopeChain, HandleObject holderBase,
                         HandleObject holder, HandleShape shape);
 
     bool attachCallGetter(JSContext *cx, HandleScript outerScript, IonScript *ion,
-                          HandleObject obj, HandleObject holder, HandleShape shape,
-                          void *returnAddr);
+                          HandleObject scopeChain, HandleObject obj, HandleObject holder,
+                          HandleShape shape, void *returnAddr);
 
     static bool
     update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain, MutableHandleValue vp);
 };
 
 class CallsiteCloneIC : public RepatchIonCache
 {
   protected: