[JAEGER] Bug 580114: fix constant-type optimization of JSOP_INSTANCEOF in the method jit, r=dvander
authorDavid Mandelin <dmandelin@mozilla.com>
Mon, 19 Jul 2010 18:34:08 -0700
changeset 53124 da41e5a6de821ac221edcf7101846662cf813471
parent 53123 5408e0e3863bce90452f5f0e49a4c45077ef8316
child 53125 1d68b3042bf58e0b4cd561ba61d2d399a3a269a9
push id15660
push userrsayre@mozilla.com
push dateSat, 11 Sep 2010 19:16:24 +0000
treeherdermozilla-central@f1bd314e64ac [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs580114
milestone2.0b2pre
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
[JAEGER] Bug 580114: fix constant-type optimization of JSOP_INSTANCEOF in the method jit, r=dvander
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/FrameEntry.h
js/src/trace-test/tests/jaeger/instanceOfWithKnownTypes.js
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -2956,35 +2956,31 @@ mjit::Compiler::jsop_unbrand()
 {
     prepareStubCall(Uses(1));
     stubCall(stubs::Unbrand);
 }
 
 void
 mjit::Compiler::jsop_instanceof()
 {
+    FrameEntry *lhs = frame.peek(-2);
     FrameEntry *rhs = frame.peek(-1);
 
-    /*
-     * Optimize only function objects, as these will have js_FunctionClass and
-     * thus have fun_instanceOf, which we're inlining.
-     */
-
-    if (rhs->isTypeKnown() && rhs->getKnownType() != JSVAL_TYPE_OBJECT) {
+    // The fast path applies only when both operands are objects.
+    if (rhs->isNotType(JSVAL_TYPE_OBJECT) || lhs->isNotType(JSVAL_TYPE_OBJECT)) {
         prepareStubCall(Uses(2));
         stubCall(stubs::InstanceOf);
         frame.popn(2);
         frame.takeReg(Registers::ReturnReg);
         frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, Registers::ReturnReg);
         return;
     }
 
-    Jump firstSlow;
-    bool typeKnown = rhs->isTypeKnown();
-    if (!typeKnown) {
+    MaybeJump firstSlow;
+    if (!rhs->isTypeKnown()) {
         Jump j = frame.testObject(Assembler::NotEqual, rhs);
         stubcc.linkExit(j, Uses(2));
         RegisterID reg = frame.tempRegForData(rhs);
         j = masm.testFunction(Assembler::NotEqual, reg);
         stubcc.linkExit(j, Uses(2));
         stubcc.leave();
         stubcc.call(stubs::InstanceOf);
         firstSlow = stubcc.masm.jump();
@@ -2996,22 +2992,23 @@ mjit::Compiler::jsop_instanceof()
     jsop_getprop(cx->runtime->atomState.classPrototypeAtom, false);
 
     /* Primitive prototypes are invalid. */
     rhs = frame.peek(-1);
     Jump j = frame.testPrimitive(Assembler::Equal, rhs);
     stubcc.linkExit(j, Uses(3));
 
     /* Allocate registers up front, because of branchiness. */
-    FrameEntry *lhs = frame.peek(-3);
     RegisterID obj = frame.copyDataIntoReg(lhs);
     RegisterID proto = frame.copyDataIntoReg(rhs);
     RegisterID temp = frame.allocReg();
 
-    Jump isFalse = frame.testPrimitive(Assembler::Equal, lhs);
+    MaybeJump isFalse;
+    if (!lhs->isTypeKnown())
+        isFalse = frame.testPrimitive(Assembler::Equal, lhs);
 
     /* Quick test to avoid wrapped objects. */
     masm.loadPtr(Address(obj, offsetof(JSObject, clasp)), temp);
     masm.load32(Address(temp, offsetof(JSClass, flags)), temp);
     masm.and32(Imm32(JSCLASS_IS_EXTENDED), temp);
     j = masm.branchTest32(Assembler::NonZero, temp, temp);
     stubcc.linkExit(j, Uses(3));
 
@@ -3021,26 +3018,28 @@ mjit::Compiler::jsop_instanceof()
     /* Walk prototype chain, break out on NULL or hit. */
     masm.loadData32(protoAddr, obj);
     Jump isFalse2 = masm.branchTestPtr(Assembler::Zero, obj, obj);
     Jump isTrue = masm.branchPtr(Assembler::NotEqual, obj, proto);
     isTrue.linkTo(loop, &masm);
     masm.move(Imm32(1), temp);
     isTrue = masm.jump();
 
-    isFalse.linkTo(masm.label(), &masm);
+    if (isFalse.isSet())
+        isFalse.getJump().linkTo(masm.label(), &masm);
     isFalse2.linkTo(masm.label(), &masm);
     masm.move(Imm32(0), temp);
     isTrue.linkTo(masm.label(), &masm);
 
     frame.freeReg(proto);
     frame.freeReg(obj);
 
     stubcc.leave();
     stubcc.call(stubs::FastInstanceOf);
 
     frame.popn(3);
     frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, temp);
 
-    firstSlow.linkTo(stubcc.masm.label(), &stubcc.masm);
+    if (firstSlow.isSet())
+        firstSlow.getJump().linkTo(stubcc.masm.label(), &stubcc.masm);
     stubcc.rejoin(Changes(1));
 }
 
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -138,16 +138,18 @@ class Compiler
         MaybeJump()
           : set(false)
         { }
 
         inline Jump getJump() const { JS_ASSERT(set); return jump; }
         inline void setJump(const Jump &j) { jump = j; set = true; }
         inline bool isSet() const { return set; }
 
+        inline MaybeJump &operator=(Jump j) { setJump(j); return *this; }
+
       private:
         Jump jump;
         bool set;
     };
 
     JSContext *cx;
     JSScript *script;
     JSObject *scopeChain;
--- a/js/src/methodjit/FrameEntry.h
+++ b/js/src/methodjit/FrameEntry.h
@@ -76,16 +76,26 @@ class FrameEntry
         return v_.s.tag;
     }
 
     JSValueType getKnownType() const {
         JS_ASSERT(isTypeKnown());
         return knownType;
     }
 
+    // Return true iff the type of this value is definitely known to be type_.
+    bool isType(JSValueType type_) const {
+        return isTypeKnown() && getKnownType() == type_;
+    }
+
+    // Return true iff the type of this value is definitely known not to be type_.
+    bool isNotType(JSValueType type_) const {
+        return isTypeKnown() && getKnownType() != type_;
+    }
+
     uint32 getPayload32() const {
         //JS_ASSERT(!Valueify(v_.asBits).isDouble() || type.synced());
         return v_.s.payload.u32;
     }
 
   private:
     void setType(JSValueType type_) {
         type.setConstant();
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/jaeger/instanceOfWithKnownTypes.js
@@ -0,0 +1,13 @@
+// |trace-test| error: TypeError
+
+// Verify that the compiler doesn't assert.
+
+function f() {
+    var o = {}, p = {};
+    z = o instanceof p;
+    z = 3 instanceof p;
+    z = p instanceof 3;
+    z = 3 instanceof 4;
+}
+
+f();