Add support for Math.imul
https://bugs.webkit.org/show_bug.cgi?id=115143

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

Add support for Math.imul, a thunk generator for Math.imul,
and an intrinsic.

Fairly self explanatory set of changes, DFG intrinsics simply
leverages the existing ValueToInt32 nodes.

* create_hash_table:
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::executeEffects):
* dfg/DFGBackwardsPropagationPhase.cpp:
(JSC::DFG::BackwardsPropagationPhase::propagate):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsic):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::performNodeCSE):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNodeType.h:
(DFG):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileArithIMul):
* dfg/DFGSpeculativeJIT.h:
(SpeculativeJIT):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* jit/ThunkGenerators.cpp:
(JSC::imulThunkGenerator):
(JSC):
* jit/ThunkGenerators.h:
(JSC):
* runtime/Intrinsic.h:
* runtime/MathObject.cpp:
(JSC):
(JSC::mathProtoFuncIMul):
* runtime/VM.cpp:
(JSC::thunkGeneratorForIntrinsic):

LayoutTests:

Add a bunch of tests for Math.imul

* fast/js/Object-getOwnPropertyNames-expected.txt:
* fast/js/imul-expected.txt: Added.
* fast/js/imul.html: Added.
* fast/js/regress/imul-double-only-expected.txt: Added.
* fast/js/regress/imul-double-only.html: Added.
* fast/js/regress/imul-int-only-expected.txt: Added.
* fast/js/regress/imul-int-only.html: Added.
* fast/js/regress/imul-mixed-expected.txt: Added.
* fast/js/regress/imul-mixed.html: Added.
* fast/js/regress/script-tests/imul-double-only.js: Added.
(f):
* fast/js/regress/script-tests/imul-int-only.js: Added.
(f):
* fast/js/regress/script-tests/imul-mixed.js: Added.
(f):
* fast/js/script-tests/Object-getOwnPropertyNames.js:
* fast/js/script-tests/imul.js: Added.
(testIMul):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@149159 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index b87fba9..52d72f1 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,51 @@
+2013-04-24  Oliver Hunt  <oliver@apple.com>
+
+        Add support for Math.imul
+        https://bugs.webkit.org/show_bug.cgi?id=115143
+
+        Reviewed by Filip Pizlo.
+
+        Add support for Math.imul, a thunk generator for Math.imul,
+        and an intrinsic.
+
+        Fairly self explanatory set of changes, DFG intrinsics simply
+        leverages the existing ValueToInt32 nodes.
+
+        * create_hash_table:
+        * dfg/DFGAbstractState.cpp:
+        (JSC::DFG::AbstractState::executeEffects):
+        * dfg/DFGBackwardsPropagationPhase.cpp:
+        (JSC::DFG::BackwardsPropagationPhase::propagate):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleIntrinsic):
+        * dfg/DFGCSEPhase.cpp:
+        (JSC::DFG::CSEPhase::performNodeCSE):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNodeType.h:
+        (DFG):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileArithIMul):
+        * dfg/DFGSpeculativeJIT.h:
+        (SpeculativeJIT):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * jit/ThunkGenerators.cpp:
+        (JSC::imulThunkGenerator):
+        (JSC):
+        * jit/ThunkGenerators.h:
+        (JSC):
+        * runtime/Intrinsic.h:
+        * runtime/MathObject.cpp:
+        (JSC):
+        (JSC::mathProtoFuncIMul):
+        * runtime/VM.cpp:
+        (JSC::thunkGeneratorForIntrinsic):
+
 2013-04-25  Filip Pizlo  <fpizlo@apple.com>
 
         Unreviewed, roll out http://trac.webkit.org/changeset/148999
diff --git a/Source/JavaScriptCore/create_hash_table b/Source/JavaScriptCore/create_hash_table
index 875018c..1bd531a 100755
--- a/Source/JavaScriptCore/create_hash_table
+++ b/Source/JavaScriptCore/create_hash_table
@@ -283,6 +283,7 @@
             $intrinsic = "RoundIntrinsic" if ($key eq "round");
             $intrinsic = "ExpIntrinsic" if ($key eq "exp");
             $intrinsic = "LogIntrinsic" if ($key eq "log");
+            $intrinsic = "IMulIntrinsic" if ($key eq "imul");
         }
         if ($name eq "arrayPrototypeTable") {
             $intrinsic = "ArrayPushIntrinsic" if ($key eq "push");
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index d598685..76e69ee 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -428,7 +428,7 @@
         forNode(node).set(SpecInt32);
         break;
     }
-        
+
     case Int32ToDouble:
     case ForwardInt32ToDouble: {
         JSValue child = forNode(node->child1()).value();
@@ -555,6 +555,11 @@
         }
         break;
     }
+
+    case ArithIMul: {
+        forNode(node).set(SpecInt32);
+        break;
+    }
         
     case ArithDiv:
     case ArithMin:
diff --git a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
index 5e2b10f..2f06646 100644
--- a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
@@ -192,7 +192,8 @@
         case BitXor:
         case BitRShift:
         case BitLShift:
-        case BitURShift: {
+        case BitURShift:
+        case ArithIMul: {
             flags |= NodeUsedAsInt;
             flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero | NodeUsedAsOther);
             node->child1()->mergeFlags(flags);
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 98ea8fa..58c9ccf 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -1600,6 +1600,17 @@
         
         return true;
     }
+
+    case IMulIntrinsic: {
+        if (argumentCountIncludingThis != 3)
+            return false;
+        int leftOperand = registerOffset + argumentToOperand(1);
+        int rightOperand = registerOffset + argumentToOperand(2);
+        Node* left = getToInt32(leftOperand);
+        Node* right = getToInt32(rightOperand);
+        setIntrinsicResult(usesResult, resultOperand, addToGraph(ArithIMul, left, right));
+        return true;
+    }
         
     default:
         return false;
diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
index 2c8cc50..47af696 100644
--- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
@@ -1059,6 +1059,7 @@
         case ArithSub:
         case ArithNegate:
         case ArithMul:
+        case ArithIMul:
         case ArithMod:
         case ArithDiv:
         case ArithAbs:
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index a0bfca8..3af1b58 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -100,7 +100,8 @@
         case BitXor:
         case BitRShift:
         case BitLShift:
-        case BitURShift: {
+        case BitURShift:
+        case ArithIMul: {
             fixIntEdge(node->child1());
             fixIntEdge(node->child2());
             break;
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index 6ef9542..29d7e0a 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -105,6 +105,7 @@
     macro(ArithSub, NodeResultNumber | NodeMustGenerate) \
     macro(ArithNegate, NodeResultNumber | NodeMustGenerate) \
     macro(ArithMul, NodeResultNumber | NodeMustGenerate) \
+    macro(ArithIMul, NodeResultInt32 | NodeMustGenerate) \
     macro(ArithDiv, NodeResultNumber | NodeMustGenerate) \
     macro(ArithMod, NodeResultNumber | NodeMustGenerate) \
     macro(ArithAbs, NodeResultNumber | NodeMustGenerate) \
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index 3377f26..63a135b 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -164,7 +164,8 @@
         case BitXor:
         case BitRShift:
         case BitLShift:
-        case BitURShift: {
+        case BitURShift:
+        case ArithIMul: {
             changed |= setPrediction(SpecInt32);
             break;
         }
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index b6c5907..4337e80 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -3332,6 +3332,20 @@
         return;
     }
 }
+void SpeculativeJIT::compileArithIMul(Node* node)
+{
+    SpeculateIntegerOperand op1(this, node->child1());
+    SpeculateIntegerOperand op2(this, node->child2());
+    GPRTemporary result(this);
+
+    GPRReg reg1 = op1.gpr();
+    GPRReg reg2 = op2.gpr();
+
+    m_jit.move(reg1, result.gpr());
+    m_jit.mul32(reg2, result.gpr());
+    integerResult(result.gpr(), node);
+    return;
+}
 
 void SpeculativeJIT::compileArithMul(Node* node)
 {
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 82679d0..6d1defa 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -1968,6 +1968,7 @@
     void compileArithSub(Node*);
     void compileArithNegate(Node*);
     void compileArithMul(Node*);
+    void compileArithIMul(Node*);
 #if CPU(X86) || CPU(X86_64)
     void compileIntegerArithDivForX86(Node*);
 #elif CPU(APPLE_ARMV7S)
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 172afee..3595753 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -2244,6 +2244,10 @@
         compileArithMul(node);
         break;
 
+    case ArithIMul:
+        compileArithIMul(node);
+        break;
+
     case ArithDiv: {
         switch (node->binaryUseKind()) {
         case Int32Use: {
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index e7a7791..8044049 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -2182,6 +2182,10 @@
         compileArithMul(node);
         break;
 
+    case ArithIMul:
+        compileArithIMul(node);
+        break;
+
     case ArithDiv: {
         switch (node->binaryUseKind()) {
         case Int32Use: {
diff --git a/Source/JavaScriptCore/jit/ThunkGenerators.cpp b/Source/JavaScriptCore/jit/ThunkGenerators.cpp
index 8490fd7..a450789 100644
--- a/Source/JavaScriptCore/jit/ThunkGenerators.cpp
+++ b/Source/JavaScriptCore/jit/ThunkGenerators.cpp
@@ -768,6 +768,39 @@
     return jit.finalize(*vm, vm->jitStubs->ctiNativeCall(vm), "pow");
 }
 
+MacroAssemblerCodeRef imulThunkGenerator(VM* vm)
+{
+    SpecializedThunkJIT jit(2);
+    MacroAssembler::Jump nonIntArg0Jump;
+    jit.loadInt32Argument(0, SpecializedThunkJIT::regT0, nonIntArg0Jump);
+    SpecializedThunkJIT::Label doneLoadingArg0(&jit);
+    MacroAssembler::Jump nonIntArg1Jump;
+    jit.loadInt32Argument(1, SpecializedThunkJIT::regT1, nonIntArg1Jump);
+    SpecializedThunkJIT::Label doneLoadingArg1(&jit);
+    jit.mul32(SpecializedThunkJIT::regT1, SpecializedThunkJIT::regT0);
+    jit.returnInt32(SpecializedThunkJIT::regT0);
+
+    if (jit.supportsFloatingPointTruncate()) {
+        nonIntArg0Jump.link(&jit);
+        jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
+        jit.branchTruncateDoubleToInt32(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0, SpecializedThunkJIT::BranchIfTruncateSuccessful).linkTo(doneLoadingArg0, &jit);
+        jit.xor32(SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT0);
+        jit.jump(doneLoadingArg0);
+    } else
+        jit.appendFailure(nonIntArg0Jump);
+
+    if (jit.supportsFloatingPointTruncate()) {
+        nonIntArg1Jump.link(&jit);
+        jit.loadDoubleArgument(1, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT1);
+        jit.branchTruncateDoubleToInt32(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT1, SpecializedThunkJIT::BranchIfTruncateSuccessful).linkTo(doneLoadingArg1, &jit);
+        jit.xor32(SpecializedThunkJIT::regT1, SpecializedThunkJIT::regT1);
+        jit.jump(doneLoadingArg1);
+    } else
+        jit.appendFailure(nonIntArg1Jump);
+
+    return jit.finalize(*vm, vm->jitStubs->ctiNativeCall(vm), "imul");
+}
+
 }
 
 #endif // ENABLE(JIT)
diff --git a/Source/JavaScriptCore/jit/ThunkGenerators.h b/Source/JavaScriptCore/jit/ThunkGenerators.h
index f01c427..a4b0fc4 100644
--- a/Source/JavaScriptCore/jit/ThunkGenerators.h
+++ b/Source/JavaScriptCore/jit/ThunkGenerators.h
@@ -51,6 +51,7 @@
 MacroAssemblerCodeRef roundThunkGenerator(VM*);
 MacroAssemblerCodeRef sqrtThunkGenerator(VM*);
 MacroAssemblerCodeRef powThunkGenerator(VM*);
+MacroAssemblerCodeRef imulThunkGenerator(VM*);
 
 }
 #endif // ENABLE(JIT)
diff --git a/Source/JavaScriptCore/runtime/Intrinsic.h b/Source/JavaScriptCore/runtime/Intrinsic.h
index 76fb92a..313826e 100644
--- a/Source/JavaScriptCore/runtime/Intrinsic.h
+++ b/Source/JavaScriptCore/runtime/Intrinsic.h
@@ -47,7 +47,8 @@
     LogIntrinsic,
     RegExpExecIntrinsic,
     RegExpTestIntrinsic,
-    StringPrototypeValueOfIntrinsic
+    StringPrototypeValueOfIntrinsic,
+    IMulIntrinsic
 };
 
 } // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/MathObject.cpp b/Source/JavaScriptCore/runtime/MathObject.cpp
index 6e467dc..71c53a3 100644
--- a/Source/JavaScriptCore/runtime/MathObject.cpp
+++ b/Source/JavaScriptCore/runtime/MathObject.cpp
@@ -52,6 +52,7 @@
 static EncodedJSValue JSC_HOST_CALL mathProtoFuncSin(ExecState*);
 static EncodedJSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState*);
 static EncodedJSValue JSC_HOST_CALL mathProtoFuncTan(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncIMul(ExecState*);
 
 }
 
@@ -81,6 +82,7 @@
   sin           mathProtoFuncSin               DontEnum|Function 1
   sqrt          mathProtoFuncSqrt              DontEnum|Function 1
   tan           mathProtoFuncTan               DontEnum|Function 1
+  imul          mathProtoFuncIMul              DontEnum|Function 2
 @end
 */
 
@@ -278,6 +280,15 @@
     return JSValue::encode(jsDoubleNumber(tan(exec->argument(0).toNumber(exec))));
 }
 
+EncodedJSValue JSC_HOST_CALL mathProtoFuncIMul(ExecState* exec)
+{
+    int32_t left = exec->argument(0).toInt32(exec);
+    if (exec->hadException())
+        return JSValue::encode(jsNull());
+    int32_t right = exec->argument(1).toInt32(exec);
+    return JSValue::encode(jsNumber(left * right));
+}
+
 #if PLATFORM(IOS) && CPU(ARM_THUMB2)
 
 // The following code is taken from netlib.org:
diff --git a/Source/JavaScriptCore/runtime/VM.cpp b/Source/JavaScriptCore/runtime/VM.cpp
index 95b6527..b352063 100644
--- a/Source/JavaScriptCore/runtime/VM.cpp
+++ b/Source/JavaScriptCore/runtime/VM.cpp
@@ -395,6 +395,8 @@
         return expThunkGenerator;
     case LogIntrinsic:
         return logThunkGenerator;
+    case IMulIntrinsic:
+        return imulThunkGenerator;
     default:
         return 0;
     }