2008-09-14 Cameron Zwarich <cwzwarich@uwaterloo.ca>
authorcwzwarich@webkit.org <cwzwarich@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 14 Sep 2008 23:01:03 +0000 (23:01 +0000)
committercwzwarich@webkit.org <cwzwarich@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 14 Sep 2008 23:01:03 +0000 (23:01 +0000)
        Reviewed by Oliver Hunt.

        Bug 20816: op_lesseq should be optimized
        <https://bugs.webkit.org/show_bug.cgi?id=20816>

        Add a loop_if_lesseq opcode that is similar to the loop_if_less opcode.

        This is a 9.4% speedup on the V8 Crypto benchmark.

        * VM/CTI.cpp:
        (JSC::CTI::privateCompileMainPass):
        (JSC::CTI::privateCompileSlowCases):
        * VM/CodeBlock.cpp:
        (JSC::CodeBlock::dump):
        * VM/CodeGenerator.cpp:
        (JSC::CodeGenerator::emitJumpIfTrue):
        * VM/Machine.cpp:
        (JSC::Machine::privateExecute):
        (JSC::Machine::cti_op_loop_if_lesseq):
        * VM/Machine.h:
        * VM/Opcode.h:

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

JavaScriptCore/ChangeLog
JavaScriptCore/VM/CTI.cpp
JavaScriptCore/VM/CodeBlock.cpp
JavaScriptCore/VM/CodeGenerator.cpp
JavaScriptCore/VM/Machine.cpp
JavaScriptCore/VM/Machine.h
JavaScriptCore/VM/Opcode.h

index 5da4564..fa16206 100644 (file)
@@ -1,13 +1,26 @@
-2008-09-14  Sam Weinig  <sam@webkit.org>
+2008-09-14  Cameron Zwarich  <cwzwarich@uwaterloo.ca>
 
-        Reviewed by Mark Rowe.
+        Reviewed by Oliver Hunt.
 
-        Remove extraneous semicolons.
+        Bug 20816: op_lesseq should be optimized
+        <https://bugs.webkit.org/show_bug.cgi?id=20816>
 
-        * kjs/nodes.cpp:
-        (JSC::PrefixResolveNode::emitCode):
-        * wtf/FastMalloc.cpp:
-        (WTF::TCMalloc_PageHeap::GrowHeap):
+        Add a loop_if_lesseq opcode that is similar to the loop_if_less opcode.
+
+        This is a 9.4% speedup on the V8 Crypto benchmark.
+
+        * VM/CTI.cpp:
+        (JSC::CTI::privateCompileMainPass):
+        (JSC::CTI::privateCompileSlowCases):
+        * VM/CodeBlock.cpp:
+        (JSC::CodeBlock::dump):
+        * VM/CodeGenerator.cpp:
+        (JSC::CodeGenerator::emitJumpIfTrue):
+        * VM/Machine.cpp:
+        (JSC::Machine::privateExecute):
+        (JSC::Machine::cti_op_loop_if_lesseq):
+        * VM/Machine.h:
+        * VM/Opcode.h:
 
 2008-09-14  Sam Weinig  <sam@webkit.org>
 
index 29fe0d3..d8f738f 100644 (file)
@@ -570,6 +570,27 @@ void CTI::privateCompileMainPass()
             i += 4;
             break;
         }
+        case op_loop_if_lesseq: {
+            emitSlowScriptCheck(i);
+
+            unsigned target = instruction[i + 3].u.operand;
+            JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
+            if (src2imm) {
+                emitGetArg(instruction[i + 1].u.operand, X86::edx);
+                emitJumpSlowCaseIfNotImm(X86::edx, i);
+                m_jit.cmpl_i32r(reinterpret_cast<unsigned>(src2imm), X86::edx);
+                m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJle(), i + 3 + target));
+            } else {
+                emitGetArg(instruction[i + 1].u.operand, X86::eax);
+                emitGetArg(instruction[i + 2].u.operand, X86::edx);
+                emitJumpSlowCaseIfNotImm(X86::eax, i);
+                emitJumpSlowCaseIfNotImm(X86::edx, i);
+                m_jit.cmpl_rr(X86::edx, X86::eax);
+                m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJle(), i + 3 + target));
+            }
+            i += 4;
+            break;
+        }
         case op_new_object: {
             emitCall(i, Machine::cti_op_new_object);
             emitPutResult(instruction[i + 1].u.operand);
@@ -1445,6 +1466,30 @@ void CTI::privateCompileSlowCases()
             i += 4;
             break;
         }
+        case op_loop_if_lesseq: {
+            emitSlowScriptCheck(i);
+
+            unsigned target = instruction[i + 3].u.operand;
+            JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
+            if (src2imm) {
+                m_jit.link(iter->from, m_jit.label());
+                emitPutArg(X86::edx, 0);
+                emitGetPutArg(instruction[i + 2].u.operand, 4, X86::ecx);
+                emitCall(i, Machine::cti_op_loop_if_lesseq);
+                m_jit.testl_rr(X86::eax, X86::eax);
+                m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 3 + target]);
+            } else {
+                m_jit.link(iter->from, m_jit.label());
+                m_jit.link((++iter)->from, m_jit.label());
+                emitPutArg(X86::eax, 0);
+                emitPutArg(X86::edx, 4);
+                emitCall(i, Machine::cti_op_loop_if_lesseq);
+                m_jit.testl_rr(X86::eax, X86::eax);
+                m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 3 + target]);
+            }
+            i += 4;
+            break;
+        }
         case op_pre_inc: {
             unsigned srcDst = instruction[i + 1].u.operand;
             X86Assembler::JmpSrc notImm = iter->from;
index 3803f25..70d77c8 100644 (file)
@@ -689,6 +689,13 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             printf("[%4d] loop_if_less\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, jumpTarget(begin, it, offset));
             break;
         }
+        case op_loop_if_lesseq: {
+            int r0 = (++it)->u.operand;
+            int r1 = (++it)->u.operand;
+            int offset = (++it)->u.operand;
+            printf("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, jumpTarget(begin, it, offset));
+            break;
+        }
         case op_switch_imm: {
             int tableIndex = (++it)->u.operand;
             int defaultTarget = (++it)->u.operand;
index 08654ad..40c0e13 100644 (file)
@@ -486,6 +486,21 @@ PassRefPtr<LabelID> CodeGenerator::emitJumpIfTrue(RegisterID* cond, LabelID* tar
             instructions().append(target->offsetFrom(instructions().size()));
             return target;
         }
+    } else if (m_lastOpcodeID == op_lesseq && !target->isForwardLabel()) {
+        int dstIndex;
+        int src1Index;
+        int src2Index;
+
+        retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
+
+        if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
+            rewindBinaryOp();
+            emitOpcode(op_loop_if_lesseq);
+            instructions().append(src1Index);
+            instructions().append(src2Index);
+            instructions().append(target->offsetFrom(instructions().size()));
+            return target;
+        }
     }
 
     emitOpcode(target->isForwardLabel() ? op_jtrue : op_loop_if_true);
index 7bd6c6a..cd8df59 100644 (file)
@@ -2823,6 +2823,33 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         ++vPC;
         NEXT_OPCODE;
     }
+    BEGIN_OPCODE(op_loop_if_lesseq) {
+        /* loop_if_lesseq src1(r) src2(r) target(offset)
+
+           Checks whether register src1 is less than or equal to register
+           src2, as with the ECMAScript '<=' operator, and then jumps to
+           offset target from the current instruction, if and only if the 
+           result of the comparison is true.
+
+           Additionally this loop instruction may terminate JS execution is
+           the JS timeout is reached.
+        */
+        JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
+        JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
+        int target = (++vPC)->u.operand;
+        
+        bool result = jsLessEq(exec, src1, src2);
+        VM_CHECK_EXCEPTION();
+        
+        if (result) {
+            vPC += target;
+            CHECK_FOR_TIMEOUT();
+            NEXT_OPCODE;
+        }
+        
+        ++vPC;
+        NEXT_OPCODE;
+    }
     BEGIN_OPCODE(op_jnless) {
         /* jnless src1(r) src2(r) target(offset)
 
@@ -3895,6 +3922,17 @@ int Machine::cti_op_loop_if_less(CTI_ARGS)
     return result;
 }
 
+int Machine::cti_op_loop_if_lesseq(CTI_ARGS)
+{
+    JSValue* src1 = ARG_src1;
+    JSValue* src2 = ARG_src2;
+    ExecState* exec = ARG_exec;
+
+    bool result = jsLessEq(exec, src1, src2);
+    VM_CHECK_EXCEPTION_AT_END();
+    return result;
+}
+
 JSValue* Machine::cti_op_new_object(CTI_ARGS)
 {
     return constructEmptyObject(ARG_exec);;
index 4a3da7f..3f7b490 100644 (file)
@@ -144,6 +144,7 @@ namespace JSC {
         static JSValue* SFX_CALL cti_op_add(CTI_ARGS);
         static JSValue* SFX_CALL cti_op_pre_inc(CTI_ARGS);
         static int SFX_CALL cti_op_loop_if_less(CTI_ARGS);
+        static int SFX_CALL cti_op_loop_if_lesseq(CTI_ARGS);
         static JSValue* SFX_CALL cti_op_new_object(CTI_ARGS);
         static void SFX_CALL cti_op_put_by_id(CTI_ARGS);
         static void SFX_CALL cti_op_put_by_id_second(CTI_ARGS);
index d8c6edd..a112671 100644 (file)
@@ -116,6 +116,7 @@ namespace JSC {
         macro(op_loop) \
         macro(op_loop_if_true) \
         macro(op_loop_if_less) \
+        macro(op_loop_if_lesseq) \
         macro(op_switch_imm) \
         macro(op_switch_char) \
         macro(op_switch_string) \