Allow for Int52Rep to see things other than Int32, and make this testable
https://bugs.webkit.org/show_bug.cgi?id=134873
<rdar://problem/17641915>
Reviewed by Geoffrey Garen and Mark Hahnenberg.
A major premise of our type inference is that prediction propagation can say whatever it
wants and we'll still have valid IR after Fixup. This previously didn't work with Int52s.
We required some kind of agreement between prediction propagation and fixup over which
data flow paths were Int52 and which weren't.
It turns out that we basically had such an agreement, with the exception of code that was
unreachable due to ForceOSRExit. Then, fixup and prediction propagation would disagree. It
might be nice to fix that bug - but it's only in the case of Int52 that such a thing would
be a bug! Normally, we allow sloppiness in prediction propagation.
This patch allows us to be sloppy with Int52 prediction propagation by giving Int52Rep the
ability to see inputs other than Int32. This fixes the particular ForceOSRExit bug (see
int52-force-osr-exit-path.js for the reduced test case). To make sure that the newly
empowered Int52Rep is actually correct - in case we end up using it on paths other than
ForceOSRExit - this patch introduces an internal intrinsic called fiatInt52() that forces
us to attempt Int52 conversion on the input. This patch adds a bunch of tests that stress
this intrinsic. This means that we're now stressing Int52Rep more so than ever before!
Note that it would still be a bug for prediction propagation to ever cause us to create an
Int52Rep node for a non-Int32 input. But, this will now be a performance bug, rather than
a crash bug.
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGAbstractValue.cpp:
(JSC::DFG::AbstractValue::fixTypeForRepresentation):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsic):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::injectTypeConversionsForEdge):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::isMachineIntConstant):
* dfg/DFGNode.h:
(JSC::DFG::Node::isMachineIntConstant):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::SafeToExecuteEdge::operator()):
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::speculate):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
(JSC::DFG::SpeculativeJIT::convertMachineInt):
(JSC::DFG::SpeculativeJIT::speculateMachineInt):
(JSC::DFG::SpeculativeJIT::speculateDoubleRepMachineInt):
* dfg/DFGStrengthReductionPhase.cpp:
(JSC::DFG::StrengthReductionPhase::handleNode):
* dfg/DFGUseKind.cpp:
(WTF::printInternal):
* dfg/DFGUseKind.h:
(JSC::DFG::typeFilterFor):
(JSC::DFG::isNumerical):
(JSC::DFG::isDouble):
* dfg/DFGValidate.cpp:
(JSC::DFG::Validate::validate):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLIntrinsicRepository.h:
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileInt52Rep):
(JSC::FTL::LowerDFGToLLVM::doubleToInt32):
(JSC::FTL::LowerDFGToLLVM::jsValueToDouble):
(JSC::FTL::LowerDFGToLLVM::jsValueToStrictInt52):
(JSC::FTL::LowerDFGToLLVM::doubleToStrictInt52):
(JSC::FTL::LowerDFGToLLVM::speculate):
(JSC::FTL::LowerDFGToLLVM::speculateMachineInt):
(JSC::FTL::LowerDFGToLLVM::speculateDoubleRepMachineInt):
* jit/JITOperations.h:
* jsc.cpp:
(GlobalObject::finishCreation):
(functionIdentity):
* runtime/Intrinsic.h:
* runtime/JSCJSValue.h:
* runtime/JSCJSValueInlines.h:
(JSC::tryConvertToInt52):
(JSC::isInt52):
(JSC::JSValue::isMachineInt):
* tests/stress/dead-fiat-double-to-int52-then-exit-not-int52.js: Added.
(foo):
* tests/stress/dead-fiat-double-to-int52.js: Added.
(foo):
* tests/stress/dead-fiat-int32-to-int52.js: Added.
(foo):
* tests/stress/dead-fiat-value-to-int52-double-path.js: Added.
(foo):
(bar):
* tests/stress/dead-fiat-value-to-int52-then-exit-not-double.js: Added.
(foo):
(bar):
* tests/stress/dead-fiat-value-to-int52-then-exit-not-int52.js: Added.
(foo):
(bar):
* tests/stress/dead-fiat-value-to-int52.js: Added.
(foo):
(bar):
* tests/stress/fiat-double-to-int52-then-exit-not-int52.js: Added.
(foo):
* tests/stress/fiat-double-to-int52-then-fail-to-fold.js: Added.
(foo):
* tests/stress/fiat-double-to-int52-then-fold.js: Added.
(foo):
* tests/stress/fiat-double-to-int52.js: Added.
(foo):
* tests/stress/fiat-int32-to-int52.js: Added.
(foo):
* tests/stress/fiat-value-to-int52-double-path.js: Added.
(foo):
(bar):
* tests/stress/fiat-value-to-int52-then-exit-not-double.js: Added.
(foo):
(bar):
* tests/stress/fiat-value-to-int52-then-exit-not-int52.js: Added.
(foo):
(bar):
* tests/stress/fiat-value-to-int52-then-fail-to-fold.js: Added.
(foo):
* tests/stress/fiat-value-to-int52-then-fold.js: Added.
(foo):
* tests/stress/fiat-value-to-int52.js: Added.
(foo):
(bar):
* tests/stress/int52-force-osr-exit-path.js: Added.
(foo):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@171096 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index ef0945a..ee08938 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -337,10 +337,8 @@
}
case Int52Rep: {
- RELEASE_ASSERT(node->child1().useKind() == Int32Use);
-
JSValue child = forNode(node->child1()).value();
- if (child && child.isInt32()) {
+ if (child && child.isMachineInt()) {
setConstant(node, child);
break;
}
@@ -1904,6 +1902,7 @@
case Unreachable:
case LastNodeType:
case ArithIMul:
+ case FiatInt52:
RELEASE_ASSERT_NOT_REACHED();
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractValue.cpp b/Source/JavaScriptCore/dfg/DFGAbstractValue.cpp
index c8d7054..d39ca87 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractValue.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractValue.cpp
@@ -95,19 +95,31 @@
m_type &= ~SpecMachineInt;
m_type |= SpecInt52AsDouble;
}
- RELEASE_ASSERT(!(m_type & ~SpecFullDouble));
+ if (m_type & ~SpecFullDouble) {
+ startCrashing();
+ dataLog("Abstract value ", *this, " for double node has type outside SpecFullDouble.\n");
+ CRASH();
+ }
} else if (representation == NodeResultInt52) {
if (m_type & SpecInt52AsDouble) {
m_type &= ~SpecInt52AsDouble;
m_type |= SpecInt52;
}
- RELEASE_ASSERT(!(m_type & ~SpecMachineInt));
+ if (m_type & ~SpecMachineInt) {
+ startCrashing();
+ dataLog("Abstract value ", *this, " for int52 node has type outside SpecMachineInt.\n");
+ CRASH();
+ }
} else {
if (m_type & SpecInt52) {
m_type &= ~SpecInt52;
m_type |= SpecInt52AsDouble;
}
- RELEASE_ASSERT(!(m_type & ~SpecBytecodeTop));
+ if (m_type & ~SpecBytecodeTop) {
+ startCrashing();
+ dataLog("Abstract value ", *this, " for value node has type outside SpecBytecodeTop.\n");
+ CRASH();
+ }
}
checkConsistency();
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index ee5c5f5..7067480 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -1749,6 +1749,17 @@
return true;
}
+ case FiatInt52Intrinsic: {
+ if (argumentCountIncludingThis != 2)
+ return false;
+ VirtualRegister operand = virtualRegisterForArgument(1, registerOffset);
+ if (enableInt52())
+ set(VirtualRegister(resultOperand), addToGraph(FiatInt52, get(operand)));
+ else
+ set(VirtualRegister(resultOperand), get(operand));
+ return true;
+ }
+
default:
return false;
}
diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h
index 7b056df..9e464cf 100644
--- a/Source/JavaScriptCore/dfg/DFGClobberize.h
+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h
@@ -132,6 +132,7 @@
case ValueRep:
case Int52Rep:
case BooleanToNumber:
+ case FiatInt52:
return;
case MovHint:
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 7835e75..3e34b5b 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -992,6 +992,14 @@
break;
}
+ case FiatInt52: {
+ RELEASE_ASSERT(enableInt52());
+ node->convertToIdentity();
+ fixEdge<Int52RepUse>(node->child1());
+ node->setResult(NodeResultInt52);
+ break;
+ }
+
case GetArrayLength:
case Phi:
case Upsilon:
@@ -1011,8 +1019,8 @@
case ValueToInt32:
case HardPhantom: // HardPhantom would be trivial to handle but anyway we assert that we won't see it here yet.
case DoubleRep:
- case Int52Rep:
case ValueRep:
+ case Int52Rep:
case DoubleConstant:
case Int52Constant:
case Identity: // This should have been cleaned up.
@@ -1909,13 +1917,19 @@
switch (edge.useKind()) {
case DoubleRepUse:
- case DoubleRepRealUse: {
+ case DoubleRepRealUse:
+ case DoubleRepMachineIntUse: {
if (edge->hasDoubleResult())
break;
addRequiredPhantom(edge.node());
- if (edge->hasInt52Result()) {
+ if (edge->op() == JSConstant && m_graph.isNumberConstant(edge.node())) {
+ result = m_insertionSet.insertNode(
+ m_indexInBlock, SpecBytecodeDouble, DoubleConstant, node->origin,
+ OpInfo(m_graph.constantRegisterForConstant(
+ jsDoubleNumber(m_graph.valueOfNumberConstant(edge.node())))));
+ } else if (edge->hasInt52Result()) {
result = m_insertionSet.insertNode(
m_indexInBlock, SpecInt52AsDouble, DoubleRep, node->origin,
Edge(edge.node(), Int52RepUse));
@@ -1935,27 +1949,22 @@
addRequiredPhantom(edge.node());
- if (edge->hasDoubleResult()) {
- // This will never happen.
- startCrashing();
- dataLog("Found an Int52RepUse to a double result: ", node, " -> ", edge, "\n");
- m_graph.dump();
- RELEASE_ASSERT_NOT_REACHED();
+ if (edge->op() == JSConstant && m_graph.isMachineIntConstant(edge.node())) {
+ result = m_insertionSet.insertNode(
+ m_indexInBlock, SpecMachineInt, Int52Constant, node->origin,
+ OpInfo(edge->constantNumber()));
+ } else if (edge->hasDoubleResult()) {
+ result = m_insertionSet.insertNode(
+ m_indexInBlock, SpecMachineInt, Int52Rep, node->origin,
+ Edge(edge.node(), DoubleRepMachineIntUse));
} else if (edge->shouldSpeculateInt32ForArithmetic()) {
result = m_insertionSet.insertNode(
m_indexInBlock, SpecInt32, Int52Rep, node->origin,
Edge(edge.node(), Int32Use));
} else {
- // This is only here for dealing with constants.
- if (edge->op() != JSConstant) {
- startCrashing();
- dataLog("Found an Int52RepUse on something that is neither Int32 nor a constant: ", node, " -> ", edge, "\n");
- m_graph.dump();
- RELEASE_ASSERT_NOT_REACHED();
- }
result = m_insertionSet.insertNode(
- m_indexInBlock, SpecMachineInt, Int52Constant, node->origin,
- OpInfo(edge->constantNumber()));
+ m_indexInBlock, SpecMachineInt, Int52Rep, node->origin,
+ Edge(edge.node(), MachineIntUse));
}
edge.setNode(result);
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index 6cd1052..c3a308b 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -332,6 +332,10 @@
{
return node->isNumberConstant(m_codeBlock);
}
+ bool isMachineIntConstant(Node* node)
+ {
+ return node->isMachineIntConstant(m_codeBlock);
+ }
bool isBooleanConstant(Node* node)
{
return node->isBooleanConstant(m_codeBlock);
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index 76dc71b..3688142 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -587,6 +587,11 @@
return result;
}
+ bool isMachineIntConstant(CodeBlock* codeBlock)
+ {
+ return isConstant() && valueOfJSConstant(codeBlock).isMachineInt();
+ }
+
bool isBooleanConstant(CodeBlock* codeBlock)
{
return isConstant() && valueOfJSConstant(codeBlock).isBoolean();
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index 702a5f9..799cf2b 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -120,6 +120,9 @@
macro(Int52Rep, NodeResultInt52) \
macro(ValueRep, NodeResultJS) \
\
+ /* Bogus type asserting node. Useful for testing, disappears during Fixup. */\
+ macro(FiatInt52, NodeResultJS) \
+ \
/* Nodes for arithmetic operations. */\
macro(ArithAdd, NodeResultNumber) \
macro(ArithSub, NodeResultNumber) \
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index 1828648..15cb4f5 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -1045,6 +1045,19 @@
return JSC::stringFromCharCode(exec, op1);
}
+int64_t JIT_OPERATION operationConvertBoxedDoubleToInt52(EncodedJSValue encodedValue)
+{
+ JSValue value = JSValue::decode(encodedValue);
+ if (!value.isDouble())
+ return JSValue::notInt52;
+ return tryConvertToInt52(value.asDouble());
+}
+
+int64_t JIT_OPERATION operationConvertDoubleToInt52(double value)
+{
+ return tryConvertToInt52(value);
+}
+
size_t JIT_OPERATION dfgConvertJSValueToInt32(ExecState* exec, EncodedJSValue value)
{
VM* vm = &exec->vm();
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h
index 83aacbb..720b60a 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.h
+++ b/Source/JavaScriptCore/dfg/DFGOperations.h
@@ -127,6 +127,9 @@
char* JIT_OPERATION operationSwitchString(ExecState*, size_t tableIndex, JSString*);
void JIT_OPERATION operationNotifyWrite(ExecState*, VariableWatchpointSet*, EncodedJSValue);
+int64_t JIT_OPERATION operationConvertBoxedDoubleToInt52(EncodedJSValue);
+int64_t JIT_OPERATION operationConvertDoubleToInt52(double);
+
// These operations implement the implicitly called ToInt32 and ToBoolean conversions from ES5.
// This conversion returns an int32_t within a size_t such that the value is zero extended to fill the register.
size_t JIT_OPERATION dfgConvertJSValueToInt32(ExecState*, EncodedJSValue) WTF_INTERNAL;
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index f3c071e..6a35b9c 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -516,6 +516,12 @@
break;
}
+ case FiatInt52: {
+ RELEASE_ASSERT(enableInt52());
+ changed |= setPrediction(SpecMachineInt);
+ break;
+ }
+
case PutByValAlias:
case GetArrayLength:
case GetTypedArrayByteOffset:
@@ -536,8 +542,8 @@
case ValueToInt32:
case HardPhantom:
case DoubleRep:
- case Int52Rep:
case ValueRep:
+ case Int52Rep:
case DoubleConstant:
case Int52Constant:
case Identity:
diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
index af59026..52bbfe4 100644
--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
@@ -63,6 +63,8 @@
case NotCellUse:
case OtherUse:
case MiscUse:
+ case MachineIntUse:
+ case DoubleRepMachineIntUse:
return;
case KnownInt32Use:
@@ -254,6 +256,7 @@
case DoubleRep:
case Int52Rep:
case BooleanToNumber:
+ case FiatInt52:
return true;
case GetByVal:
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 64d3ff0..83b07e8 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -4817,6 +4817,14 @@
case DoubleRepRealUse:
speculateDoubleReal(edge);
break;
+#if USE(JSVALUE64)
+ case MachineIntUse:
+ speculateMachineInt(edge);
+ break;
+ case DoubleRepMachineIntUse:
+ speculateDoubleRepMachineInt(edge);
+ break;
+#endif
case BooleanUse:
speculateBoolean(edge);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 02f93cb..da17fb3 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -1231,6 +1231,16 @@
m_jit.zeroExtend32ToPtr(GPRInfo::returnValueGPR, result);
return call;
}
+ JITCompiler::Call callOperation(Q_JITOperation_J operation, GPRReg result, GPRReg value)
+ {
+ m_jit.setupArguments(value);
+ return appendCallSetResult(operation, result);
+ }
+ JITCompiler::Call callOperation(Q_JITOperation_D operation, GPRReg result, FPRReg value)
+ {
+ m_jit.setupArguments(value);
+ return appendCallSetResult(operation, result);
+ }
JITCompiler::Call callOperation(J_JITOperation_EI operation, GPRReg result, StringImpl* uid)
{
m_jit.setupArgumentsWithExecState(TrustedImmPtr(uid));
@@ -2234,9 +2244,13 @@
// Helpers for performing type checks on an edge stored in the given registers.
bool needsTypeCheck(Edge edge, SpeculatedType typesPassedThrough) { return m_interpreter.needsTypeCheck(edge, typesPassedThrough); }
void typeCheck(JSValueSource, Edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail);
-
+
void speculateInt32(Edge);
+#if USE(JSVALUE64)
+ void convertMachineInt(Edge, GPRReg resultGPR);
void speculateMachineInt(Edge);
+ void speculateDoubleRepMachineInt(Edge);
+#endif // USE(JSVALUE64)
void speculateNumber(Edge);
void speculateDoubleReal(Edge);
void speculateBoolean(Edge);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 80f6563..8b2b696 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -4633,6 +4633,7 @@
case CheckTierUpAtReturn:
case CheckTierUpAndOSREnter:
case Int52Rep:
+ case FiatInt52:
case Int52Constant:
case CheckInBounds:
case ArithIMul:
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index f30cf69..25944a4 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -957,7 +957,7 @@
FPRReg SpeculativeJIT::fillSpeculateDouble(Edge edge)
{
- ASSERT(edge.useKind() == DoubleRepUse || edge.useKind() == DoubleRepRealUse);
+ ASSERT(edge.useKind() == DoubleRepUse || edge.useKind() == DoubleRepRealUse || edge.useKind() == DoubleRepMachineIntUse);
ASSERT(edge->hasDoubleResult());
VirtualRegister virtualRegister = edge->virtualRegister();
GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
@@ -2035,12 +2035,51 @@
}
case Int52Rep: {
- SpeculateInt32Operand operand(this, node->child1());
- GPRTemporary result(this, Reuse, operand);
-
- m_jit.signExtend32ToPtr(operand.gpr(), result.gpr());
-
- strictInt52Result(result.gpr(), node);
+ switch (node->child1().useKind()) {
+ case Int32Use: {
+ SpeculateInt32Operand operand(this, node->child1());
+ GPRTemporary result(this, Reuse, operand);
+
+ m_jit.signExtend32ToPtr(operand.gpr(), result.gpr());
+
+ strictInt52Result(result.gpr(), node);
+ break;
+ }
+
+ case MachineIntUse: {
+ GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
+
+ convertMachineInt(node->child1(), resultGPR);
+
+ strictInt52Result(resultGPR, node);
+ break;
+ }
+
+ case DoubleRepMachineIntUse: {
+ SpeculateDoubleOperand value(this, node->child1());
+ FPRReg valueFPR = value.fpr();
+
+ GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
+
+ flushRegisters();
+
+ callOperation(operationConvertDoubleToInt52, resultGPR, valueFPR);
+
+ DFG_TYPE_CHECK(
+ JSValueRegs(), node->child1(), SpecInt52AsDouble,
+ m_jit.branch64(
+ JITCompiler::Equal, resultGPR,
+ JITCompiler::TrustedImm64(JSValue::notInt52)));
+
+ strictInt52Result(resultGPR, node);
+ break;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
break;
}
@@ -4721,6 +4760,7 @@
case ArithIMul:
case MultiGetByOffset:
case MultiPutByOffset:
+ case FiatInt52:
RELEASE_ASSERT_NOT_REACHED();
break;
}
@@ -4805,6 +4845,61 @@
m_jit.or32(TrustedImm32(ValueFalse), gpr);
}
+void SpeculativeJIT::convertMachineInt(Edge valueEdge, GPRReg resultGPR)
+{
+ JSValueOperand value(this, valueEdge, ManualOperandSpeculation);
+ GPRReg valueGPR = value.gpr();
+
+ JITCompiler::Jump notInt32 =
+ m_jit.branch64(JITCompiler::Below, valueGPR, GPRInfo::tagTypeNumberRegister);
+
+ m_jit.signExtend32ToPtr(valueGPR, resultGPR);
+ JITCompiler::Jump done = m_jit.jump();
+
+ notInt32.link(&m_jit);
+ silentSpillAllRegisters(resultGPR);
+ callOperation(operationConvertBoxedDoubleToInt52, resultGPR, valueGPR);
+ silentFillAllRegisters(resultGPR);
+
+ DFG_TYPE_CHECK(
+ JSValueRegs(valueGPR), valueEdge, SpecInt32 | SpecInt52AsDouble,
+ m_jit.branch64(
+ JITCompiler::Equal, resultGPR,
+ JITCompiler::TrustedImm64(JSValue::notInt52)));
+ done.link(&m_jit);
+}
+
+void SpeculativeJIT::speculateMachineInt(Edge edge)
+{
+ if (!needsTypeCheck(edge, SpecInt32 | SpecInt52AsDouble))
+ return;
+
+ GPRTemporary temp(this);
+ convertMachineInt(edge, temp.gpr());
+}
+
+void SpeculativeJIT::speculateDoubleRepMachineInt(Edge edge)
+{
+ if (!needsTypeCheck(edge, SpecInt52AsDouble))
+ return;
+
+ SpeculateDoubleOperand value(this, edge);
+ FPRReg valueFPR = value.fpr();
+
+ GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
+
+ flushRegisters();
+
+ callOperation(operationConvertDoubleToInt52, resultGPR, valueFPR);
+
+ DFG_TYPE_CHECK(
+ JSValueRegs(), edge, SpecInt52AsDouble,
+ m_jit.branch64(
+ JITCompiler::Equal, resultGPR,
+ JITCompiler::TrustedImm64(JSValue::notInt52)));
+}
+
#endif
} } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp b/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
index 9fc2ae7..1f837d3 100644
--- a/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
@@ -184,7 +184,8 @@
// as an excuse not to fold. The only thing we would need is a Int52RepInt32Use kind.
bool hadInt32Check = false;
if (m_node->op() == Int52Rep) {
- ASSERT(m_node->child1().useKind() == Int32Use);
+ if (m_node->child1().useKind() != Int32Use)
+ break;
hadInt32Check = true;
}
for (Node* node = m_node->child1().node(); ; node = node->child1().node()) {
@@ -211,7 +212,8 @@
switch (node->op()) {
case Int52Rep:
- ASSERT(node->child1().useKind() == Int32Use);
+ if (node->child1().useKind() != Int32Use)
+ break;
hadInt32Check = true;
continue;
diff --git a/Source/JavaScriptCore/dfg/DFGUseKind.cpp b/Source/JavaScriptCore/dfg/DFGUseKind.cpp
index 4c9661d..913a715 100644
--- a/Source/JavaScriptCore/dfg/DFGUseKind.cpp
+++ b/Source/JavaScriptCore/dfg/DFGUseKind.cpp
@@ -49,6 +49,9 @@
case Int52RepUse:
out.print("Int52Rep");
break;
+ case MachineIntUse:
+ out.print("MachineInt");
+ break;
case NumberUse:
out.print("Number");
break;
@@ -58,6 +61,9 @@
case DoubleRepRealUse:
out.print("DoubleRepReal");
break;
+ case DoubleRepMachineIntUse:
+ out.print("DoubleRepMachineInt");
+ break;
case BooleanUse:
out.print("Boolean");
break;
diff --git a/Source/JavaScriptCore/dfg/DFGUseKind.h b/Source/JavaScriptCore/dfg/DFGUseKind.h
index 3410b21..d6eeef7 100644
--- a/Source/JavaScriptCore/dfg/DFGUseKind.h
+++ b/Source/JavaScriptCore/dfg/DFGUseKind.h
@@ -39,9 +39,11 @@
Int32Use,
KnownInt32Use,
Int52RepUse,
+ MachineIntUse,
NumberUse,
DoubleRepUse,
DoubleRepRealUse,
+ DoubleRepMachineIntUse,
BooleanUse,
CellUse,
KnownCellUse,
@@ -70,12 +72,16 @@
return SpecInt32;
case Int52RepUse:
return SpecMachineInt;
+ case MachineIntUse:
+ return SpecInt32 | SpecInt52AsDouble;
case NumberUse:
return SpecBytecodeNumber;
case DoubleRepUse:
return SpecFullDouble;
case DoubleRepRealUse:
return SpecDoubleReal;
+ case DoubleRepMachineIntUse:
+ return SpecInt52AsDouble;
case BooleanUse:
return SpecBoolean;
case CellUse:
@@ -139,6 +145,8 @@
case Int52RepUse:
case DoubleRepUse:
case DoubleRepRealUse:
+ case MachineIntUse:
+ case DoubleRepMachineIntUse:
return true;
default:
return false;
@@ -150,6 +158,7 @@
switch (kind) {
case DoubleRepUse:
case DoubleRepRealUse:
+ case DoubleRepMachineIntUse:
return true;
default:
return false;
diff --git a/Source/JavaScriptCore/dfg/DFGValidate.cpp b/Source/JavaScriptCore/dfg/DFGValidate.cpp
index 3612b1d..ecd4d87 100644
--- a/Source/JavaScriptCore/dfg/DFGValidate.cpp
+++ b/Source/JavaScriptCore/dfg/DFGValidate.cpp
@@ -117,7 +117,7 @@
m_myRefCounts.find(edge.node())->value++;
- VALIDATE((node, edge), edge->hasDoubleResult() == (edge.useKind() == DoubleRepUse || edge.useKind() == DoubleRepRealUse));
+ VALIDATE((node, edge), edge->hasDoubleResult() == (edge.useKind() == DoubleRepUse || edge.useKind() == DoubleRepRealUse || edge.useKind() == DoubleRepMachineIntUse));
VALIDATE((node, edge), edge->hasInt52Result() == (edge.useKind() == Int52RepUse));
if (m_graph.m_form == SSA) {