https://bugs.webkit.org/show_bug.cgi?id=151746
Reviewed by Filip Pizlo.
Source/JavaScriptCore:
Perf on benchmarks is neutral except for the newly added JSRegress ftl-object-mul
test which shows a 2.16x speed up on x86_64 FTL, 1.27x speed up on x86_64 DFG,
and 1.56x on x86 DFG.
The speed up comes not from the mul operator itself, but from the fact that the
polymorphic operand types support now allow the test function to run without OSR
exiting, thereby realizing the DFG and FTL's speed up on other work that the test
function does.
This patch has passed the layout tests on x86_64 with a debug build.
It passed the JSC tests with x86 and x86_64 debug builds.
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileArithMul):
* ftl/FTLCompile.cpp:
- Changed to call generateBinaryOpFastPath() instead now, and let it dispatch to
the appropriate snippet generator.
* ftl/FTLCompileBinaryOp.cpp:
(JSC::FTL::generateBinaryArithOpFastPath):
(JSC::FTL::generateBinaryOpFastPath):
(JSC::FTL::generateArithSubFastPath): Deleted.
(JSC::FTL::generateValueAddFastPath): Deleted.
- Refactored these functions to eliminate the need for copy-pasting every time
we add support for another binary arithmetic snippet.
* ftl/FTLCompileBinaryOp.h:
* ftl/FTLInlineCacheDescriptor.h:
* ftl/FTLInlineCacheDescriptorInlines.h:
(JSC::FTL::ArithMulDescriptor::ArithMulDescriptor):
(JSC::FTL::ArithMulDescriptor::icSize):
* ftl/FTLInlineCacheSize.cpp:
(JSC::FTL::sizeOfArithMul):
* ftl/FTLInlineCacheSize.h:
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::DFG::LowerDFGToLLVM::lower):
(JSC::FTL::DFG::LowerDFGToLLVM::compileArithMul):
* jit/JITMulGenerator.h:
(JSC::JITMulGenerator::JITMulGenerator):
* tests/stress/op_mul.js:
- Updated a test value: the interesting value for imminent overflow from an
int32 is 0x7fffffff, not 0x7ffffff.
LayoutTests:
* js/regress/ftl-object-mul-expected.txt: Added.
* js/regress/ftl-object-mul.html: Added.
* js/regress/script-tests/ftl-object-mul.js: Added.
(o1.valueOf):
(foo):
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@192993
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2015-12-02 Mark Lam <mark.lam@apple.com>
+
+ Polymorphic operand types for DFG and FTL mul.
+ https://bugs.webkit.org/show_bug.cgi?id=151746
+
+ Reviewed by Filip Pizlo.
+
+ * js/regress/ftl-object-mul-expected.txt: Added.
+ * js/regress/ftl-object-mul.html: Added.
+ * js/regress/script-tests/ftl-object-mul.js: Added.
+ (o1.valueOf):
+ (foo):
+
2015-12-02 Myles C. Maxfield <mmaxfield@apple.com>
Unify font-variant-* with font-variant shorthand
--- /dev/null
+JSRegress/ftl-object-mul
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/ftl-object-mul.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+//@ runFTLNoCJIT
+var o1 = {
+ i: 0,
+ valueOf: function() { return this.i; }
+};
+
+result = 0;
+function foo(a, b) {
+ var result = 0;
+ for (var j = 0; j < 10; j++) {
+ if (a > b)
+ result += a * b;
+ else
+ result += b * 1;
+ }
+ for (var i = 0; i < 1000; i++)
+ result += i;
+ return result;
+}
+noInline(foo);
+
+var iterations;
+var expectedResult;
+if (this.window) {
+ // The layout test doesn't like too many iterations and may time out.
+ iterations = 10000;
+ expectedResult = 9997995200;
+} else {
+ iterations = 100000;
+ expectedResult = 549975495200;
+}
+
+
+for (var i = 0; i <= iterations; i++) {
+ o1.i = i + 2;
+ result += foo(o1, 10);
+}
+
+if (result != expectedResult)
+ throw "Bad result: " + result;
+2015-12-02 Mark Lam <mark.lam@apple.com>
+
+ Polymorphic operand types for DFG and FTL mul.
+ https://bugs.webkit.org/show_bug.cgi?id=151746
+
+ Reviewed by Filip Pizlo.
+
+ Perf on benchmarks is neutral except for the newly added JSRegress ftl-object-mul
+ test which shows a 2.16x speed up on x86_64 FTL, 1.27x speed up on x86_64 DFG,
+ and 1.56x on x86 DFG.
+
+ The speed up comes not from the mul operator itself, but from the fact that the
+ polymorphic operand types support now allow the test function to run without OSR
+ exiting, thereby realizing the DFG and FTL's speed up on other work that the test
+ function does.
+
+ This patch has passed the layout tests on x86_64 with a debug build.
+ It passed the JSC tests with x86 and x86_64 debug builds.
+
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGClobberize.h:
+ (JSC::DFG::clobberize):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGOperations.h:
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileArithMul):
+ * ftl/FTLCompile.cpp:
+ - Changed to call generateBinaryOpFastPath() instead now, and let it dispatch to
+ the appropriate snippet generator.
+
+ * ftl/FTLCompileBinaryOp.cpp:
+ (JSC::FTL::generateBinaryArithOpFastPath):
+ (JSC::FTL::generateBinaryOpFastPath):
+ (JSC::FTL::generateArithSubFastPath): Deleted.
+ (JSC::FTL::generateValueAddFastPath): Deleted.
+ - Refactored these functions to eliminate the need for copy-pasting every time
+ we add support for another binary arithmetic snippet.
+
+ * ftl/FTLCompileBinaryOp.h:
+ * ftl/FTLInlineCacheDescriptor.h:
+ * ftl/FTLInlineCacheDescriptorInlines.h:
+ (JSC::FTL::ArithMulDescriptor::ArithMulDescriptor):
+ (JSC::FTL::ArithMulDescriptor::icSize):
+ * ftl/FTLInlineCacheSize.cpp:
+ (JSC::FTL::sizeOfArithMul):
+ * ftl/FTLInlineCacheSize.h:
+ * ftl/FTLLowerDFGToLLVM.cpp:
+ (JSC::FTL::DFG::LowerDFGToLLVM::lower):
+ (JSC::FTL::DFG::LowerDFGToLLVM::compileArithMul):
+ * jit/JITMulGenerator.h:
+ (JSC::JITMulGenerator::JITMulGenerator):
+
+ * tests/stress/op_mul.js:
+ - Updated a test value: the interesting value for imminent overflow from an
+ int32 is 0x7fffffff, not 0x7ffffff.
+
2015-12-02 Joseph Pecoraro <pecoraro@apple.com>
REGRESSION(r192753): Remote Web Inspector: Applications and Debuggables not showing up in debuggers
typeOfDoubleProduct(
forNode(node->child1()).m_type, forNode(node->child2()).m_type));
break;
+ case UntypedUse:
+ clobberWorld(node->origin.semantic, clobberLimit);
+ forNode(node).setType(m_graph, SpecBytecodeNumber);
+ break;
default:
RELEASE_ASSERT_NOT_REACHED();
break;
case ArithAdd:
case ArithNegate:
- case ArithMul:
case ArithDiv:
case ArithMod:
case DoubleAsInt32:
return;
case ArithSub:
+ case ArithMul:
switch (node->binaryUseKind()) {
case Int32Use:
case Int52RepUse:
}
case ArithMul: {
+ Edge& leftChild = node->child1();
+ Edge& rightChild = node->child2();
+ if (Node::shouldSpeculateUntypedForArithmetic(leftChild.node(), rightChild.node())
+ || m_graph.hasExitSite(node->origin.semantic, BadType)) {
+ fixEdge<UntypedUse>(leftChild);
+ fixEdge<UntypedUse>(rightChild);
+ node->setResult(NodeResultJS);
+ break;
+ }
if (m_graph.mulShouldSpeculateInt32(node, FixupPass)) {
- fixIntOrBooleanEdge(node->child1());
- fixIntOrBooleanEdge(node->child2());
+ fixIntOrBooleanEdge(leftChild);
+ fixIntOrBooleanEdge(rightChild);
if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
node->setArithMode(Arith::Unchecked);
else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
break;
}
if (m_graph.mulShouldSpeculateMachineInt(node, FixupPass)) {
- fixEdge<Int52RepUse>(node->child1());
- fixEdge<Int52RepUse>(node->child2());
+ fixEdge<Int52RepUse>(leftChild);
+ fixEdge<Int52RepUse>(rightChild);
if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
node->setArithMode(Arith::CheckOverflow);
else
node->setResult(NodeResultInt52);
break;
}
- fixDoubleOrBooleanEdge(node->child1());
- fixDoubleOrBooleanEdge(node->child2());
+ fixDoubleOrBooleanEdge(leftChild);
+ fixDoubleOrBooleanEdge(rightChild);
node->setResult(NodeResultDouble);
break;
}
return JSValue::encode(jsAddSlowCase(exec, op1, op2));
}
+EncodedJSValue JIT_OPERATION operationValueMul(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
+{
+ VM* vm = &exec->vm();
+ NativeCallFrameTracer tracer(vm, exec);
+
+ JSValue op1 = JSValue::decode(encodedOp1);
+ JSValue op2 = JSValue::decode(encodedOp2);
+
+ double a = op1.toNumber(exec);
+ double b = op2.toNumber(exec);
+ return JSValue::encode(jsNumber(a * b));
+}
+
EncodedJSValue JIT_OPERATION operationValueSub(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
{
VM* vm = &exec->vm();
EncodedJSValue JIT_OPERATION operationToThisStrict(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationValueAdd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationValueAddNotNumber(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationValueMul(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationValueSub(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationGetByVal(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationGetByValCell(ExecState*, JSCell*, EncodedJSValue encodedProperty) WTF_INTERNAL;
SpeculatedType right = node->child2()->prediction();
if (left && right) {
- if (m_graph.mulShouldSpeculateInt32(node, m_pass))
- changed |= mergePrediction(SpecInt32);
- else if (m_graph.mulShouldSpeculateMachineInt(node, m_pass))
- changed |= mergePrediction(SpecInt52);
- else
- changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
+ if (isFullNumberOrBooleanSpeculationExpectingDefined(left)
+ && isFullNumberOrBooleanSpeculationExpectingDefined(right)) {
+ if (m_graph.mulShouldSpeculateInt32(node, m_pass))
+ changed |= mergePrediction(SpecInt32);
+ else if (m_graph.mulShouldSpeculateMachineInt(node, m_pass))
+ changed |= mergePrediction(SpecInt52);
+ else
+ changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
+ } else
+ changed |= mergePrediction(SpecInt32 | SpecBytecodeDouble);
}
break;
}
#include "DFGSlowPathGenerator.h"
#include "DirectArguments.h"
#include "JITAddGenerator.h"
+#include "JITMulGenerator.h"
#include "JITSubGenerator.h"
#include "JSArrowFunction.h"
#include "JSCInlines.h"
doubleResult(result.fpr(), node);
return;
}
-
+
+ case UntypedUse: {
+ Edge& leftChild = node->child1();
+ Edge& rightChild = node->child2();
+
+ if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node())) {
+ JSValueOperand left(this, leftChild);
+ JSValueOperand right(this, rightChild);
+ JSValueRegs leftRegs = left.jsValueRegs();
+ JSValueRegs rightRegs = right.jsValueRegs();
+#if USE(JSVALUE64)
+ GPRTemporary result(this);
+ JSValueRegs resultRegs = JSValueRegs(result.gpr());
+#else
+ GPRTemporary resultTag(this);
+ GPRTemporary resultPayload(this);
+ JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr());
+#endif
+ flushRegisters();
+ callOperation(operationValueMul, resultRegs, leftRegs, rightRegs);
+ m_jit.exceptionCheck();
+
+ jsValueResult(resultRegs, node);
+ return;
+ }
+
+ Optional<JSValueOperand> left;
+ Optional<JSValueOperand> right;
+
+ JSValueRegs leftRegs;
+ JSValueRegs rightRegs;
+
+ FPRTemporary leftNumber(this);
+ FPRTemporary rightNumber(this);
+ FPRReg leftFPR = leftNumber.fpr();
+ FPRReg rightFPR = rightNumber.fpr();
+
+#if USE(JSVALUE64)
+ GPRTemporary result(this);
+ JSValueRegs resultRegs = JSValueRegs(result.gpr());
+ GPRTemporary scratch(this);
+ GPRReg scratchGPR = scratch.gpr();
+ FPRReg scratchFPR = InvalidFPRReg;
+#else
+ GPRTemporary resultTag(this);
+ GPRTemporary resultPayload(this);
+ JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr());
+ GPRReg scratchGPR = resultTag.gpr();
+ FPRTemporary fprScratch(this);
+ FPRReg scratchFPR = fprScratch.fpr();
+#endif
+
+ SnippetOperand leftOperand(m_state.forNode(leftChild).resultType());
+ SnippetOperand rightOperand(m_state.forNode(rightChild).resultType());
+
+ if (leftChild->isInt32Constant())
+ leftOperand.setConstInt32(leftChild->asInt32());
+ if (rightChild->isInt32Constant())
+ rightOperand.setConstInt32(rightChild->asInt32());
+
+ RELEASE_ASSERT(!leftOperand.isConst() || !rightOperand.isConst());
+
+ if (!leftOperand.isPositiveConstInt32()) {
+ left = JSValueOperand(this, leftChild);
+ leftRegs = left->jsValueRegs();
+ }
+ if (!rightOperand.isPositiveConstInt32()) {
+ right = JSValueOperand(this, rightChild);
+ rightRegs = right->jsValueRegs();
+ }
+
+ JITMulGenerator gen(leftOperand, rightOperand, resultRegs, leftRegs, rightRegs,
+ leftFPR, rightFPR, scratchGPR, scratchFPR);
+ gen.generateFastPath(m_jit);
+
+ ASSERT(gen.didEmitFastPath());
+ gen.endJumpList().append(m_jit.jump());
+
+ gen.slowPathJumpList().link(&m_jit);
+ silentSpillAllRegisters(resultRegs);
+
+ if (leftOperand.isPositiveConstInt32()) {
+ leftRegs = resultRegs;
+ int64_t leftConst = leftOperand.asConstInt32();
+ m_jit.moveValue(JSValue(leftConst), leftRegs);
+ }
+ if (rightOperand.isPositiveConstInt32()) {
+ rightRegs = resultRegs;
+ int64_t rightConst = rightOperand.asConstInt32();
+ m_jit.moveValue(JSValue(rightConst), rightRegs);
+ }
+
+ callOperation(operationValueMul, resultRegs, leftRegs, rightRegs);
+
+ silentFillAllRegisters(resultRegs);
+ m_jit.exceptionCheck();
+
+ gen.endJumpList().link(&m_jit);
+ jsValueResult(resultRegs, node);
+ return;
+ }
+
default:
RELEASE_ASSERT_NOT_REACHED();
return;
CCallHelpers::Jump done;
CCallHelpers::Jump slowPathStart;
- switch (ic.nodeType()) {
- case ArithSub:
- generateArithSubFastPath(ic, fastPathJIT, result, left, right, usedRegisters, done, slowPathStart);
- break;
- case ValueAdd:
- generateValueAddFastPath(ic, fastPathJIT, result, left, right, usedRegisters, done, slowPathStart);
- break;
- default:
- RELEASE_ASSERT_NOT_REACHED();
- }
+ generateBinaryOpFastPath(ic, fastPathJIT, result, left, right, usedRegisters, done, slowPathStart);
char* startOfIC = bitwise_cast<char*>(generatedFunction) + record.instructionOffset;
const char* fastPathICName = ic.fastPathICName();
#include "FTLInlineCacheDescriptor.h"
#include "GPRInfo.h"
#include "JITAddGenerator.h"
+#include "JITMulGenerator.h"
#include "JITSubGenerator.h"
#include "ScratchRegisterAllocator.h"
GPRReg m_savedTagTypeNumberRegister { InvalidGPRReg };
};
-void generateArithSubFastPath(BinaryOpDescriptor& ic, CCallHelpers& jit,
+template<typename BinaryArithOpGenerator>
+void generateBinaryArithOpFastPath(BinaryOpDescriptor& ic, CCallHelpers& jit,
GPRReg result, GPRReg left, GPRReg right, RegisterSet usedRegisters,
CCallHelpers::Jump& done, CCallHelpers::Jump& slowPathStart)
{
- ASSERT(ic.nodeType() == ArithSub);
ScratchRegisterAllocator allocator(usedRegisters);
BinarySnippetRegisterContext context(allocator, result, left, right);
FPRReg rightFPR = allocator.allocateScratchFPR();
FPRReg scratchFPR = InvalidFPRReg;
- JITSubGenerator gen(ic.leftOperand(), ic.rightOperand(), JSValueRegs(result),
+ BinaryArithOpGenerator gen(ic.leftOperand(), ic.rightOperand(), JSValueRegs(result),
JSValueRegs(left), JSValueRegs(right), leftFPR, rightFPR, scratchGPR, scratchFPR);
auto numberOfBytesUsedToPreserveReusedRegisters =
slowPathStart = jit.jump();
}
-void generateValueAddFastPath(BinaryOpDescriptor& ic, CCallHelpers& jit,
+void generateBinaryOpFastPath(BinaryOpDescriptor& ic, CCallHelpers& jit,
GPRReg result, GPRReg left, GPRReg right, RegisterSet usedRegisters,
CCallHelpers::Jump& done, CCallHelpers::Jump& slowPathStart)
{
- ASSERT(ic.nodeType() == ValueAdd);
- ScratchRegisterAllocator allocator(usedRegisters);
-
- BinarySnippetRegisterContext context(allocator, result, left, right);
-
- GPRReg scratchGPR = allocator.allocateScratchGPR();
- FPRReg leftFPR = allocator.allocateScratchFPR();
- FPRReg rightFPR = allocator.allocateScratchFPR();
- FPRReg scratchFPR = InvalidFPRReg;
-
- JITAddGenerator gen(ic.leftOperand(), ic.rightOperand(), JSValueRegs(result),
- JSValueRegs(left), JSValueRegs(right), leftFPR, rightFPR, scratchGPR, scratchFPR);
-
- auto numberOfBytesUsedToPreserveReusedRegisters =
- allocator.preserveReusedRegistersByPushing(jit, ScratchRegisterAllocator::ExtraStackSpace::NoExtraSpace);
-
- context.initializeRegisters(jit);
- gen.generateFastPath(jit);
-
- ASSERT(gen.didEmitFastPath());
- gen.endJumpList().link(&jit);
- context.restoreRegisters(jit);
- allocator.restoreReusedRegistersByPopping(jit, numberOfBytesUsedToPreserveReusedRegisters,
- ScratchRegisterAllocator::ExtraStackSpace::SpaceForCCall);
- done = jit.jump();
-
- gen.slowPathJumpList().link(&jit);
- context.restoreRegisters(jit);
- allocator.restoreReusedRegistersByPopping(jit, numberOfBytesUsedToPreserveReusedRegisters,
- ScratchRegisterAllocator::ExtraStackSpace::SpaceForCCall);
- slowPathStart = jit.jump();
+ switch (ic.nodeType()) {
+ case ArithMul:
+ generateBinaryArithOpFastPath<JITMulGenerator>(ic, jit, result, left, right, usedRegisters, done, slowPathStart);
+ break;
+ case ArithSub:
+ generateBinaryArithOpFastPath<JITSubGenerator>(ic, jit, result, left, right, usedRegisters, done, slowPathStart);
+ break;
+ case ValueAdd:
+ generateBinaryArithOpFastPath<JITAddGenerator>(ic, jit, result, left, right, usedRegisters, done, slowPathStart);
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
}
} } // namespace JSC::FTL
class BinaryOpDescriptor;
-void generateArithSubFastPath(BinaryOpDescriptor&, CCallHelpers&,
- GPRReg result, GPRReg left, GPRReg right, RegisterSet usedRegisters,
- CCallHelpers::Jump& done, CCallHelpers::Jump& slowPathStart);
-
-void generateValueAddFastPath(BinaryOpDescriptor&, CCallHelpers&,
+void generateBinaryOpFastPath(BinaryOpDescriptor&, CCallHelpers&,
GPRReg result, GPRReg left, GPRReg right, RegisterSet usedRegisters,
CCallHelpers::Jump& done, CCallHelpers::Jump& slowPathStart);
SnippetOperand m_rightOperand;
};
+class ArithMulDescriptor : public BinaryOpDescriptor {
+public:
+ ArithMulDescriptor(unsigned stackmapID, CodeOrigin, const SnippetOperand& leftOperand, const SnippetOperand& rightOperand);
+ static size_t icSize();
+};
+
class ArithSubDescriptor : public BinaryOpDescriptor {
public:
ArithSubDescriptor(unsigned stackmapID, CodeOrigin, const SnippetOperand& leftOperand, const SnippetOperand& rightOperand);
namespace JSC { namespace FTL {
+ArithMulDescriptor::ArithMulDescriptor(unsigned stackmapID, CodeOrigin codeOrigin,
+ const SnippetOperand& leftOperand, const SnippetOperand& rightOperand)
+ : BinaryOpDescriptor(DFG::ArithMul, stackmapID, codeOrigin, icSize(),
+ "ArithMul", "ArithMul IC fast path", DFG::operationValueMul, leftOperand, rightOperand)
+{
+}
+
+size_t ArithMulDescriptor::icSize()
+{
+ return sizeOfArithMul();
+}
+
ArithSubDescriptor::ArithSubDescriptor(unsigned stackmapID, CodeOrigin codeOrigin,
const SnippetOperand& leftOperand, const SnippetOperand& rightOperand)
: BinaryOpDescriptor(DFG::ArithSub, stackmapID, codeOrigin, icSize(),
#endif
}
+size_t sizeOfArithMul()
+{
+#if CPU(ARM64)
+#ifdef NDEBUG
+ return 180; // ARM64 release.
+#else
+ return 276; // ARM64 debug.
+#endif
+#else // CPU(X86_64)
+#ifdef NDEBUG
+ return 199; // X86_64 release.
+#else
+ return 286; // X86_64 debug.
+#endif
+#endif
+}
+
size_t sizeOfArithSub()
{
#if CPU(ARM64)
size_t sizeOfConstructVarargs();
size_t sizeOfConstructForwardVarargs();
size_t sizeOfIn();
+size_t sizeOfArithMul();
size_t sizeOfArithSub();
size_t sizeOfValueAdd();
#if ENABLE(MASM_PROBE)
maxNumberOfCatchSpills = std::max(maxNumberOfCatchSpills, m_graph.localsLiveInBytecode(opCatchOrigin).bitCount());
break;
}
+ case ArithMul:
case ArithSub:
case GetById:
case GetByIdFlush:
void compileValueAdd()
{
- auto leftChild = m_node->child1();
- auto rightChild = m_node->child2();
+ Edge& leftChild = m_node->child1();
+ Edge& rightChild = m_node->child2();
if (!(provenType(leftChild) & SpecFullNumber) || !(provenType(rightChild) & SpecFullNumber)) {
setJSValue(vmCall(m_out.int64, m_out.operation(operationValueAddNotNumber), m_callFrame,
m_out.doubleMul(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
break;
}
-
+
+ case UntypedUse: {
+ Edge& leftChild = m_node->child1();
+ Edge& rightChild = m_node->child2();
+
+ if (!(provenType(leftChild) & SpecFullNumber) || !(provenType(rightChild) & SpecFullNumber)) {
+ setJSValue(vmCall(m_out.int64, m_out.operation(operationValueMul), m_callFrame,
+ lowJSValue(leftChild), lowJSValue(rightChild)));
+ return;
+ }
+
+ unsigned stackmapID = m_stackmapIDs++;
+
+ if (Options::verboseCompilation())
+ dataLog(" Emitting ArithMul patchpoint with stackmap #", stackmapID, "\n");
+
+#if FTL_USES_B3
+ CRASH();
+#else
+ LValue left = lowJSValue(leftChild);
+ LValue right = lowJSValue(rightChild);
+
+ SnippetOperand leftOperand(abstractValue(leftChild).resultType());
+ SnippetOperand rightOperand(abstractValue(rightChild).resultType());
+
+ if (leftChild->isInt32Constant())
+ leftOperand.setConstInt32(leftChild->asInt32());
+ if (rightChild->isInt32Constant())
+ rightOperand.setConstInt32(rightChild->asInt32());
+
+ RELEASE_ASSERT(!leftOperand.isConst() || !rightOperand.isConst());
+
+ // Arguments: id, bytes, target, numArgs, args...
+ StackmapArgumentList arguments;
+ arguments.append(m_out.constInt64(stackmapID));
+ arguments.append(m_out.constInt32(ArithSubDescriptor::icSize()));
+ arguments.append(constNull(m_out.ref8));
+ arguments.append(m_out.constInt32(2));
+ arguments.append(left);
+ arguments.append(right);
+
+ appendOSRExitArgumentsForPatchpointIfWillCatchException(arguments,
+ ExceptionType::BinaryOpGenerator, 3); // left, right, and result show up in the stackmap locations.
+
+ LValue call = m_out.call(m_out.int64, m_out.patchpointInt64Intrinsic(), arguments);
+ setInstructionCallingConvention(call, LLVMAnyRegCallConv);
+
+ m_ftlState.binaryOps.append(ArithMulDescriptor(stackmapID, m_node->origin.semantic, leftOperand, rightOperand));
+
+ setJSValue(call);
+#endif
+ break;
+ }
+
default:
DFG_CRASH(m_graph, m_node, "Bad use kind");
break;
public:
JITMulGenerator(SnippetOperand leftOperand, SnippetOperand rightOperand,
JSValueRegs result, JSValueRegs left, JSValueRegs right,
- FPRReg leftFPR, FPRReg rightFPR, GPRReg scratchGPR, FPRReg scratchFPR, uint32_t* profilingCounter)
+ FPRReg leftFPR, FPRReg rightFPR, GPRReg scratchGPR, FPRReg scratchFPR, uint32_t* profilingCounter = nullptr)
: m_leftOperand(leftOperand)
, m_rightOperand(rightOperand)
, m_result(result)
'-0x7fff',
'0x10000',
'-0x10000',
- '0x7ffffff',
- '-0x7ffffff',
+ '0x7fffffff',
+ '-0x7fffffff',
'0x100000000',
'-0x100000000',
'"-0x7fff"',
'"0x10000"',
'"-0x10000"',
- '"0x7ffffff"',
- '"-0x7ffffff"',
+ '"0x7fffffff"',
+ '"-0x7fffffff"',
'"0x100000000"',
'"-0x100000000"',
];