2008-09-24 Maciej Stachowiak <mjs@apple.com>
authormjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 25 Sep 2008 00:26:38 +0000 (00:26 +0000)
committermjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 25 Sep 2008 00:26:38 +0000 (00:26 +0000)
        Reviewed by Oliver Hunt.

        - inline JIT fast case of op_neq
        - remove extra level of function call indirection from slow cases of eq and neq

        1% speedup on Richards

        * VM/CTI.cpp:
        (JSC::CTI::privateCompileMainPass):
        (JSC::CTI::privateCompileSlowCases):
        * VM/Machine.cpp:
        (JSC::Machine::privateExecute):
        (JSC::Machine::cti_op_eq):
        (JSC::Machine::cti_op_neq):
        * kjs/operations.cpp:
        (JSC::equal):
        (JSC::equalSlowCase):
        * kjs/operations.h:
        (JSC::equalSlowCaseInline):

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

JavaScriptCore/ChangeLog
JavaScriptCore/VM/CTI.cpp
JavaScriptCore/VM/Machine.cpp
JavaScriptCore/kjs/operations.cpp
JavaScriptCore/kjs/operations.h

index 2d7b9af9fc818e13d6ab1b24e92cfca0cc137101..7ae5a3068ae4a5bbe02a5013dcc828f7dcf935c3 100644 (file)
@@ -1,3 +1,25 @@
+2008-09-24  Maciej Stachowiak  <mjs@apple.com>
+
+        Reviewed by Oliver Hunt.
+        
+        - inline JIT fast case of op_neq
+        - remove extra level of function call indirection from slow cases of eq and neq
+        
+        1% speedup on Richards
+
+        * VM/CTI.cpp:
+        (JSC::CTI::privateCompileMainPass):
+        (JSC::CTI::privateCompileSlowCases):
+        * VM/Machine.cpp:
+        (JSC::Machine::privateExecute):
+        (JSC::Machine::cti_op_eq):
+        (JSC::Machine::cti_op_neq):
+        * kjs/operations.cpp:
+        (JSC::equal):
+        (JSC::equalSlowCase):
+        * kjs/operations.h:
+        (JSC::equalSlowCaseInline):
+
 2008-09-24  Sam Weinig  <sam@webkit.org>
 
         Reviewed by Darin Adler.
index 96e67e79248f0279c3891d56634e6618ab054cf6..a53ca6020d5e7cb9cf2724a8f7ead0eec467b4e5 100644 (file)
@@ -1417,7 +1417,21 @@ void CTI::privateCompileMainPass()
             break;
         }
         CTI_COMPILE_BINARY_OP(op_less)
-        CTI_COMPILE_BINARY_OP(op_neq)
+        case op_neq: {
+            emitGetArg(instruction[i + 2].u.operand, X86::eax);
+            emitGetArg(instruction[i + 3].u.operand, X86::edx);
+            emitJumpSlowCaseIfNotImmNums(X86::eax, X86::edx, i);
+            m_jit.cmpl_rr(X86::eax, X86::edx);
+
+            m_jit.setne_r(X86::eax);
+            m_jit.movzbl_rr(X86::eax, X86::eax);
+            emitTagAsBoolImmediate(X86::eax);
+
+            emitPutResult(instruction[i + 1].u.operand);
+
+            i += 4;
+            break;
+        }
         case op_post_dec: {
             int srcDst = instruction[i + 2].u.operand;
             emitGetArg(srcDst, X86::eax);
@@ -2178,6 +2192,15 @@ void CTI::privateCompileSlowCases()
             i += 4;
             break;
         }
+        case op_neq: {
+            m_jit.link(iter->from, m_jit.label());
+            emitPutArg(X86::eax, 0);
+            emitPutArg(X86::edx, 4);
+            emitCall(i, Machine::cti_op_neq);
+            emitPutResult(instruction[i + 1].u.operand);
+            i += 4;
+            break;
+        }
         CTI_COMPILE_BINARY_OP_SLOW_CASE(op_stricteq);
         CTI_COMPILE_BINARY_OP_SLOW_CASE(op_nstricteq);
         case op_instanceof: {
index 8c7b624a9676a17139065904ccc9aca65fa69448..4512b0cfe8f2065e084726b11b35e85f8f7335e7 100644 (file)
@@ -1561,7 +1561,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         if (JSImmediate::areBothImmediateNumbers(src1, src2))
             r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
         else {
-            JSValue* result = jsBoolean(equal(exec, src1, src2));
+            JSValue* result = jsBoolean(equalSlowCase(exec, src1, src2));
             VM_CHECK_EXCEPTION();
             r[dst] = result;
         }
@@ -1601,7 +1601,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         if (JSImmediate::areBothImmediateNumbers(src1, src2))
             r[dst] = jsBoolean(src1 != src2);
         else {
-            JSValue* result = jsBoolean(!equal(exec, src1, src2));
+            JSValue* result = jsBoolean(!equalSlowCase(exec, src1, src2));
             VM_CHECK_EXCEPTION();
             r[dst] = result;
         }
@@ -5020,7 +5020,7 @@ JSValue* Machine::cti_op_eq(CTI_ARGS)
     ExecState* exec = ARG_exec;
 
     ASSERT(!JSImmediate::areBothImmediateNumbers(src1, src2));
-    JSValue* result = jsBoolean(equal(exec, src1, src2));
+    JSValue* result = jsBoolean(equalSlowCaseInline(exec, src1, src2));
     VM_CHECK_EXCEPTION_AT_END();
     return result;
 }
@@ -5163,14 +5163,12 @@ JSValue* Machine::cti_op_neq(CTI_ARGS)
     JSValue* src1 = ARG_src1;
     JSValue* src2 = ARG_src2;
 
-    if (JSImmediate::areBothImmediateNumbers(src1, src2))
-        return jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
-    else {
-        ExecState* exec = ARG_exec;
-        JSValue* result = jsBoolean(!equal(exec, src1, src2));
-        VM_CHECK_EXCEPTION_AT_END();
-        return result;
-    }
+    ASSERT(!JSImmediate::areBothImmediateNumbers(src1, src2));
+
+    ExecState* exec = ARG_exec;
+    JSValue* result = jsBoolean(!equalSlowCaseInline(exec, src1, src2));
+    VM_CHECK_EXCEPTION_AT_END();
+    return result;
 }
 
 JSValue* Machine::cti_op_post_dec(CTI_ARGS)
index 98ca23cf46f12df3ab35c64f52ac31d51cf963da..f2d8debbb5dfb4fe8d502cf2f11037f62c708e96 100644 (file)
@@ -38,65 +38,15 @@ namespace JSC {
 // ECMA 11.9.3
 bool equal(ExecState* exec, JSValue* v1, JSValue* v2)
 {
-startOver:
     if (JSImmediate::areBothImmediateNumbers(v1, v2))
         return v1 == v2;
 
-    if (v1->isNumber() && v2->isNumber())
-        return v1->uncheckedGetNumber() == v2->uncheckedGetNumber();
-
-    bool s1 = v1->isString();
-    bool s2 = v2->isString();
-    if (s1 && s2)
-        return static_cast<JSString*>(v1)->value() == static_cast<JSString*>(v2)->value();
-
-    if (v1->isUndefinedOrNull()) {
-        if (v2->isUndefinedOrNull())
-            return true;
-        if (JSImmediate::isImmediate(v2))
-            return false;
-        return v2->asCell()->structureID()->typeInfo().masqueradesAsUndefined();
-    }
-
-    if (v2->isUndefinedOrNull()) {
-        if (JSImmediate::isImmediate(v1))
-            return false;
-        return v1->asCell()->structureID()->typeInfo().masqueradesAsUndefined();
-    }
-
-    if (v1->isObject()) {
-        if (v2->isObject())
-            return v1 == v2;
-        JSValue* p1 = v1->toPrimitive(exec);
-        if (exec->hadException())
-            return false;
-        v1 = p1;
-        goto startOver;
-    }
-
-    if (v2->isObject()) {
-        JSValue* p2 = v2->toPrimitive(exec);
-        if (exec->hadException())
-            return false;
-        v2 = p2;
-        goto startOver;
-    }
-
-    if (s1 || s2) {
-        double d1 = v1->toNumber(exec);
-        double d2 = v2->toNumber(exec);
-        return d1 == d2;
-    }
-
-    if (v1->isBoolean()) {
-        if (v2->isNumber())
-            return static_cast<double>(v1->getBoolean()) == v2->uncheckedGetNumber();
-    } else if (v2->isBoolean()) {
-        if (v1->isNumber())
-            return v1->uncheckedGetNumber() == static_cast<double>(v2->getBoolean());
-    }
+    return equalSlowCaseInline(exec, v1, v2);
+}
 
-    return v1 == v2;
+bool equalSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
+{
+    return equalSlowCaseInline(exec, v1, v2);
 }
 
 bool strictEqual(JSValue* v1, JSValue* v2)
index 5d9975943728e509f8ca68cd57d2f132a518ac44..ff11ce952c30729812335730ad06b106fdd6636e 100644 (file)
@@ -31,7 +31,78 @@ namespace JSC {
   class ExecState;
   class JSValue;
 
+  // ECMA 11.9.3
   bool equal(ExecState*, JSValue*, JSValue*);
+  bool equalSlowCase(ExecState*, JSValue*, JSValue*);
+
+  ALWAYS_INLINE bool equalSlowCaseInline(ExecState* exec, JSValue* v1, JSValue* v2)
+  {
+      ASSERT(!JSImmediate::areBothImmediateNumbers(v1, v2));
+
+      do {
+          if (v1->isNumber() && v2->isNumber())
+              return v1->uncheckedGetNumber() == v2->uncheckedGetNumber();
+
+          bool s1 = v1->isString();
+          bool s2 = v2->isString();
+          if (s1 && s2)
+              return static_cast<JSString*>(v1)->value() == static_cast<JSString*>(v2)->value();
+
+          if (v1->isUndefinedOrNull()) {
+              if (v2->isUndefinedOrNull())
+                  return true;
+              if (JSImmediate::isImmediate(v2))
+                  return false;
+              return v2->asCell()->structureID()->typeInfo().masqueradesAsUndefined();
+          }
+
+          if (v2->isUndefinedOrNull()) {
+              if (JSImmediate::isImmediate(v1))
+                  return false;
+              return v1->asCell()->structureID()->typeInfo().masqueradesAsUndefined();
+          }
+
+          if (v1->isObject()) {
+              if (v2->isObject())
+                  return v1 == v2;
+              JSValue* p1 = v1->toPrimitive(exec);
+              if (exec->hadException())
+                  return false;
+              v1 = p1;
+              if (JSImmediate::areBothImmediateNumbers(v1, v2))
+                  return v1 == v2;
+              continue;
+          }
+
+          if (v2->isObject()) {
+              JSValue* p2 = v2->toPrimitive(exec);
+              if (exec->hadException())
+                  return false;
+              v2 = p2;
+              if (JSImmediate::areBothImmediateNumbers(v1, v2))
+                  return v1 == v2;
+              continue;
+          }
+
+          if (s1 || s2) {
+              double d1 = v1->toNumber(exec);
+              double d2 = v2->toNumber(exec);
+              return d1 == d2;
+          }
+
+          if (v1->isBoolean()) {
+              if (v2->isNumber())
+                  return static_cast<double>(v1->getBoolean()) == v2->uncheckedGetNumber();
+          } else if (v2->isBoolean()) {
+              if (v1->isNumber())
+                  return v1->uncheckedGetNumber() == static_cast<double>(v2->getBoolean());
+          }
+
+          return v1 == v2;
+      } while (true);
+  }
+
+
   bool strictEqual(JSValue*, JSValue*);
   bool strictEqualSlowCase(JSValue*, JSValue*);