Bug 470143 - Part 1/2 - Implement an IM IC for typeof nosuchvar. r=jandem
authorSean Stangl <sstangl@mozilla.com>
Fri, 11 Dec 2015 11:27:55 -0500
changeset 278069 989883d9a10ac4dfc5ab964e9b36417c1f99882e
parent 278068 e779e01003e891cbbd6919aae279359120374efd
child 278070 8554cdd93607ca19ab378583a9b3c498562b4a59
push id29841
push userryanvm@gmail.com
push dateSat, 02 Jan 2016 00:29:52 +0000
treeherderautoland@f7fbc524f9f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs470143
milestone46.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 470143 - Part 1/2 - Implement an IM IC for typeof nosuchvar. r=jandem
js/src/jit-test/tests/ion/bug470143.js
js/src/jit/IonCaches.cpp
js/src/jit/IonCaches.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug470143.js
@@ -0,0 +1,6 @@
+// Test that getname caches correctly handle typeof for missing names.
+function f() { for (i = 0; i < 2000; ++i) { var k = typeof nosuchvar; } return k; }
+
+assertEq(f(), "undefined");
+this.nosuchvar = 5;
+assertEq(f(), "number");
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -4916,16 +4916,73 @@ IsCacheableNameCallGetter(HandleObject s
         return false;
 
     return IsCacheableGetPropCallNative(obj, holder, shape) ||
         IsCacheableGetPropCallPropertyOp(obj, holder, shape) ||
         IsCacheableGetPropCallScripted(obj, holder, shape);
 }
 
 bool
+NameIC::attachTypeOfNoProperty(JSContext* cx, HandleScript outerScript, IonScript* ion,
+                               HandleObject scopeChain)
+{
+    MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
+    Label failures;
+    StubAttacher attacher(*this);
+
+    Register scratchReg = outputReg().valueReg().scratchReg();
+
+    masm.movePtr(scopeChainReg(), scratchReg);
+
+    // Generate scope chain guards.
+    // Since the property was not defined on any object, iterate until reaching the global.
+    JSObject* tobj = scopeChain;
+    while (true) {
+        GenerateScopeChainGuard(masm, tobj, scratchReg, nullptr, &failures);
+
+        if (tobj->is<GlobalObject>())
+            break;
+
+        // Load the next link.
+        tobj = &tobj->as<ScopeObject>().enclosingScope();
+        masm.extractObject(Address(scratchReg, ScopeObject::offsetOfEnclosingScope()), scratchReg);
+    }
+
+    masm.moveValue(UndefinedValue(), outputReg().valueReg());
+    attacher.jumpRejoin(masm);
+
+    masm.bind(&failures);
+    attacher.jumpNextStub(masm);
+
+    // TODO: ICNameStub_TypeOfNoProperty
+    return linkAndAttachStub(cx, masm, attacher, ion, "generic",
+                             JS::TrackedOutcome::ICNameStub_ReadSlot);
+}
+
+static bool
+IsCacheableNameNoProperty(HandleObject scopeChain, HandleObject obj,
+                          HandleObject holder, HandleShape shape, jsbytecode* pc,
+                          NameIC& cache)
+{
+    if (cache.isTypeOf() && !shape) {
+        MOZ_ASSERT(!obj);
+        MOZ_ASSERT(!holder);
+        MOZ_ASSERT(scopeChain);
+
+        // Assert those extra things checked by IsCacheableNoProperty().
+        MOZ_ASSERT(cache.outputReg().hasValue());
+        MOZ_ASSERT(pc != nullptr);
+
+        return true;
+    }
+
+    return false;
+}
+
+bool
 NameIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex, HandleObject scopeChain,
                MutableHandleValue vp)
 {
     IonScript* ion = outerScript->ionScript();
 
     NameIC& cache = ion->getCache(cacheIndex).toName();
     RootedPropertyName name(cx, cache.name());
 
@@ -4957,16 +5014,19 @@ NameIC::update(JSContext* cx, HandleScri
             }
         } else if (IsCacheableNameCallGetter(scopeChain, obj, holder, shape)) {
             void* returnAddr = GetReturnAddressToIonCode(cx);
             if (!cache.attachCallGetter(cx, outerScript, ion, scopeChain, obj, holder, shape,
                                         returnAddr))
             {
                 return false;
             }
+        } else if (IsCacheableNameNoProperty(scopeChain, obj, holder, shape, pc, cache)) {
+            if (!cache.attachTypeOfNoProperty(cx, outerScript, ion, scopeChain))
+                return false;
         }
     }
 
     // Monitor changes to cache entry.
     TypeScript::Monitor(cx, script, pc, vp);
 
     return true;
 }
--- a/js/src/jit/IonCaches.h
+++ b/js/src/jit/IonCaches.h
@@ -789,16 +789,19 @@ class NameIC : public IonCache
     bool attachReadSlot(JSContext* cx, HandleScript outerScript, IonScript* ion,
                         HandleObject scopeChain, HandleObject holderBase,
                         HandleNativeObject holder, HandleShape shape);
 
     bool attachCallGetter(JSContext* cx, HandleScript outerScript, IonScript* ion,
                           HandleObject scopeChain, HandleObject obj, HandleObject holder,
                           HandleShape shape, void* returnAddr);
 
+    bool attachTypeOfNoProperty(JSContext* cx, HandleScript outerScript, IonScript* ion,
+                                HandleObject scopeChain);
+
     static bool
     update(JSContext* cx, HandleScript outerScript, size_t cacheIndex, HandleObject scopeChain,
            MutableHandleValue vp);
 };
 
 #undef CACHE_HEADER
 
 // Implement cache casts now that the compiler can see the inheritance.