2008-09-21 Maciej Stachowiak <mjs@apple.com>
authormjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 21 Sep 2008 10:39:29 +0000 (10:39 +0000)
committermjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 21 Sep 2008 10:39:29 +0000 (10:39 +0000)
        Reviewed by Oliver.

        - speed up === operator by generating inline machine code for the fast paths
        https://bugs.webkit.org/show_bug.cgi?id=20820

        * VM/CTI.cpp:
        (JSC::CTI::emitJumpSlowCaseIfNotImmediateNumber):
        (JSC::CTI::emitJumpSlowCaseIfNotImmediateNumbers):
        (JSC::CTI::emitJumpSlowCaseIfNotImmediates):
        (JSC::CTI::emitTagAsBoolImmediate):
        (JSC::CTI::privateCompileMainPass):
        (JSC::CTI::privateCompileSlowCases):
        * VM/CTI.h:
        * VM/Machine.cpp:
        (JSC::Machine::cti_op_stricteq):
        * masm/X86Assembler.h:
        (JSC::X86Assembler::):
        (JSC::X86Assembler::sete_r):
        (JSC::X86Assembler::setz_r):
        (JSC::X86Assembler::movzbl_rr):
        (JSC::X86Assembler::emitUnlinkedJnz):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@36738 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JavaScriptCore/ChangeLog
JavaScriptCore/VM/CTI.cpp
JavaScriptCore/VM/CTI.h
JavaScriptCore/VM/Machine.cpp
JavaScriptCore/masm/X86Assembler.h

index 217af8e993dc8772e2b9990a5709882ccb994690..cc10303b29fa138200e89e24d36d77096071234f 100644 (file)
@@ -1,3 +1,27 @@
+2008-09-21  Maciej Stachowiak  <mjs@apple.com>
+
+        Reviewed by Oliver.
+        
+        - speed up === operator by generating inline machine code for the fast paths
+        https://bugs.webkit.org/show_bug.cgi?id=20820
+
+        * VM/CTI.cpp:
+        (JSC::CTI::emitJumpSlowCaseIfNotImmediateNumber):
+        (JSC::CTI::emitJumpSlowCaseIfNotImmediateNumbers):
+        (JSC::CTI::emitJumpSlowCaseIfNotImmediates):
+        (JSC::CTI::emitTagAsBoolImmediate):
+        (JSC::CTI::privateCompileMainPass):
+        (JSC::CTI::privateCompileSlowCases):
+        * VM/CTI.h:
+        * VM/Machine.cpp:
+        (JSC::Machine::cti_op_stricteq):
+        * masm/X86Assembler.h:
+        (JSC::X86Assembler::):
+        (JSC::X86Assembler::sete_r):
+        (JSC::X86Assembler::setz_r):
+        (JSC::X86Assembler::movzbl_rr):
+        (JSC::X86Assembler::emitUnlinkedJnz):
+
 2008-09-21  Cameron Zwarich  <cwzwarich@uwaterloo.ca>
 
         Reviewed by Maciej Stachowiak.
index 2cf5293c27ecbfc4720d67cdb59668e321a5a566..e32a642777cb966f02c19cc27d73a6bdd78f9a16 100644 (file)
@@ -387,6 +387,12 @@ ALWAYS_INLINE void CTI::emitFastArithIntToImmNoCheck(X86Assembler::RegisterID re
     emitFastArithReTagImmediate(reg);
 }
 
+ALWAYS_INLINE void CTI::emitTagAsBoolImmediate(X86Assembler::RegisterID reg)
+{
+    m_jit.shl_i8r(JSImmediate::ExtendedPayloadShift, reg);
+    m_jit.orl_i32r(JSImmediate::FullTagTypeBool, reg);
+}
+
 CTI::CTI(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
     : m_jit(machine->jitCodeBuffer())
     , m_machine(machine)
@@ -1374,8 +1380,60 @@ void CTI::privateCompileMainPass()
         CTI_COMPILE_UNARY_OP(op_is_string)
         CTI_COMPILE_UNARY_OP(op_is_object)
         CTI_COMPILE_UNARY_OP(op_is_function)
-        CTI_COMPILE_BINARY_OP(op_stricteq)
         CTI_COMPILE_BINARY_OP(op_nstricteq)
+        case op_stricteq: {
+            unsigned dst = instruction[i + 1].u.operand;
+            unsigned src1 = instruction[i + 2].u.operand;
+            unsigned src2 = instruction[i + 3].u.operand;
+
+            emitGetArg(src1, X86::eax);
+            emitGetArg(src2, X86::edx);
+
+            m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
+            X86Assembler::JmpSrc firstNotImmediate = m_jit.emitUnlinkedJe();
+            m_jit.testl_i32r(JSImmediate::TagMask, X86::edx);
+            X86Assembler::JmpSrc secondNotImmediate = m_jit.emitUnlinkedJe();
+
+            m_jit.cmpl_rr(X86::edx, X86::eax);
+            m_jit.sete_r(X86::eax);
+            m_jit.movzbl_rr(X86::eax, X86::eax);
+            emitTagAsBoolImmediate(X86::eax);
+            
+            X86Assembler::JmpSrc bothWereImmediates = m_jit.emitUnlinkedJmp();
+
+            m_jit.link(firstNotImmediate, m_jit.label());
+
+            // check that edx is immediate but not the zero immediate
+            
+            m_jit.testl_i32r(JSImmediate::TagMask, X86::edx);
+            m_jit.setz_r(X86::ecx);
+            m_jit.movzbl_rr(X86::ecx, X86::ecx); // ecx is now 1 if edx was nonimmediate
+            m_jit.cmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::zeroImmediate()), X86::edx);
+            m_jit.sete_r(X86::edx);
+            m_jit.movzbl_rr(X86::edx, X86::edx); // edx is now 1 if edx was the 0 immediate
+            m_jit.orl_rr(X86::ecx, X86::edx);
+
+            m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJnz(), i));
+
+            m_jit.movl_i32r(reinterpret_cast<uint32_t>(jsBoolean(false)), X86::eax);
+
+            X86Assembler::JmpSrc firstWasNotImmediate = m_jit.emitUnlinkedJmp();
+
+            m_jit.link(secondNotImmediate, m_jit.label());
+            // check that eax is not the zero immediate (we know it must be immediate)
+            m_jit.cmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::zeroImmediate()), X86::eax);
+            m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJe(), i));
+
+            m_jit.movl_i32r(reinterpret_cast<uint32_t>(jsBoolean(false)), X86::eax);
+
+            m_jit.link(bothWereImmediates, m_jit.label());
+            m_jit.link(firstWasNotImmediate, m_jit.label());
+
+            emitPutResult(dst);
+            
+            i += 4;
+            break;
+        }
         case op_to_jsnumber: {
             emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
             emitCall(i, Machine::cti_op_to_jsnumber);
@@ -1972,6 +2030,8 @@ void CTI::privateCompileSlowCases()
             i += 4;
             break;
         }
+        CTI_COMPILE_BINARY_OP_SLOW_CASE(op_stricteq);
+
         case op_mod: {
             X86Assembler::JmpSrc notImm1 = iter->from;
             X86Assembler::JmpSrc notImm2 = (++iter)->from;
index 4350afdf806db4b4ba4a8502a00c471b091ea315..86dbb6f4831250a81ceab188bbc230beb42f770d 100644 (file)
@@ -370,6 +370,8 @@ namespace JSC {
         void emitFastArithIntToImmOrSlowCase(X86Assembler::RegisterID, unsigned opcodeIndex);
         void emitFastArithIntToImmNoCheck(X86Assembler::RegisterID);
 
+        void emitTagAsBoolImmediate(X86Assembler::RegisterID reg);
+
         void emitDebugExceptionCheck();
 
         X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, CTIHelper_j);
index 52dab14ee75056e907cef901719c4e45f2ca7b91..10ab0bf6c691f3ee657d1e610742edcf57650910 100644 (file)
@@ -5299,10 +5299,9 @@ JSValue* Machine::cti_op_stricteq(CTI_ARGS)
     JSValue* src1 = ARG_src1;
     JSValue* src2 = ARG_src2;
 
-    if (JSImmediate::areBothImmediate(src1, src2))
-        return jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
-    if (JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate()))
-        return jsBoolean(false);
+    // handled inline as fast cases
+    ASSERT(!JSImmediate::areBothImmediate(src1, src2));
+    ASSERT(!(JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate())));
 
     return jsBoolean(strictEqualSlowCaseInline(src1, src2));
 }
index 93886e43d45ed7ba2cbebfa44dfef4545453b9ba..c5fa6e69bb2d28bbe6ecfc9b033a0f5c87fd7a35 100644 (file)
@@ -191,6 +191,7 @@ public:
         OP_LEA                          = 0x8D,
         OP_GROUP1A_Ev                   = 0x8F,
         OP_CDQ                          = 0x99,
+        OP_SETE                         = 0x94,
         OP_GROUP2_EvIb                  = 0xC1,
         OP_RET                          = 0xC3,
         OP_GROUP11_EvIz                 = 0xC7,
@@ -214,6 +215,7 @@ public:
         OP2_JGE_rel32   = 0x8D,
         OP2_JLE_rel32   = 0x8E,
         OP2_IMUL_GvEv   = 0xAF,
+        OP2_MOVZX_GvEb  = 0xB6,
         OP2_MOVZX_GvEw  = 0xB7,
 
         GROUP1_OP_ADD = 0,
@@ -386,6 +388,18 @@ public:
         emitModRm_rmsib(src, base, index, scale);
     }
 
+    void sete_r(RegisterID dst)
+    {
+        m_buffer->putByte(OP_2BYTE_ESCAPE);
+        m_buffer->putByte(OP_SETE);
+        m_buffer->putByte(MODRM(3, 0, dst));
+    }
+
+    void setz_r(RegisterID dst)
+    {
+        sete_r(dst);
+    }
+
     void orl_rr(RegisterID src, RegisterID dst)
     {
         m_buffer->putByte(OP_OR_EvGv);
@@ -545,6 +559,13 @@ public:
         emitModRm_rmsib(dst, base, index, scale, offset);
     }
 
+    void movzbl_rr(RegisterID src, RegisterID dst)
+    {
+        m_buffer->putByte(OP_2BYTE_ESCAPE);
+        m_buffer->putByte(OP2_MOVZX_GvEb);
+        emitModRm_rr(dst, src);
+    }
+
     void movzwl_mr(int offset, RegisterID base, RegisterID dst)
     {
         m_buffer->putByte(OP_2BYTE_ESCAPE);
@@ -700,6 +721,11 @@ public:
         return JmpSrc(m_buffer->getOffset());
     }
     
+    JmpSrc emitUnlinkedJnz()
+    {
+        return emitUnlinkedJne();
+    }
+
     JmpSrc emitUnlinkedJe()
     {
         m_buffer->ensureSpace(MAX_INSTRUCTION_SIZE);