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;
}