[JAEGER] Fast path for EQ,NE when one side is constant null or undefined.
authorDavid Anderson <danderson@mozilla.com>
Fri, 18 Jun 2010 13:55:08 -0700
changeset 52879 a58ad51a2a08279cba501033655c17e889067865
parent 52878 3f955bda7cfe0659ca0c6ddc3ad231613d817a05
child 52880 22020675ec7709279c9f01a89ee39ac72573e39b
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.3a5pre
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] Fast path for EQ,NE when one side is constant null or undefined.
js/src/jsparse.h
js/src/methodjit/Compiler.h
js/src/methodjit/nunbox/FastOps.cpp
--- a/js/src/jsparse.h
+++ b/js/src/jsparse.h
@@ -485,17 +485,16 @@ public:
                                            statements */
 #define PNX_DESTRUCT   0x200            /* destructuring special cases:
                                            1. shorthand syntax used, at present
                                               object destructuring ({x,y}) only;
                                            2. the first child of function body
                                               is code evaluating destructuring
                                               arguments */
 #define PNX_HOLEY      0x400            /* array initialiser has holes */
-#define PNX_CLOSED     0x800            /* closed over */
 
     uintN frameLevel() const {
         JS_ASSERT(pn_arity == PN_FUNC || pn_arity == PN_NAME);
         return UPVAR_FRAME_SKIP(pn_cookie);
     }
 
     uintN frameSlot() const {
         JS_ASSERT(pn_arity == PN_FUNC || pn_arity == PN_NAME);
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -179,16 +179,17 @@ class Compiler
     void jsop_objtostr();
     void jsop_not();
     void jsop_typeof();
     void jsop_arginc(JSOp op, uint32 slot, bool popped);
     void jsop_localinc(JSOp op, uint32 slot, bool popped);
     void jsop_setelem();
     void jsop_getelem();
     void jsop_stricteq(JSOp op);
+    void jsop_equality(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
 
 #define STUB_CALL_TYPE(type)                                            \
     Call stubCall(type stub, Uses uses, Defs defs) {                    \
         return stubCall(JS_FUNC_TO_DATA_PTR(void *, stub), uses, defs); \
     }
 
     STUB_CALL_TYPE(JSObjStub);
     STUB_CALL_TYPE(VoidStubUInt32);
--- a/js/src/methodjit/nunbox/FastOps.cpp
+++ b/js/src/methodjit/nunbox/FastOps.cpp
@@ -554,29 +554,112 @@ mjit::Compiler::jsop_binary(JSOp op, Voi
     stubcc.call(stub);
 
     frame.popn(2);
     frame.pushUntypedPayload(JSVAL_MASK32_INT32, reg);
 
     stubcc.rejoin(1);
 }
 
+static inline bool
+CheckNullOrUndefined(FrameEntry *fe, JSValueMask32 &mask)
+{
+    if (!fe->isTypeKnown())
+        return false;
+    mask = fe->getTypeTag();
+    if (mask == JSVAL_MASK32_NULL)
+        return true;
+    else if (mask == JSVAL_MASK32_UNDEFINED)
+        return true;
+    return false;
+}
+
+void
+mjit::Compiler::jsop_equality(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused)
+{
+    FrameEntry *rhs = frame.peek(-1);
+    FrameEntry *lhs = frame.peek(-2);
+
+    /* The compiler should have handled constant folding. */
+    JS_ASSERT(!(rhs->isConstant() && lhs->isConstant()));
+
+    bool lhsTest;
+    JSValueMask32 mask;
+    if ((lhsTest = CheckNullOrUndefined(lhs, mask)) || CheckNullOrUndefined(rhs, mask)) {
+        /* What's the other mask? */
+        FrameEntry *test = lhsTest ? rhs : lhs;
+
+        if (test->isTypeKnown()) {
+            emitStubCmpOp(stub, target, fused);
+            return;
+        }
+
+        /* The other side must be null or undefined. */
+        RegisterID reg = frame.ownRegForType(test);
+        masm.and32(Imm32(JSVAL_MASK32_SINGLETON), reg);
+        
+        Assembler::Condition cond;
+        if (op == JSOP_EQ)
+            cond = Assembler::Above;
+        else
+            cond = Assembler::BelowOrEqual;
+
+        frame.pop();
+        frame.pop();
+
+        if (target) {
+            frame.forgetEverything();
+
+            if (fused == JSOP_IFEQ) {
+                if (op == JSOP_EQ)
+                    cond = Assembler::BelowOrEqual;
+                else
+                    cond = Assembler::Above;
+            } else {
+                if (op == JSOP_EQ)
+                    cond = Assembler::Above;
+                else
+                    cond = Assembler::BelowOrEqual;
+            }
+
+            Jump j = masm.branch32(cond, reg, Imm32(JSVAL_MASK32_CLEAR));
+            jumpInScript(j, target);
+        } else {
+            RegisterID resultReg = reg;
+            if (!(Registers::maskReg(reg) & Registers::SingleByteRegs))
+                resultReg = frame.allocReg(Registers::SingleByteRegs);
+
+            masm.set32(cond, reg, Imm32(JSVAL_MASK32_CLEAR), resultReg);
+
+            if (reg != resultReg)
+                frame.freeReg(reg);
+            frame.pushTypedPayload(JSVAL_MASK32_BOOLEAN, resultReg);
+        }
+        return;
+    }
+
+    emitStubCmpOp(stub, target, fused);
+}
+
 void
 mjit::Compiler::jsop_relational(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused)
 {
     FrameEntry *rhs = frame.peek(-1);
     FrameEntry *lhs = frame.peek(-2);
 
     /* The compiler should have handled constant folding. */
     JS_ASSERT(!(rhs->isConstant() && lhs->isConstant()));
 
     /* Always slow path... */
     if ((rhs->isTypeKnown() && rhs->getTypeTag() != JSVAL_MASK32_INT32) ||
         (lhs->isTypeKnown() && lhs->getTypeTag() != JSVAL_MASK32_INT32)) {
-        emitStubCmpOp(stub, target, fused);
+        if (op == JSOP_EQ || op == JSOP_NE)
+            jsop_equality(op, stub, target, fused);
+        else
+            emitStubCmpOp(stub, target, fused);
         return;
     }
 
     /* Test the types. */
     if (!rhs->isTypeKnown()) {
         Jump rhsFail = frame.testInt32(Assembler::NotEqual, rhs);
         stubcc.linkExit(rhsFail);
         frame.learnType(rhs, JSVAL_MASK32_INT32);