summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-07-11 13:45:28 +0200
committerSimon Hausmann <simon.hausmann@nokia.com>2012-07-11 13:45:28 +0200
commitd6a599dbc9d824a462b2b206316e102bf8136446 (patch)
treeecb257a5e55b2239d74b90fdad62fccd661cf286 /Source/JavaScriptCore/dfg
parent3ccc3a85f09a83557b391aae380d3bf5f81a2911 (diff)
downloadqtwebkit-d6a599dbc9d824a462b2b206316e102bf8136446.tar.gz
Imported WebKit commit 8ff1f22783a32de82fee915abd55bd1b298f2644 (http://svn.webkit.org/repository/webkit/trunk@122325)
New snapshot that should work with the latest Qt build system changes
Diffstat (limited to 'Source/JavaScriptCore/dfg')
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractState.cpp137
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractState.h17
-rw-r--r--Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp26
-rw-r--r--Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h2
-rw-r--r--Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp66
-rw-r--r--Source/JavaScriptCore/dfg/DFGCCallHelpers.h4
-rw-r--r--Source/JavaScriptCore/dfg/DFGCFAPhase.cpp1
-rw-r--r--Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp3
-rw-r--r--Source/JavaScriptCore/dfg/DFGCSEPhase.cpp1
-rw-r--r--Source/JavaScriptCore/dfg/DFGCapabilities.h16
-rw-r--r--Source/JavaScriptCore/dfg/DFGCommon.h2
-rw-r--r--Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp1
-rw-r--r--Source/JavaScriptCore/dfg/DFGDisassembler.cpp4
-rw-r--r--Source/JavaScriptCore/dfg/DFGDriver.cpp6
-rw-r--r--Source/JavaScriptCore/dfg/DFGFPRInfo.h2
-rw-r--r--Source/JavaScriptCore/dfg/DFGFixupPhase.cpp1
-rw-r--r--Source/JavaScriptCore/dfg/DFGGPRInfo.h4
-rw-r--r--Source/JavaScriptCore/dfg/DFGGenerationInfo.h107
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.cpp3
-rw-r--r--Source/JavaScriptCore/dfg/DFGJITCompiler.cpp8
-rw-r--r--Source/JavaScriptCore/dfg/DFGJITCompiler.h4
-rw-r--r--Source/JavaScriptCore/dfg/DFGMinifiedGraph.h81
-rw-r--r--Source/JavaScriptCore/dfg/DFGMinifiedNode.cpp57
-rw-r--r--Source/JavaScriptCore/dfg/DFGMinifiedNode.h129
-rw-r--r--Source/JavaScriptCore/dfg/DFGNode.h19
-rw-r--r--Source/JavaScriptCore/dfg/DFGOSRExit.cpp30
-rw-r--r--Source/JavaScriptCore/dfg/DFGOSRExit.h42
-rw-r--r--Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp61
-rw-r--r--Source/JavaScriptCore/dfg/DFGOSRExitCompiler.h2
-rw-r--r--Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp117
-rw-r--r--Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp93
-rw-r--r--Source/JavaScriptCore/dfg/DFGOperations.cpp73
-rw-r--r--Source/JavaScriptCore/dfg/DFGPhase.h17
-rw-r--r--Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp1
-rw-r--r--Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.cpp1
-rw-r--r--Source/JavaScriptCore/dfg/DFGRepatch.cpp180
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp278
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h129
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp135
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp160
-rw-r--r--Source/JavaScriptCore/dfg/DFGValueRecoveryOverride.h57
-rw-r--r--Source/JavaScriptCore/dfg/DFGValueSource.cpp69
-rw-r--r--Source/JavaScriptCore/dfg/DFGValueSource.h225
-rw-r--r--Source/JavaScriptCore/dfg/DFGVariableAccessData.h2
-rw-r--r--Source/JavaScriptCore/dfg/DFGVariableEvent.cpp91
-rw-r--r--Source/JavaScriptCore/dfg/DFGVariableEvent.h270
-rw-r--r--Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp286
-rw-r--r--Source/JavaScriptCore/dfg/DFGVariableEventStream.h64
-rw-r--r--Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp1
49 files changed, 2226 insertions, 859 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index c2d49f7ee..4cd31f2a8 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -311,31 +311,35 @@ bool AbstractState::execute(unsigned indexInBlock)
if (left && right && left.isInt32() && right.isInt32()) {
int32_t a = left.asInt32();
int32_t b = right.asInt32();
+ bool constantWasSet;
switch (node.op()) {
case BitAnd:
- forNode(nodeIndex).set(JSValue(a & b));
+ constantWasSet = trySetConstant(nodeIndex, JSValue(a & b));
break;
case BitOr:
- forNode(nodeIndex).set(JSValue(a | b));
+ constantWasSet = trySetConstant(nodeIndex, JSValue(a | b));
break;
case BitXor:
- forNode(nodeIndex).set(JSValue(a ^ b));
+ constantWasSet = trySetConstant(nodeIndex, JSValue(a ^ b));
break;
case BitRShift:
- forNode(nodeIndex).set(JSValue(a >> static_cast<uint32_t>(b)));
+ constantWasSet = trySetConstant(nodeIndex, JSValue(a >> static_cast<uint32_t>(b)));
break;
case BitLShift:
- forNode(nodeIndex).set(JSValue(a << static_cast<uint32_t>(b)));
+ constantWasSet = trySetConstant(nodeIndex, JSValue(a << static_cast<uint32_t>(b)));
break;
case BitURShift:
- forNode(nodeIndex).set(JSValue(static_cast<uint32_t>(a) >> static_cast<uint32_t>(b)));
+ constantWasSet = trySetConstant(nodeIndex, JSValue(static_cast<uint32_t>(a) >> static_cast<uint32_t>(b)));
break;
default:
ASSERT_NOT_REACHED();
+ constantWasSet = false;
+ }
+ if (constantWasSet) {
+ m_foundConstants = true;
+ node.setCanExit(false);
+ break;
}
- m_foundConstants = true;
- node.setCanExit(false);
- break;
}
speculateInt32Binary(node);
forNode(nodeIndex).set(SpecInt32);
@@ -346,10 +350,11 @@ bool AbstractState::execute(unsigned indexInBlock)
JSValue child = forNode(node.child1()).value();
if (child && child.isNumber()) {
ASSERT(child.isInt32());
- forNode(nodeIndex).set(JSValue(child.asUInt32()));
- m_foundConstants = true;
- node.setCanExit(false);
- break;
+ if (trySetConstant(nodeIndex, JSValue(child.asUInt32()))) {
+ m_foundConstants = true;
+ node.setCanExit(false);
+ break;
+ }
}
if (!node.canSpeculateInteger()) {
forNode(nodeIndex).set(SpecDouble);
@@ -367,8 +372,8 @@ bool AbstractState::execute(unsigned indexInBlock)
if (child && child.isNumber()) {
double asDouble = child.asNumber();
int32_t asInt = JSC::toInt32(asDouble);
- if (bitwise_cast<int64_t>(static_cast<double>(asInt)) == bitwise_cast<int64_t>(asDouble)) {
- forNode(nodeIndex).set(JSValue(asInt));
+ if (bitwise_cast<int64_t>(static_cast<double>(asInt)) == bitwise_cast<int64_t>(asDouble)
+ && trySetConstant(nodeIndex, JSValue(asInt))) {
m_foundConstants = true;
break;
}
@@ -382,13 +387,16 @@ bool AbstractState::execute(unsigned indexInBlock)
case ValueToInt32: {
JSValue child = forNode(node.child1()).value();
if (child && child.isNumber()) {
+ bool constantWasSet;
if (child.isInt32())
- forNode(nodeIndex).set(child);
+ constantWasSet = trySetConstant(nodeIndex, child);
else
- forNode(nodeIndex).set(JSValue(JSC::toInt32(child.asDouble())));
- m_foundConstants = true;
- node.setCanExit(false);
- break;
+ constantWasSet = trySetConstant(nodeIndex, JSValue(JSC::toInt32(child.asDouble())));
+ if (constantWasSet) {
+ m_foundConstants = true;
+ node.setCanExit(false);
+ break;
+ }
}
if (m_graph[node.child1()].shouldSpeculateInteger())
speculateInt32Unary(node);
@@ -405,8 +413,8 @@ bool AbstractState::execute(unsigned indexInBlock)
case Int32ToDouble: {
JSValue child = forNode(node.child1()).value();
- if (child && child.isNumber()) {
- forNode(nodeIndex).set(JSValue(JSValue::EncodeAsDouble, child.asNumber()));
+ if (child && child.isNumber()
+ && trySetConstant(nodeIndex, JSValue(JSValue::EncodeAsDouble, child.asNumber()))) {
m_foundConstants = true;
node.setCanExit(false);
break;
@@ -424,8 +432,8 @@ bool AbstractState::execute(unsigned indexInBlock)
case ArithAdd: {
JSValue left = forNode(node.child1()).value();
JSValue right = forNode(node.child2()).value();
- if (left && right && left.isNumber() && right.isNumber()) {
- forNode(nodeIndex).set(JSValue(left.asNumber() + right.asNumber()));
+ if (left && right && left.isNumber() && right.isNumber()
+ && trySetConstant(nodeIndex, JSValue(left.asNumber() + right.asNumber()))) {
m_foundConstants = true;
node.setCanExit(false);
break;
@@ -456,8 +464,8 @@ bool AbstractState::execute(unsigned indexInBlock)
case ArithSub: {
JSValue left = forNode(node.child1()).value();
JSValue right = forNode(node.child2()).value();
- if (left && right && left.isNumber() && right.isNumber()) {
- forNode(nodeIndex).set(JSValue(left.asNumber() - right.asNumber()));
+ if (left && right && left.isNumber() && right.isNumber()
+ && trySetConstant(nodeIndex, JSValue(left.asNumber() - right.asNumber()))) {
m_foundConstants = true;
node.setCanExit(false);
break;
@@ -475,8 +483,8 @@ bool AbstractState::execute(unsigned indexInBlock)
case ArithNegate: {
JSValue child = forNode(node.child1()).value();
- if (child && child.isNumber()) {
- forNode(nodeIndex).set(JSValue(-child.asNumber()));
+ if (child && child.isNumber()
+ && trySetConstant(nodeIndex, JSValue(-child.asNumber()))) {
m_foundConstants = true;
node.setCanExit(false);
break;
@@ -495,8 +503,8 @@ bool AbstractState::execute(unsigned indexInBlock)
case ArithMul: {
JSValue left = forNode(node.child1()).value();
JSValue right = forNode(node.child2()).value();
- if (left && right && left.isNumber() && right.isNumber()) {
- forNode(nodeIndex).set(JSValue(left.asNumber() * right.asNumber()));
+ if (left && right && left.isNumber() && right.isNumber()
+ && trySetConstant(nodeIndex, JSValue(left.asNumber() * right.asNumber()))) {
m_foundConstants = true;
node.setCanExit(false);
break;
@@ -523,26 +531,30 @@ bool AbstractState::execute(unsigned indexInBlock)
if (left && right && left.isNumber() && right.isNumber()) {
double a = left.asNumber();
double b = right.asNumber();
+ bool constantWasSet;
switch (node.op()) {
case ArithDiv:
- forNode(nodeIndex).set(JSValue(a / b));
+ constantWasSet = trySetConstant(nodeIndex, JSValue(a / b));
break;
case ArithMin:
- forNode(nodeIndex).set(JSValue(a < b ? a : (b <= a ? b : a + b)));
+ constantWasSet = trySetConstant(nodeIndex, JSValue(a < b ? a : (b <= a ? b : a + b)));
break;
case ArithMax:
- forNode(nodeIndex).set(JSValue(a > b ? a : (b >= a ? b : a + b)));
+ constantWasSet = trySetConstant(nodeIndex, JSValue(a > b ? a : (b >= a ? b : a + b)));
break;
case ArithMod:
- forNode(nodeIndex).set(JSValue(fmod(a, b)));
+ constantWasSet = trySetConstant(nodeIndex, JSValue(fmod(a, b)));
break;
default:
ASSERT_NOT_REACHED();
+ constantWasSet = false;
+ break;
+ }
+ if (constantWasSet) {
+ m_foundConstants = true;
+ node.setCanExit(false);
break;
}
- m_foundConstants = true;
- node.setCanExit(false);
- break;
}
if (Node::shouldSpeculateInteger(
m_graph[node.child1()], m_graph[node.child2()])
@@ -558,8 +570,8 @@ bool AbstractState::execute(unsigned indexInBlock)
case ArithAbs: {
JSValue child = forNode(node.child1()).value();
- if (child && child.isNumber()) {
- forNode(nodeIndex).set(JSValue(fabs(child.asNumber())));
+ if (child && child.isNumber()
+ && trySetConstant(nodeIndex, JSValue(fabs(child.asNumber())))) {
m_foundConstants = true;
node.setCanExit(false);
break;
@@ -577,8 +589,8 @@ bool AbstractState::execute(unsigned indexInBlock)
case ArithSqrt: {
JSValue child = forNode(node.child1()).value();
- if (child && child.isNumber()) {
- forNode(nodeIndex).set(JSValue(sqrt(child.asNumber())));
+ if (child && child.isNumber()
+ && trySetConstant(nodeIndex, JSValue(sqrt(child.asNumber())))) {
m_foundConstants = true;
node.setCanExit(false);
break;
@@ -590,8 +602,7 @@ bool AbstractState::execute(unsigned indexInBlock)
case LogicalNot: {
JSValue childConst = forNode(node.child1()).value();
- if (childConst) {
- forNode(nodeIndex).set(jsBoolean(!childConst.toBoolean()));
+ if (childConst && trySetConstant(nodeIndex, jsBoolean(!childConst.toBoolean()))) {
m_foundConstants = true;
node.setCanExit(false);
break;
@@ -626,27 +637,28 @@ bool AbstractState::execute(unsigned indexInBlock)
node.setCanExit(false);
JSValue child = forNode(node.child1()).value();
if (child) {
- bool foundConstant = true;
+ bool constantWasSet;
switch (node.op()) {
case IsUndefined:
- forNode(nodeIndex).set(jsBoolean(
+ constantWasSet = trySetConstant(nodeIndex, jsBoolean(
child.isCell()
? child.asCell()->structure()->typeInfo().masqueradesAsUndefined()
: child.isUndefined()));
break;
case IsBoolean:
- forNode(nodeIndex).set(jsBoolean(child.isBoolean()));
+ constantWasSet = trySetConstant(nodeIndex, jsBoolean(child.isBoolean()));
break;
case IsNumber:
- forNode(nodeIndex).set(jsBoolean(child.isNumber()));
+ constantWasSet = trySetConstant(nodeIndex, jsBoolean(child.isNumber()));
break;
case IsString:
- forNode(nodeIndex).set(jsBoolean(isJSString(child)));
+ constantWasSet = trySetConstant(nodeIndex, jsBoolean(isJSString(child)));
break;
default:
+ constantWasSet = false;
break;
}
- if (foundConstant) {
+ if (constantWasSet) {
m_foundConstants = true;
break;
}
@@ -665,29 +677,33 @@ bool AbstractState::execute(unsigned indexInBlock)
if (leftConst && rightConst && leftConst.isNumber() && rightConst.isNumber()) {
double a = leftConst.asNumber();
double b = rightConst.asNumber();
+ bool constantWasSet;
switch (node.op()) {
case CompareLess:
- forNode(nodeIndex).set(jsBoolean(a < b));
+ constantWasSet = trySetConstant(nodeIndex, jsBoolean(a < b));
break;
case CompareLessEq:
- forNode(nodeIndex).set(jsBoolean(a <= b));
+ constantWasSet = trySetConstant(nodeIndex, jsBoolean(a <= b));
break;
case CompareGreater:
- forNode(nodeIndex).set(jsBoolean(a > b));
+ constantWasSet = trySetConstant(nodeIndex, jsBoolean(a > b));
break;
case CompareGreaterEq:
- forNode(nodeIndex).set(jsBoolean(a >= b));
+ constantWasSet = trySetConstant(nodeIndex, jsBoolean(a >= b));
break;
case CompareEq:
- forNode(nodeIndex).set(jsBoolean(a == b));
+ constantWasSet = trySetConstant(nodeIndex, jsBoolean(a == b));
break;
default:
ASSERT_NOT_REACHED();
+ constantWasSet = false;
+ break;
+ }
+ if (constantWasSet) {
+ m_foundConstants = true;
+ node.setCanExit(false);
break;
}
- m_foundConstants = true;
- node.setCanExit(false);
- break;
}
forNode(nodeIndex).set(SpecBoolean);
@@ -767,8 +783,8 @@ bool AbstractState::execute(unsigned indexInBlock)
case CompareStrictEq: {
JSValue left = forNode(node.child1()).value();
JSValue right = forNode(node.child2()).value();
- if (left && right && left.isNumber() && right.isNumber()) {
- forNode(nodeIndex).set(jsBoolean(left.asNumber() == right.asNumber()));
+ if (left && right && left.isNumber() && right.isNumber()
+ && trySetConstant(nodeIndex, jsBoolean(left.asNumber() == right.asNumber()))) {
m_foundConstants = true;
node.setCanExit(false);
break;
@@ -1106,8 +1122,7 @@ bool AbstractState::execute(unsigned indexInBlock)
case ToPrimitive: {
JSValue childConst = forNode(node.child1()).value();
- if (childConst && childConst.isNumber()) {
- forNode(nodeIndex).set(childConst);
+ if (childConst && childConst.isNumber() && trySetConstant(nodeIndex, childConst)) {
m_foundConstants = true;
node.setCanExit(false);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.h b/Source/JavaScriptCore/dfg/DFGAbstractState.h
index 9bb74cd86..95cadecbb 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.h
@@ -267,6 +267,23 @@ private:
childValue2.filter(SpecNumber);
}
+ bool trySetConstant(NodeIndex nodeIndex, JSValue value)
+ {
+ // Make sure we don't constant fold something that will produce values that contravene
+ // predictions. If that happens then we know that the code will OSR exit, forcing
+ // recompilation. But if we tried to constant fold then we'll have a very degenerate
+ // IR: namely we'll have a JSConstant that contravenes its own prediction. There's a
+ // lot of subtle code that assumes that
+ // speculationFromValue(jsConstant) == jsConstant.prediction(). "Hardening" that code
+ // is probably less sane than just pulling back on constant folding.
+ SpeculatedType oldType = m_graph[nodeIndex].prediction();
+ if (mergeSpeculations(speculationFromValue(value), oldType) != oldType)
+ return false;
+
+ forNode(nodeIndex).set(value);
+ return true;
+ }
+
CodeBlock* m_codeBlock;
Graph& m_graph;
diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
index 28e686aef..9208cde1b 100644
--- a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
@@ -627,8 +627,9 @@ public:
continue;
// If this is a CreateArguments for an InlineCallFrame* that does
// not create arguments, then replace it with a PhantomArguments.
- // PhantomArguments is a constant that represents JSValue() (the
- // empty value) in DFG and arguments creation for OSR exit.
+ // PhantomArguments is a non-executing node that just indicates
+ // that the node should be reified as an arguments object on OSR
+ // exit.
if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame))
continue;
if (node.shouldGenerate()) {
@@ -641,12 +642,30 @@ public:
}
node.setOpAndDefaultFlags(PhantomArguments);
node.children.reset();
+ changed = true;
}
insertionSet.execute(*block);
}
- if (changed)
+ if (changed) {
m_graph.collectGarbage();
+
+ // Verify that PhantomArguments nodes are not shouldGenerate().
+#if !ASSERT_DISABLED
+ for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
+ BasicBlock* block = m_graph.m_blocks[blockIndex].get();
+ if (!block)
+ continue;
+ for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
+ NodeIndex nodeIndex = block->at(indexInBlock);
+ Node& node = m_graph[nodeIndex];
+ if (node.op() != PhantomArguments)
+ continue;
+ ASSERT(!node.shouldGenerate());
+ }
+ }
+#endif
+ }
return changed;
}
@@ -815,6 +834,7 @@ private:
bool performArgumentsSimplification(Graph& graph)
{
+ SamplingRegion samplingRegion("DFG Arguments Simplification Phase");
return runPhase<ArgumentsSimplificationPhase>(graph);
}
diff --git a/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h b/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h
index f86c15e65..4bea292f3 100644
--- a/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h
+++ b/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h
@@ -182,7 +182,7 @@ public:
move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::regT0);
storePtr(TrustedImmPtr(scratchSize), GPRInfo::regT0);
-#if CPU(X86_64) || CPU(ARM_THUMB2)
+#if CPU(X86_64) || CPU(ARM)
move(TrustedImmPtr(argument), GPRInfo::argumentGPR1);
move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
GPRReg scratch = selectScratchGPR(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1);
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index cdb0b639a..91b882399 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -99,7 +99,7 @@ private:
bool handleConstantInternalFunction(bool usesResult, int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, CodeSpecializationKind);
void handleGetByOffset(
int destinationOperand, SpeculatedType, NodeIndex base, unsigned identifierNumber,
- bool useInlineStorage, size_t offset);
+ PropertyOffset);
void handleGetById(
int destinationOperand, SpeculatedType, NodeIndex base, unsigned identifierNumber,
const GetByIdStatus&);
@@ -871,7 +871,7 @@ private:
// care about when the outcome of the division is not an integer, which
// is what the special fast case counter tells us.
- if (!m_inlineStackTop->m_profiledBlock->likelyToTakeSpecialFastCase(m_currentIndex)
+ if (!m_inlineStackTop->m_profiledBlock->couldTakeSpecialFastCase(m_currentIndex)
&& !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow)
&& !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero))
return nodeIndex;
@@ -1273,7 +1273,7 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c
unsigned depth = 0;
for (InlineStackEntry* entry = m_inlineStackTop; entry; entry = entry->m_caller) {
++depth;
- if (depth >= Options::maximumInliningDepth)
+ if (depth >= Options::maximumInliningDepth())
return false; // Depth exceeded.
if (entry->executable() == executable)
@@ -1630,25 +1630,20 @@ bool ByteCodeParser::handleConstantInternalFunction(
void ByteCodeParser::handleGetByOffset(
int destinationOperand, SpeculatedType prediction, NodeIndex base, unsigned identifierNumber,
- bool useInlineStorage, size_t offset)
+ PropertyOffset offset)
{
NodeIndex propertyStorage;
- size_t offsetOffset;
- if (useInlineStorage) {
+ if (isInlineOffset(offset))
propertyStorage = base;
- ASSERT(!(sizeof(JSObject) % sizeof(EncodedJSValue)));
- offsetOffset = sizeof(JSObject) / sizeof(EncodedJSValue);
- } else {
+ else
propertyStorage = addToGraph(GetPropertyStorage, base);
- offsetOffset = 0;
- }
set(destinationOperand,
addToGraph(
GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction),
propertyStorage));
StorageAccessData storageAccessData;
- storageAccessData.offset = offset + offsetOffset;
+ storageAccessData.offset = indexRelativeToBase(offset);
storageAccessData.identifierNumber = identifierNumber;
m_graph.m_storageAccessData.append(storageAccessData);
}
@@ -1677,7 +1672,6 @@ void ByteCodeParser::handleGetById(
addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(getByIdStatus.structureSet())), base);
- bool useInlineStorage;
if (!getByIdStatus.chain().isEmpty()) {
Structure* currentStructure = getByIdStatus.structureSet().singletonStructure();
JSObject* currentObject = 0;
@@ -1686,9 +1680,7 @@ void ByteCodeParser::handleGetById(
currentStructure = getByIdStatus.chain()[i];
base = addStructureTransitionCheck(currentObject, currentStructure);
}
- useInlineStorage = currentStructure->isUsingInlineStorage();
- } else
- useInlineStorage = getByIdStatus.structureSet().allAreUsingInlinePropertyStorage();
+ }
// Unless we want bugs like https://bugs.webkit.org/show_bug.cgi?id=88783, we need to
// ensure that the base of the original get_by_id is kept alive until we're done with
@@ -1707,8 +1699,7 @@ void ByteCodeParser::handleGetById(
}
handleGetByOffset(
- destinationOperand, prediction, base, identifierNumber, useInlineStorage,
- getByIdStatus.offset());
+ destinationOperand, prediction, base, identifierNumber, getByIdStatus.offset());
}
void ByteCodeParser::prepareToParseBlock()
@@ -2172,7 +2163,8 @@ bool ByteCodeParser::parseBlock(unsigned limit)
SpeculatedType prediction = getPrediction();
- ASSERT(interpreter->getOpcodeID(getInstruction->u.opcode) == op_get_by_id);
+ ASSERT(interpreter->getOpcodeID(getInstruction->u.opcode) == op_get_by_id
+ || interpreter->getOpcodeID(getInstruction->u.opcode) == op_get_by_id_out_of_line);
NodeIndex base = get(getInstruction[2].u.operand);
unsigned identifier = m_inlineStackTop->m_identifierRemap[getInstruction[3].u.operand];
@@ -2225,7 +2217,8 @@ bool ByteCodeParser::parseBlock(unsigned limit)
addToGraph(PutScopedVar, OpInfo(slot), getScopeChain, get(source));
NEXT_OPCODE(op_put_scoped_var);
}
- case op_get_by_id: {
+ case op_get_by_id:
+ case op_get_by_id_out_of_line: {
SpeculatedType prediction = getPredictionWithoutOSRExit();
NodeIndex base = get(currentInstruction[2].u.operand);
@@ -2241,8 +2234,11 @@ bool ByteCodeParser::parseBlock(unsigned limit)
NEXT_OPCODE(op_get_by_id);
}
case op_put_by_id:
+ case op_put_by_id_out_of_line:
case op_put_by_id_transition_direct:
- case op_put_by_id_transition_normal: {
+ case op_put_by_id_transition_normal:
+ case op_put_by_id_transition_direct_out_of_line:
+ case op_put_by_id_transition_normal_out_of_line: {
NodeIndex value = get(currentInstruction[3].u.operand);
NodeIndex base = get(currentInstruction[1].u.operand);
unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand];
@@ -2259,25 +2255,20 @@ bool ByteCodeParser::parseBlock(unsigned limit)
if (!hasExitSite && putByIdStatus.isSimpleReplace()) {
addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(putByIdStatus.oldStructure())), base);
- size_t offsetOffset;
NodeIndex propertyStorage;
- if (putByIdStatus.oldStructure()->isUsingInlineStorage()) {
+ if (isInlineOffset(putByIdStatus.offset()))
propertyStorage = base;
- ASSERT(!(sizeof(JSObject) % sizeof(EncodedJSValue)));
- offsetOffset = sizeof(JSObject) / sizeof(EncodedJSValue);
- } else {
+ else
propertyStorage = addToGraph(GetPropertyStorage, base);
- offsetOffset = 0;
- }
addToGraph(PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), propertyStorage, base, value);
StorageAccessData storageAccessData;
- storageAccessData.offset = putByIdStatus.offset() + offsetOffset;
+ storageAccessData.offset = indexRelativeToBase(putByIdStatus.offset());
storageAccessData.identifierNumber = identifierNumber;
m_graph.m_storageAccessData.append(storageAccessData);
} else if (!hasExitSite
&& putByIdStatus.isSimpleTransition()
- && putByIdStatus.oldStructure()->propertyStorageCapacity() == putByIdStatus.newStructure()->propertyStorageCapacity()
+ && putByIdStatus.oldStructure()->outOfLineCapacity() == putByIdStatus.newStructure()->outOfLineCapacity()
&& structureChainIsStillValid(
direct,
putByIdStatus.oldStructure(),
@@ -2308,16 +2299,11 @@ bool ByteCodeParser::parseBlock(unsigned limit)
putByIdStatus.newStructure()))),
base);
- size_t offsetOffset;
NodeIndex propertyStorage;
- if (putByIdStatus.newStructure()->isUsingInlineStorage()) {
+ if (isInlineOffset(putByIdStatus.offset()))
propertyStorage = base;
- ASSERT(!(sizeof(JSObject) % sizeof(EncodedJSValue)));
- offsetOffset = sizeof(JSObject) / sizeof(EncodedJSValue);
- } else {
+ else
propertyStorage = addToGraph(GetPropertyStorage, base);
- offsetOffset = 0;
- }
addToGraph(
PutByOffset,
OpInfo(m_graph.m_storageAccessData.size()),
@@ -2326,7 +2312,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
value);
StorageAccessData storageAccessData;
- storageAccessData.offset = putByIdStatus.offset() + offsetOffset;
+ storageAccessData.offset = indexRelativeToBase(putByIdStatus.offset());
storageAccessData.identifierNumber = identifierNumber;
m_graph.m_storageAccessData.append(storageAccessData);
} else {
@@ -2738,8 +2724,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
} else {
handleGetByOffset(
currentInstruction[1].u.operand, prediction, globalObject,
- identifierNumber, status.structure()->isUsingInlineStorage(),
- status.offset());
+ identifierNumber, status.offset());
}
m_globalResolveNumber++; // Skip over the unused global resolve info.
@@ -3341,6 +3326,7 @@ bool ByteCodeParser::parse()
bool parse(ExecState* exec, Graph& graph)
{
+ SamplingRegion samplingRegion("DFG Parsing");
#if DFG_DEBUG_LOCAL_DISBALE
UNUSED_PARAM(exec);
UNUSED_PARAM(graph);
diff --git a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
index b60290870..9c1718bdb 100644
--- a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
+++ b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
@@ -434,7 +434,7 @@ public:
{
setupTwoStubArgs<FPRInfo::argumentFPR0, FPRInfo::argumentFPR1>(arg1, arg2);
}
-#else
+#elif CPU(ARM)
ALWAYS_INLINE void setupArguments(FPRReg arg1)
{
assembler().vmov(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, arg1);
@@ -445,6 +445,8 @@ public:
assembler().vmov(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, arg1);
assembler().vmov(GPRInfo::argumentGPR2, GPRInfo::argumentGPR3, arg2);
}
+#else
+#error "DFG JIT not supported on this platform."
#endif
ALWAYS_INLINE void setupArguments(GPRReg arg1)
diff --git a/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp
index c6042448a..c52349645 100644
--- a/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp
@@ -132,6 +132,7 @@ private:
bool performCFA(Graph& graph)
{
+ SamplingRegion samplingRegion("DFG CFA Phase");
return runPhase<CFAPhase>(graph);
}
diff --git a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
index 161f51e30..c234e6e4e 100644
--- a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
@@ -613,7 +613,7 @@ private:
ASSERT(node.shouldGenerate());
Node& possibleLocalOp = m_graph[node.child1()];
- if (possibleLocalOp.hasLocal()) {
+ if (possibleLocalOp.hasLocal() && !possibleLocalOp.variableAccessData()->isCaptured()) {
NodeIndex setLocalIndex =
firstBlock->variablesAtTail.operand(possibleLocalOp.local());
Node& setLocal = m_graph[setLocalIndex];
@@ -745,6 +745,7 @@ private:
bool performCFGSimplification(Graph& graph)
{
+ SamplingRegion samplingRegion("DFG CFG Simplification Phase");
return runPhase<CFGSimplificationPhase>(graph);
}
diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
index be0012f56..108cf1965 100644
--- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
@@ -1172,6 +1172,7 @@ private:
bool performCSE(Graph& graph, OptimizationFixpointState fixpointState)
{
+ SamplingRegion samplingRegion("DFG CSE Phase");
return runPhase<CSEPhase>(graph, fixpointState);
}
diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.h b/Source/JavaScriptCore/dfg/DFGCapabilities.h
index 1aec0bca1..2bc9b2965 100644
--- a/Source/JavaScriptCore/dfg/DFGCapabilities.h
+++ b/Source/JavaScriptCore/dfg/DFGCapabilities.h
@@ -41,29 +41,29 @@ namespace JSC { namespace DFG {
// check opcodes.
inline bool mightCompileEval(CodeBlock* codeBlock)
{
- return codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount;
+ return codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
}
inline bool mightCompileProgram(CodeBlock* codeBlock)
{
- return codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount;
+ return codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
}
inline bool mightCompileFunctionForCall(CodeBlock* codeBlock)
{
- return codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount;
+ return codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
}
inline bool mightCompileFunctionForConstruct(CodeBlock* codeBlock)
{
- return codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount;
+ return codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
}
inline bool mightInlineFunctionForCall(CodeBlock* codeBlock)
{
- return codeBlock->instructionCount() <= Options::maximumFunctionForCallInlineCandidateInstructionCount
+ return codeBlock->instructionCount() <= Options::maximumFunctionForCallInlineCandidateInstructionCount()
&& !codeBlock->ownerExecutable()->needsActivation();
}
inline bool mightInlineFunctionForConstruct(CodeBlock* codeBlock)
{
- return codeBlock->instructionCount() <= Options::maximumFunctionForConstructInlineCandidateInstructionCount
+ return codeBlock->instructionCount() <= Options::maximumFunctionForConstructInlineCandidateInstructionCount()
&& !codeBlock->ownerExecutable()->needsActivation();
}
@@ -119,9 +119,13 @@ inline CapabilityLevel canCompileOpcode(OpcodeID opcodeID, CodeBlock*, Instructi
case op_get_scoped_var:
case op_put_scoped_var:
case op_get_by_id:
+ case op_get_by_id_out_of_line:
case op_put_by_id:
+ case op_put_by_id_out_of_line:
case op_put_by_id_transition_direct:
+ case op_put_by_id_transition_direct_out_of_line:
case op_put_by_id_transition_normal:
+ case op_put_by_id_transition_normal_out_of_line:
case op_get_global_var:
case op_get_global_var_watchable:
case op_put_global_var:
diff --git a/Source/JavaScriptCore/dfg/DFGCommon.h b/Source/JavaScriptCore/dfg/DFGCommon.h
index c9d3cbc32..1a64a248c 100644
--- a/Source/JavaScriptCore/dfg/DFGCommon.h
+++ b/Source/JavaScriptCore/dfg/DFGCommon.h
@@ -136,7 +136,7 @@ enum OptimizationFixpointState { FixpointConverged, FixpointNotConverged };
inline bool shouldShowDisassembly()
{
- return Options::showDisassembly || Options::showDFGDisassembly;
+ return Options::showDisassembly() || Options::showDFGDisassembly();
}
} } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
index 9e6720c80..d3029b39a 100644
--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
@@ -159,6 +159,7 @@ public:
bool performConstantFolding(Graph& graph)
{
+ SamplingRegion samplingRegion("DFG Constant Folding Phase");
return runPhase<ConstantFoldingPhase>(graph);
}
diff --git a/Source/JavaScriptCore/dfg/DFGDisassembler.cpp b/Source/JavaScriptCore/dfg/DFGDisassembler.cpp
index 1dde37cf2..cfbb936b8 100644
--- a/Source/JavaScriptCore/dfg/DFGDisassembler.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDisassembler.cpp
@@ -43,7 +43,7 @@ void Disassembler::dump(LinkBuffer& linkBuffer)
{
m_graph.m_dominators.computeIfNecessary(m_graph);
- dataLog("Generated JIT code for DFG CodeBlock %p:\n", m_graph.m_codeBlock);
+ dataLog("Generated JIT code for DFG CodeBlock %p, instruction count = %u:\n", m_graph.m_codeBlock, m_graph.m_codeBlock->instructionCount());
dataLog(" Code at [%p, %p):\n", linkBuffer.debugAddress(), static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize());
const char* prefix = " ";
@@ -59,7 +59,7 @@ void Disassembler::dump(LinkBuffer& linkBuffer)
m_graph.dumpBlockHeader(prefix, blockIndex, Graph::DumpLivePhisOnly);
NodeIndex lastNodeIndexForDisassembly = block->at(0);
for (size_t i = 0; i < block->size(); ++i) {
- if (!m_graph[block->at(i)].willHaveCodeGen())
+ if (!m_graph[block->at(i)].willHaveCodeGenOrOSR())
continue;
MacroAssembler::Label currentLabel;
if (m_labelForNodeIndex[block->at(i)].isSet())
diff --git a/Source/JavaScriptCore/dfg/DFGDriver.cpp b/Source/JavaScriptCore/dfg/DFGDriver.cpp
index 5033aa2c0..64fc0c7e5 100644
--- a/Source/JavaScriptCore/dfg/DFGDriver.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDriver.cpp
@@ -40,6 +40,7 @@
#include "DFGRedundantPhiEliminationPhase.h"
#include "DFGValidate.h"
#include "DFGVirtualRegisterAllocationPhase.h"
+#include "Options.h"
namespace JSC { namespace DFG {
@@ -60,7 +61,10 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo
ASSERT(codeBlock);
ASSERT(codeBlock->alternative());
ASSERT(codeBlock->alternative()->getJITType() == JITCode::BaselineJIT);
-
+
+ if (!Options::useDFGJIT())
+ return false;
+
#if DFG_ENABLE(DEBUG_VERBOSE)
dataLog("DFG compiling code block %p(%p) for executable %p, number of instructions = %u.\n", codeBlock, codeBlock->alternative(), codeBlock->ownerExecutable(), codeBlock->instructionCount());
#endif
diff --git a/Source/JavaScriptCore/dfg/DFGFPRInfo.h b/Source/JavaScriptCore/dfg/DFGFPRInfo.h
index 6af45dd81..e817ed396 100644
--- a/Source/JavaScriptCore/dfg/DFGFPRInfo.h
+++ b/Source/JavaScriptCore/dfg/DFGFPRInfo.h
@@ -102,7 +102,7 @@ public:
#endif
-#if CPU(ARM_THUMB2)
+#if CPU(ARM)
class FPRInfo {
public:
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index f6e3c0a96..2e7389f21 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -402,6 +402,7 @@ private:
bool performFixup(Graph& graph)
{
+ SamplingRegion samplingRegion("DFG Fixup Phase");
return runPhase<FixupPhase>(graph);
}
diff --git a/Source/JavaScriptCore/dfg/DFGGPRInfo.h b/Source/JavaScriptCore/dfg/DFGGPRInfo.h
index bd4fa32d1..89faef94b 100644
--- a/Source/JavaScriptCore/dfg/DFGGPRInfo.h
+++ b/Source/JavaScriptCore/dfg/DFGGPRInfo.h
@@ -384,7 +384,7 @@ private:
#endif
-#if CPU(ARM_THUMB2)
+#if CPU(ARM)
#define NUMBER_OF_ARGUMENT_REGISTERS 4
class GPRInfo {
@@ -410,7 +410,7 @@ public:
static const GPRReg argumentGPR1 = ARMRegisters::r1; // regT1
static const GPRReg argumentGPR2 = ARMRegisters::r2; // regT2
// FIXME: r3 is currently used be the MacroAssembler as a temporary - it seems
- // This could threoretically be a problem if theis is used in code generation
+ // This could threoretically be a problem if this is used in code generation
// between the arguments being set up, and the call being made. That said,
// any change introducing a problem here is likely to be immediately apparent!
static const GPRReg argumentGPR3 = ARMRegisters::r3; // FIXME!
diff --git a/Source/JavaScriptCore/dfg/DFGGenerationInfo.h b/Source/JavaScriptCore/dfg/DFGGenerationInfo.h
index 125a5a4f9..905c5c5fb 100644
--- a/Source/JavaScriptCore/dfg/DFGGenerationInfo.h
+++ b/Source/JavaScriptCore/dfg/DFGGenerationInfo.h
@@ -29,8 +29,10 @@
#if ENABLE(DFG_JIT)
+#include "DFGJITCompiler.h"
+#include "DFGVariableEvent.h"
+#include "DFGVariableEventStream.h"
#include "DataFormat.h"
-#include <dfg/DFGJITCompiler.h>
namespace JSC { namespace DFG {
@@ -51,6 +53,7 @@ public:
, m_registerFormat(DataFormatNone)
, m_spillFormat(DataFormatNone)
, m_canFill(false)
+ , m_bornForOSR(false)
{
}
@@ -61,6 +64,7 @@ public:
m_registerFormat = DataFormatNone;
m_spillFormat = DataFormatNone;
m_canFill = true;
+ m_bornForOSR = false;
ASSERT(m_useCount);
}
void initInteger(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
@@ -71,6 +75,7 @@ public:
m_spillFormat = DataFormatNone;
m_canFill = false;
u.gpr = gpr;
+ m_bornForOSR = false;
ASSERT(m_useCount);
}
#if USE(JSVALUE64)
@@ -84,6 +89,7 @@ public:
m_spillFormat = DataFormatNone;
m_canFill = false;
u.gpr = gpr;
+ m_bornForOSR = false;
ASSERT(m_useCount);
}
#elif USE(JSVALUE32_64)
@@ -98,6 +104,7 @@ public:
m_canFill = false;
u.v.tagGPR = tagGPR;
u.v.payloadGPR = payloadGPR;
+ m_bornForOSR = false;
ASSERT(m_useCount);
}
#endif
@@ -109,6 +116,7 @@ public:
m_spillFormat = DataFormatNone;
m_canFill = false;
u.gpr = gpr;
+ m_bornForOSR = false;
ASSERT(m_useCount);
}
void initBoolean(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
@@ -119,6 +127,7 @@ public:
m_spillFormat = DataFormatNone;
m_canFill = false;
u.gpr = gpr;
+ m_bornForOSR = false;
ASSERT(m_useCount);
}
void initDouble(NodeIndex nodeIndex, uint32_t useCount, FPRReg fpr)
@@ -130,6 +139,7 @@ public:
m_spillFormat = DataFormatNone;
m_canFill = false;
u.fpr = fpr;
+ m_bornForOSR = false;
ASSERT(m_useCount);
}
void initStorage(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
@@ -140,19 +150,44 @@ public:
m_spillFormat = DataFormatNone;
m_canFill = false;
u.gpr = gpr;
+ m_bornForOSR = false;
ASSERT(m_useCount);
}
// Get the index of the node that produced this value.
NodeIndex nodeIndex() { return m_nodeIndex; }
+
+ void noticeOSRBirth(VariableEventStream& stream, NodeIndex nodeIndex, VirtualRegister virtualRegister)
+ {
+ if (m_nodeIndex != nodeIndex)
+ return;
+ if (!alive())
+ return;
+ if (m_bornForOSR)
+ return;
+
+ m_bornForOSR = true;
+
+ if (m_registerFormat != DataFormatNone)
+ appendFill(BirthToFill, stream);
+ else if (m_spillFormat != DataFormatNone)
+ appendSpill(BirthToSpill, stream, virtualRegister);
+ }
// Mark the value as having been used (decrement the useCount).
// Returns true if this was the last use of the value, and any
// associated machine registers may be freed.
- bool use()
+ bool use(VariableEventStream& stream)
{
ASSERT(m_useCount);
- return !--m_useCount;
+ bool result = !--m_useCount;
+
+ if (result && m_bornForOSR) {
+ ASSERT(m_nodeIndex != NoNode);
+ stream.appendAndLog(VariableEvent::death(m_nodeIndex));
+ }
+
+ return result;
}
// Used to check the operands of operations to see if they are on
@@ -225,7 +260,7 @@ public:
}
// Called when a VirtualRegister is being spilled to the RegisterFile for the first time.
- void spill(DataFormat spillFormat)
+ void spill(VariableEventStream& stream, VirtualRegister virtualRegister, DataFormat spillFormat)
{
// We shouldn't be spill values that don't need spilling.
ASSERT(!m_canFill);
@@ -236,15 +271,21 @@ public:
m_registerFormat = DataFormatNone;
m_spillFormat = spillFormat;
m_canFill = true;
+
+ if (m_bornForOSR)
+ appendSpill(Spill, stream, virtualRegister);
}
// Called on values that don't need spilling (constants and values that have
// already been spilled), to mark them as no longer being in machine registers.
- void setSpilled()
+ void setSpilled(VariableEventStream& stream, VirtualRegister virtualRegister)
{
// Should only be called on values that don't need spilling, and are currently in registers.
ASSERT(m_canFill && m_registerFormat != DataFormatNone);
m_registerFormat = DataFormatNone;
+
+ if (m_bornForOSR)
+ appendSpill(Spill, stream, virtualRegister);
}
void killSpilled()
@@ -256,46 +297,67 @@ public:
// Record that this value is filled into machine registers,
// tracking which registers, and what format the value has.
#if USE(JSVALUE64)
- void fillJSValue(GPRReg gpr, DataFormat format = DataFormatJS)
+ void fillJSValue(VariableEventStream& stream, GPRReg gpr, DataFormat format = DataFormatJS)
{
ASSERT(format & DataFormatJS);
m_registerFormat = format;
u.gpr = gpr;
+
+ if (m_bornForOSR)
+ appendFill(Fill, stream);
}
#elif USE(JSVALUE32_64)
- void fillJSValue(GPRReg tagGPR, GPRReg payloadGPR, DataFormat format = DataFormatJS)
+ void fillJSValue(VariableEventStream& stream, GPRReg tagGPR, GPRReg payloadGPR, DataFormat format = DataFormatJS)
{
ASSERT(format & DataFormatJS);
m_registerFormat = format;
u.v.tagGPR = tagGPR; // FIXME: for JSValues with known type (boolean, integer, cell etc.) no tagGPR is needed?
u.v.payloadGPR = payloadGPR;
+
+ if (m_bornForOSR)
+ appendFill(Fill, stream);
}
- void fillCell(GPRReg gpr)
+ void fillCell(VariableEventStream& stream, GPRReg gpr)
{
m_registerFormat = DataFormatCell;
u.gpr = gpr;
+
+ if (m_bornForOSR)
+ appendFill(Fill, stream);
}
#endif
- void fillInteger(GPRReg gpr)
+ void fillInteger(VariableEventStream& stream, GPRReg gpr)
{
m_registerFormat = DataFormatInteger;
u.gpr = gpr;
+
+ if (m_bornForOSR)
+ appendFill(Fill, stream);
}
- void fillBoolean(GPRReg gpr)
+ void fillBoolean(VariableEventStream& stream, GPRReg gpr)
{
m_registerFormat = DataFormatBoolean;
u.gpr = gpr;
+
+ if (m_bornForOSR)
+ appendFill(Fill, stream);
}
- void fillDouble(FPRReg fpr)
+ void fillDouble(VariableEventStream& stream, FPRReg fpr)
{
ASSERT(fpr != InvalidFPRReg);
m_registerFormat = DataFormatDouble;
u.fpr = fpr;
+
+ if (m_bornForOSR)
+ appendFill(Fill, stream);
}
- void fillStorage(GPRReg gpr)
+ void fillStorage(VariableEventStream& stream, GPRReg gpr)
{
m_registerFormat = DataFormatStorage;
u.gpr = gpr;
+
+ if (m_bornForOSR)
+ appendFill(Fill, stream);
}
bool alive()
@@ -304,12 +366,33 @@ public:
}
private:
+ void appendFill(VariableEventKind kind, VariableEventStream& stream)
+ {
+ if (m_registerFormat == DataFormatDouble) {
+ stream.appendAndLog(VariableEvent::fillFPR(kind, m_nodeIndex, u.fpr));
+ return;
+ }
+#if USE(JSVALUE32_64)
+ if (m_registerFormat & DataFormatJS) {
+ stream.appendAndLog(VariableEvent::fillPair(kind, m_nodeIndex, u.v.tagGPR, u.v.payloadGPR));
+ return;
+ }
+#endif
+ stream.appendAndLog(VariableEvent::fillGPR(kind, m_nodeIndex, u.gpr, m_registerFormat));
+ }
+
+ void appendSpill(VariableEventKind kind, VariableEventStream& stream, VirtualRegister virtualRegister)
+ {
+ stream.appendAndLog(VariableEvent::spill(kind, m_nodeIndex, virtualRegister, m_spillFormat));
+ }
+
// The index of the node whose result is stored in this virtual register.
NodeIndex m_nodeIndex;
uint32_t m_useCount;
DataFormat m_registerFormat;
DataFormat m_spillFormat;
bool m_canFill;
+ bool m_bornForOSR;
union {
GPRReg gpr;
FPRReg fpr;
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp
index 4689470c8..c7a4d94d2 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.cpp
+++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp
@@ -327,14 +327,11 @@ void Graph::dumpBlockHeader(const char* prefix, BlockIndex blockIndex, PhiNodeDu
dataLog("\n");
}
dataLog("%s Phi Nodes:", prefix);
- unsigned count = 0;
for (size_t i = 0; i < block->phis.size(); ++i) {
NodeIndex phiNodeIndex = block->phis[i];
Node& phiNode = at(phiNodeIndex);
if (!phiNode.shouldGenerate() && phiNodeDumpMode == DumpLivePhisOnly)
continue;
- if (!((++count) % 4))
- dataLog("\n%s ", prefix);
dataLog(" @%u->(", phiNodeIndex);
if (phiNode.child1()) {
dataLog("@%u", phiNode.child1().index());
diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
index 3c85cc77c..497fc346f 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
@@ -88,8 +88,6 @@ void JITCompiler::compileBody(SpeculativeJIT& speculative)
breakpoint();
#endif
- addPtr(TrustedImm32(1), AbsoluteAddress(codeBlock()->addressOfSpeculativeSuccessCounter()));
-
bool compiledSpeculative = speculative.compile();
ASSERT_UNUSED(compiledSpeculative, compiledSpeculative);
}
@@ -174,6 +172,7 @@ void JITCompiler::link(LinkBuffer& linkBuffer)
#endif
info.patch.dfg.deltaCallToSlowCase = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_propertyAccesses[i].m_slowPathGenerator->label()));
info.patch.dfg.deltaCallToDone = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_propertyAccesses[i].m_done));
+ info.patch.dfg.deltaCallToStorageLoad = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_propertyAccesses[i].m_propertyStorageLoad));
info.patch.dfg.baseGPR = m_propertyAccesses[i].m_baseGPR;
#if USE(JSVALUE64)
info.patch.dfg.valueGPR = m_propertyAccesses[i].m_valueGPR;
@@ -205,11 +204,14 @@ void JITCompiler::link(LinkBuffer& linkBuffer)
codeBlock()->watchpoint(exit.m_watchpointIndex).correctLabels(linkBuffer);
}
+ codeBlock()->minifiedDFG().setOriginalGraphSize(m_graph.size());
codeBlock()->shrinkToFit(CodeBlock::LateShrink);
}
bool JITCompiler::compile(JITCode& entry)
{
+ SamplingRegion samplingRegion("DFG Backend");
+
setStartOfCode();
compileEntry();
SpeculativeJIT speculative(*this);
@@ -243,6 +245,8 @@ bool JITCompiler::compile(JITCode& entry)
bool JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck)
{
+ SamplingRegion samplingRegion("DFG Backend");
+
setStartOfCode();
compileEntry();
diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.h b/Source/JavaScriptCore/dfg/DFGJITCompiler.h
index ed16459cc..24dbbdcd0 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.h
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.h
@@ -136,6 +136,7 @@ struct PropertyAccessRecord {
CodeOrigin codeOrigin,
MacroAssembler::DataLabelPtr structureImm,
MacroAssembler::PatchableJump structureCheck,
+ MacroAssembler::ConvertibleLoadLabel propertyStorageLoad,
MacroAssembler::DataLabelCompact loadOrStore,
SlowPathGenerator* slowPathGenerator,
MacroAssembler::Label done,
@@ -148,6 +149,7 @@ struct PropertyAccessRecord {
CodeOrigin codeOrigin,
MacroAssembler::DataLabelPtr structureImm,
MacroAssembler::PatchableJump structureCheck,
+ MacroAssembler::ConvertibleLoadLabel propertyStorageLoad,
MacroAssembler::DataLabelCompact tagLoadOrStore,
MacroAssembler::DataLabelCompact payloadLoadOrStore,
SlowPathGenerator* slowPathGenerator,
@@ -161,6 +163,7 @@ struct PropertyAccessRecord {
: m_codeOrigin(codeOrigin)
, m_structureImm(structureImm)
, m_structureCheck(structureCheck)
+ , m_propertyStorageLoad(propertyStorageLoad)
#if USE(JSVALUE64)
, m_loadOrStore(loadOrStore)
#elif USE(JSVALUE32_64)
@@ -182,6 +185,7 @@ struct PropertyAccessRecord {
CodeOrigin m_codeOrigin;
MacroAssembler::DataLabelPtr m_structureImm;
MacroAssembler::PatchableJump m_structureCheck;
+ MacroAssembler::ConvertibleLoadLabel m_propertyStorageLoad;
#if USE(JSVALUE64)
MacroAssembler::DataLabelCompact m_loadOrStore;
#elif USE(JSVALUE32_64)
diff --git a/Source/JavaScriptCore/dfg/DFGMinifiedGraph.h b/Source/JavaScriptCore/dfg/DFGMinifiedGraph.h
new file mode 100644
index 000000000..b38ef07ed
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGMinifiedGraph.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGMinifiedGraph_h
+#define DFGMinifiedGraph_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGMinifiedNode.h"
+#include <algorithm>
+#include <wtf/StdLibExtras.h>
+#include <wtf/Vector.h>
+
+namespace JSC { namespace DFG {
+
+class MinifiedGraph {
+public:
+ MinifiedGraph() { }
+
+ MinifiedNode* at(NodeIndex nodeIndex)
+ {
+ if (!m_list.size())
+ return 0;
+ MinifiedNode* entry =
+ binarySearch<MinifiedNode, NodeIndex, MinifiedNode::getIndex>(
+ m_list.begin(), m_list.size(), nodeIndex, WTF::KeyMustNotBePresentInArray);
+ if (entry->index() != nodeIndex)
+ return 0;
+ return entry;
+ }
+
+ void append(const MinifiedNode& node)
+ {
+ m_list.append(node);
+ }
+
+ void prepareAndShrink()
+ {
+ std::sort(m_list.begin(), m_list.end(), MinifiedNode::compareByNodeIndex);
+ m_list.shrinkToFit();
+ }
+
+ void setOriginalGraphSize(size_t size) { m_size = size; }
+
+ size_t originalGraphSize() const { return m_size; }
+
+private:
+ Vector<MinifiedNode> m_list;
+ size_t m_size;
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGMinifiedGraph_h
+
diff --git a/Source/JavaScriptCore/dfg/DFGMinifiedNode.cpp b/Source/JavaScriptCore/dfg/DFGMinifiedNode.cpp
new file mode 100644
index 000000000..6362344fb
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGMinifiedNode.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DFGMinifiedNode.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGNode.h"
+
+namespace JSC { namespace DFG {
+
+MinifiedNode MinifiedNode::fromNode(NodeIndex nodeIndex, Node& node)
+{
+ ASSERT(belongsInMinifiedGraph(node.op()));
+ MinifiedNode result;
+ result.m_index = nodeIndex;
+ result.m_op = node.op();
+ if (hasChild(node.op()))
+ result.m_childOrInfo = node.child1().index();
+ else if (hasConstantNumber(node.op()))
+ result.m_childOrInfo = node.constantNumber();
+ else if (hasWeakConstant(node.op()))
+ result.m_childOrInfo = bitwise_cast<uintptr_t>(node.weakConstant());
+ else {
+ ASSERT(node.op() == PhantomArguments);
+ result.m_childOrInfo = 0;
+ }
+ return result;
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
diff --git a/Source/JavaScriptCore/dfg/DFGMinifiedNode.h b/Source/JavaScriptCore/dfg/DFGMinifiedNode.h
new file mode 100644
index 000000000..b80cbd777
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGMinifiedNode.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGMinifiedNode_h
+#define DFGMinifiedNode_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGCommon.h"
+#include "DFGNodeType.h"
+
+namespace JSC { namespace DFG {
+
+struct Node;
+
+inline bool belongsInMinifiedGraph(NodeType type)
+{
+ switch (type) {
+ case JSConstant:
+ case WeakJSConstant:
+ case ValueToInt32:
+ case Int32ToDouble:
+ case UInt32ToNumber:
+ case DoubleAsInt32:
+ case PhantomArguments:
+ return true;
+ default:
+ return false;
+ }
+}
+
+class MinifiedNode {
+public:
+ MinifiedNode() { }
+
+ static MinifiedNode fromNode(NodeIndex, Node&);
+
+ NodeIndex index() const { return m_index; }
+ NodeType op() const { return m_op; }
+
+ bool hasChild1() const { return hasChild(m_op); }
+
+ NodeIndex child1() const
+ {
+ ASSERT(hasChild(m_op));
+ return m_childOrInfo;
+ }
+
+ bool hasConstant() const { return hasConstantNumber() || hasWeakConstant(); }
+
+ bool hasConstantNumber() const { return hasConstantNumber(m_op); }
+
+ unsigned constantNumber() const
+ {
+ ASSERT(hasConstantNumber(m_op));
+ return m_childOrInfo;
+ }
+
+ bool hasWeakConstant() const { return hasWeakConstant(m_op); }
+
+ JSCell* weakConstant() const
+ {
+ ASSERT(hasWeakConstant(m_op));
+ return bitwise_cast<JSCell*>(m_childOrInfo);
+ }
+
+ static NodeIndex getIndex(MinifiedNode* node) { return node->index(); }
+ static bool compareByNodeIndex(const MinifiedNode& a, const MinifiedNode& b)
+ {
+ return a.m_index < b.m_index;
+ }
+
+private:
+ static bool hasChild(NodeType type)
+ {
+ switch (type) {
+ case ValueToInt32:
+ case Int32ToDouble:
+ case UInt32ToNumber:
+ case DoubleAsInt32:
+ return true;
+ default:
+ return false;
+ }
+ }
+ static bool hasConstantNumber(NodeType type)
+ {
+ return type == JSConstant;
+ }
+ static bool hasWeakConstant(NodeType type)
+ {
+ return type == WeakJSConstant;
+ }
+
+ NodeIndex m_index;
+ NodeType m_op;
+ uintptr_t m_childOrInfo; // Nodes in the minified graph have only one child each.
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGMinifiedNode_h
+
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index 40701c3bd..ae07d5512 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -40,6 +40,7 @@
#include "JSValue.h"
#include "Operands.h"
#include "SpeculatedType.h"
+#include "StructureSet.h"
#include "ValueProfile.h"
namespace JSC { namespace DFG {
@@ -707,7 +708,7 @@ struct Node {
ASSERT(m_virtualRegister != InvalidVirtualRegister);
return m_virtualRegister;
}
-
+
void setVirtualRegister(VirtualRegister virtualRegister)
{
ASSERT(hasResult());
@@ -731,9 +732,21 @@ struct Node {
return m_refCount;
}
- bool willHaveCodeGen()
+ bool willHaveCodeGenOrOSR()
{
- return shouldGenerate() && op() != Phantom && op() != Nop;
+ switch (op()) {
+ case SetLocal:
+ case Int32ToDouble:
+ case ValueToInt32:
+ case UInt32ToNumber:
+ case DoubleAsInt32:
+ return true;
+ case Phantom:
+ case Nop:
+ return false;
+ default:
+ return shouldGenerate();
+ }
}
unsigned refCount()
diff --git a/Source/JavaScriptCore/dfg/DFGOSRExit.cpp b/Source/JavaScriptCore/dfg/DFGOSRExit.cpp
index d0e0de9da..e9b02b2e3 100644
--- a/Source/JavaScriptCore/dfg/DFGOSRExit.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOSRExit.cpp
@@ -33,17 +33,7 @@
namespace JSC { namespace DFG {
-static unsigned computeNumVariablesForCodeOrigin(
- CodeBlock* codeBlock, const CodeOrigin& codeOrigin)
-{
- if (!codeOrigin.inlineCallFrame)
- return codeBlock->m_numCalleeRegisters;
- return
- codeOrigin.inlineCallFrame->stackOffset +
- baselineCodeBlockForInlineCallFrame(codeOrigin.inlineCallFrame)->m_numCalleeRegisters;
-}
-
-OSRExit::OSRExit(ExitKind kind, JSValueSource jsValueSource, MethodOfGettingAValueProfile valueProfile, MacroAssembler::Jump check, SpeculativeJIT* jit, unsigned recoveryIndex)
+OSRExit::OSRExit(ExitKind kind, JSValueSource jsValueSource, MethodOfGettingAValueProfile valueProfile, MacroAssembler::Jump check, SpeculativeJIT* jit, unsigned streamIndex, unsigned recoveryIndex)
: m_jsValueSource(jsValueSource)
, m_valueProfile(valueProfile)
, m_check(check)
@@ -54,29 +44,15 @@ OSRExit::OSRExit(ExitKind kind, JSValueSource jsValueSource, MethodOfGettingAVal
, m_watchpointIndex(std::numeric_limits<unsigned>::max())
, m_kind(kind)
, m_count(0)
- , m_arguments(jit->m_arguments.size())
- , m_variables(computeNumVariablesForCodeOrigin(jit->m_jit.graph().m_profiledBlock, jit->m_codeOriginForOSR))
+ , m_streamIndex(streamIndex)
, m_lastSetOperand(jit->m_lastSetOperand)
{
ASSERT(m_codeOrigin.isSet());
- for (unsigned argument = 0; argument < m_arguments.size(); ++argument)
- m_arguments[argument] = jit->computeValueRecoveryFor(jit->m_arguments[argument]);
- for (unsigned variable = 0; variable < m_variables.size(); ++variable)
- m_variables[variable] = jit->computeValueRecoveryFor(jit->m_variables[variable]);
-}
-
-void OSRExit::dump(FILE* out) const
-{
- for (unsigned argument = 0; argument < m_arguments.size(); ++argument)
- m_arguments[argument].dump(out);
- fprintf(out, " : ");
- for (unsigned variable = 0; variable < m_variables.size(); ++variable)
- m_variables[variable].dump(out);
}
bool OSRExit::considerAddingAsFrequentExitSiteSlow(CodeBlock* dfgCodeBlock, CodeBlock* profiledCodeBlock)
{
- if (static_cast<double>(m_count) / dfgCodeBlock->speculativeFailCounter() <= Options::osrExitProminenceForFrequentExitSite)
+ if (static_cast<double>(m_count) / dfgCodeBlock->osrExitCounter() <= Options::osrExitProminenceForFrequentExitSite())
return false;
FrequentExitSite exitSite;
diff --git a/Source/JavaScriptCore/dfg/DFGOSRExit.h b/Source/JavaScriptCore/dfg/DFGOSRExit.h
index 683f260f1..cd2434c11 100644
--- a/Source/JavaScriptCore/dfg/DFGOSRExit.h
+++ b/Source/JavaScriptCore/dfg/DFGOSRExit.h
@@ -35,6 +35,7 @@
#include "DFGCorrectableJumpPoint.h"
#include "DFGExitProfile.h"
#include "DFGGPRInfo.h"
+#include "DFGValueRecoveryOverride.h"
#include "MacroAssembler.h"
#include "MethodOfGettingAValueProfile.h"
#include "Operands.h"
@@ -83,7 +84,7 @@ private:
// This structure describes how to exit the speculative path by
// going into baseline code.
struct OSRExit {
- OSRExit(ExitKind, JSValueSource, MethodOfGettingAValueProfile, MacroAssembler::Jump, SpeculativeJIT*, unsigned recoveryIndex = 0);
+ OSRExit(ExitKind, JSValueSource, MethodOfGettingAValueProfile, MacroAssembler::Jump, SpeculativeJIT*, unsigned streamIndex, unsigned recoveryIndex = 0);
MacroAssemblerCodeRef m_code;
@@ -101,38 +102,6 @@ struct OSRExit {
ExitKind m_kind;
uint32_t m_count;
- // Convenient way of iterating over ValueRecoveries while being
- // generic over argument versus variable.
- int numberOfRecoveries() const { return m_arguments.size() + m_variables.size(); }
- const ValueRecovery& valueRecovery(int index) const
- {
- if (index < (int)m_arguments.size())
- return m_arguments[index];
- return m_variables[index - m_arguments.size()];
- }
- ValueRecovery& valueRecoveryForOperand(int operand)
- {
- if (operandIsArgument(operand))
- return m_arguments[operandToArgument(operand)];
- return m_variables[operand];
- }
- bool isArgument(int index) const { return index < (int)m_arguments.size(); }
- bool isVariable(int index) const { return !isArgument(index); }
- int argumentForIndex(int index) const
- {
- return index;
- }
- int variableForIndex(int index) const
- {
- return index - m_arguments.size();
- }
- int operandForIndex(int index) const
- {
- if (index < (int)m_arguments.size())
- return operandToArgument(index);
- return index - m_arguments.size();
- }
-
bool considerAddingAsFrequentExitSite(CodeBlock* dfgCodeBlock, CodeBlock* profiledCodeBlock)
{
if (!m_count || !exitKindIsCountable(m_kind))
@@ -140,11 +109,10 @@ struct OSRExit {
return considerAddingAsFrequentExitSiteSlow(dfgCodeBlock, profiledCodeBlock);
}
- void dump(FILE* out) const;
-
- Vector<ValueRecovery, 0> m_arguments;
- Vector<ValueRecovery, 0> m_variables;
+ unsigned m_streamIndex;
int m_lastSetOperand;
+
+ RefPtr<ValueRecoveryOverride> m_valueRecoveryOverride;
private:
bool considerAddingAsFrequentExitSiteSlow(CodeBlock* dfgCodeBlock, CodeBlock* profiledCodeBlock);
diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp
index e617b5479..2ce1c887b 100644
--- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp
@@ -29,6 +29,7 @@
#if ENABLE(DFG_JIT)
#include "CallFrame.h"
+#include "DFGCommon.h"
#include "LinkBuffer.h"
#include "RepatchBuffer.h"
@@ -38,6 +39,8 @@ extern "C" {
void compileOSRExit(ExecState* exec)
{
+ SamplingRegion samplingRegion("DFG OSR Exit Compilation");
+
CodeBlock* codeBlock = exec->codeBlock();
ASSERT(codeBlock);
@@ -63,12 +66,22 @@ void compileOSRExit(ExecState* exec)
->jitCompile(exec);
}
+ // Compute the value recoveries.
+ Operands<ValueRecovery> operands;
+ codeBlock->variableEventStream().reconstruct(codeBlock, exit.m_codeOrigin, codeBlock->minifiedDFG(), exit.m_streamIndex, operands);
+
+ // There may be an override, for forward speculations.
+ if (!!exit.m_valueRecoveryOverride) {
+ operands.setOperand(
+ exit.m_valueRecoveryOverride->operand, exit.m_valueRecoveryOverride->recovery);
+ }
+
SpeculationRecovery* recovery = 0;
if (exit.m_recoveryIndex)
recovery = &codeBlock->speculationRecovery(exit.m_recoveryIndex - 1);
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Generating OSR exit #%u (bc#%u, @%u, %s) for code block %p.\n", exitIndex, exit.m_codeOrigin.bytecodeIndex, exit.m_nodeIndex, exitKindToString(exit.m_kind), codeBlock);
+ dataLog("Generating OSR exit #%u (seq#%u, bc#%u, @%u, %s) for code block %p.\n", exitIndex, exit.m_streamIndex, exit.m_codeOrigin.bytecodeIndex, exit.m_nodeIndex, exitKindToString(exit.m_kind), codeBlock);
#endif
{
@@ -76,10 +89,11 @@ void compileOSRExit(ExecState* exec)
OSRExitCompiler exitCompiler(jit);
jit.jitAssertHasValidCallFrame();
- exitCompiler.compileExit(exit, recovery);
+ exitCompiler.compileExit(exit, operands, recovery);
LinkBuffer patchBuffer(*globalData, &jit, codeBlock);
- exit.m_code = FINALIZE_CODE(
+ exit.m_code = FINALIZE_CODE_IF(
+ shouldShowDisassembly(),
patchBuffer,
("DFG OSR exit #%u (bc#%u, @%u, %s) from CodeBlock %p",
exitIndex, exit.m_codeOrigin.bytecodeIndex, exit.m_nodeIndex,
@@ -102,42 +116,14 @@ void OSRExitCompiler::handleExitCounts(const OSRExit& exit)
m_jit.move(AssemblyHelpers::TrustedImmPtr(m_jit.codeBlock()), GPRInfo::regT0);
- AssemblyHelpers::JumpList tooFewFails;
+ AssemblyHelpers::Jump tooFewFails;
- if (exit.m_kind == InadequateCoverage) {
- // Proceed based on the assumption that we can profitably optimize this code once
- // it has executed enough times.
-
- m_jit.load32(AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfForcedOSRExitCounter()), GPRInfo::regT2);
- m_jit.load32(AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeSuccessCounter()), GPRInfo::regT1);
- m_jit.add32(AssemblyHelpers::TrustedImm32(1), GPRInfo::regT2);
- m_jit.add32(AssemblyHelpers::TrustedImm32(-1), GPRInfo::regT1);
- m_jit.store32(GPRInfo::regT2, AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfForcedOSRExitCounter()));
- m_jit.store32(GPRInfo::regT1, AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeSuccessCounter()));
-
- m_jit.move(AssemblyHelpers::TrustedImmPtr(m_jit.baselineCodeBlock()), GPRInfo::regT0);
-
- tooFewFails.append(m_jit.branch32(AssemblyHelpers::BelowOrEqual, GPRInfo::regT2, AssemblyHelpers::TrustedImm32(Options::forcedOSRExitCountForReoptimization)));
-
- } else {
- // Proceed based on the assumption that we can handle these exits so long as they
- // don't get too frequent.
-
- m_jit.load32(AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeFailCounter()), GPRInfo::regT2);
- m_jit.load32(AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeSuccessCounter()), GPRInfo::regT1);
- m_jit.add32(AssemblyHelpers::TrustedImm32(1), GPRInfo::regT2);
- m_jit.add32(AssemblyHelpers::TrustedImm32(-1), GPRInfo::regT1);
- m_jit.store32(GPRInfo::regT2, AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeFailCounter()));
- m_jit.store32(GPRInfo::regT1, AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeSuccessCounter()));
-
- m_jit.move(AssemblyHelpers::TrustedImmPtr(m_jit.baselineCodeBlock()), GPRInfo::regT0);
+ m_jit.load32(AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfOSRExitCounter()), GPRInfo::regT2);
+ m_jit.add32(AssemblyHelpers::TrustedImm32(1), GPRInfo::regT2);
+ m_jit.store32(GPRInfo::regT2, AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfOSRExitCounter()));
+ m_jit.move(AssemblyHelpers::TrustedImmPtr(m_jit.baselineCodeBlock()), GPRInfo::regT0);
+ tooFewFails = m_jit.branch32(AssemblyHelpers::BelowOrEqual, GPRInfo::regT2, AssemblyHelpers::TrustedImm32(m_jit.codeBlock()->exitCountThresholdForReoptimization()));
- tooFewFails.append(m_jit.branch32(AssemblyHelpers::BelowOrEqual, GPRInfo::regT2, AssemblyHelpers::TrustedImm32(m_jit.codeBlock()->largeFailCountThreshold())));
- m_jit.mul32(AssemblyHelpers::TrustedImm32(Options::desiredSpeculativeSuccessFailRatio), GPRInfo::regT2, GPRInfo::regT2);
-
- tooFewFails.append(m_jit.branch32(AssemblyHelpers::BelowOrEqual, GPRInfo::regT2, GPRInfo::regT1));
- }
-
// Reoptimize as soon as possible.
#if !NUMBER_OF_ARGUMENT_REGISTERS
m_jit.poke(GPRInfo::regT0);
@@ -157,6 +143,7 @@ void OSRExitCompiler::handleExitCounts(const OSRExit& exit)
m_jit.baselineCodeBlock()->counterValueForOptimizeAfterLongWarmUp(),
m_jit.baselineCodeBlock());
m_jit.store32(AssemblyHelpers::TrustedImm32(-targetValue), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecuteCounter()));
+ targetValue = ExecutionCounter::clippedThreshold(m_jit.codeBlock()->globalObject(), targetValue);
m_jit.store32(AssemblyHelpers::TrustedImm32(targetValue), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecutionActiveThreshold()));
m_jit.store32(AssemblyHelpers::TrustedImm32(ExecutionCounter::formattedTotalCount(targetValue)), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecutionTotalCount()));
diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.h b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.h
index ae29a92d5..a2be5b849 100644
--- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.h
+++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.h
@@ -48,7 +48,7 @@ public:
{
}
- void compileExit(const OSRExit&, SpeculationRecovery*);
+ void compileExit(const OSRExit&, const Operands<ValueRecovery>&, SpeculationRecovery*);
private:
#if !ASSERT_DISABLED
diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp
index 09912b3e5..6bc136da4 100644
--- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp
@@ -29,10 +29,11 @@
#if ENABLE(DFG_JIT) && USE(JSVALUE32_64)
#include "DFGOperations.h"
+#include <wtf/DataLog.h>
namespace JSC { namespace DFG {
-void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* recovery)
+void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecovery>& operands, SpeculationRecovery* recovery)
{
// 1) Pro-forma stuff.
#if DFG_ENABLE(DEBUG_VERBOSE)
@@ -44,7 +45,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
dataLog(" -> %p ", codeOrigin.inlineCallFrame->executable.get());
}
dataLog(") at JIT offset 0x%x ", m_jit.debugOffset());
- exit.dump(WTF::dataFile());
+ dumpOperands(operands, WTF::dataFile());
#endif
#if DFG_ENABLE(VERBOSE_SPECULATION_FAILURE)
SpeculationFailureDebugInfo* debugInfo = new SpeculationFailureDebugInfo;
@@ -113,7 +114,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
// GPRInfo::numberOfRegisters of them. Also see if there are any constants,
// any undefined slots, any FPR slots, and any unboxed ints.
- Vector<bool> poisonedVirtualRegisters(exit.m_variables.size());
+ Vector<bool> poisonedVirtualRegisters(operands.numberOfLocals());
for (unsigned i = 0; i < poisonedVirtualRegisters.size(); ++i)
poisonedVirtualRegisters[i] = false;
@@ -133,8 +134,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
bool haveUndefined = false;
bool haveArguments = false;
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
switch (recovery.technique()) {
case DisplacedInRegisterFile:
case Int32DisplacedInRegisterFile:
@@ -150,8 +151,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
// to ensure this happens efficiently. Note that we expect this case
// to be rare, so the handling of it is optimized for the cases in
// which it does not happen.
- if (recovery.virtualRegister() < (int)exit.m_variables.size()) {
- switch (exit.m_variables[recovery.virtualRegister()].technique()) {
+ if (recovery.virtualRegister() < (int)operands.numberOfLocals()) {
+ switch (operands.local(recovery.virtualRegister()).technique()) {
case InGPR:
case UnboxedInt32InGPR:
case UnboxedBooleanInGPR:
@@ -214,19 +215,19 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
// 5) Perform all reboxing of integers and cells, except for those in registers.
if (haveUnboxedInt32InRegisterFile || haveUnboxedCellInRegisterFile || haveUnboxedBooleanInRegisterFile) {
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
switch (recovery.technique()) {
case AlreadyInRegisterFileAsUnboxedInt32:
- m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::Int32Tag), AssemblyHelpers::tagFor(static_cast<VirtualRegister>(exit.operandForIndex(index))));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::Int32Tag), AssemblyHelpers::tagFor(static_cast<VirtualRegister>(operands.operandForIndex(index))));
break;
case AlreadyInRegisterFileAsUnboxedCell:
- m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::CellTag), AssemblyHelpers::tagFor(static_cast<VirtualRegister>(exit.operandForIndex(index))));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::CellTag), AssemblyHelpers::tagFor(static_cast<VirtualRegister>(operands.operandForIndex(index))));
break;
case AlreadyInRegisterFileAsUnboxedBoolean:
- m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::BooleanTag), AssemblyHelpers::tagFor(static_cast<VirtualRegister>(exit.operandForIndex(index))));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::BooleanTag), AssemblyHelpers::tagFor(static_cast<VirtualRegister>(operands.operandForIndex(index))));
break;
default:
@@ -239,19 +240,19 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
// Note that GPRs do not have a fast change (like haveFPRs) because we expect that
// most OSR failure points will have at least one GPR that needs to be dumped.
- initializePoisoned(exit.m_variables.size());
+ initializePoisoned(operands.numberOfLocals());
unsigned currentPoisonIndex = 0;
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
- int operand = exit.operandForIndex(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
+ int operand = operands.operandForIndex(index);
switch (recovery.technique()) {
case InGPR:
case UnboxedInt32InGPR:
case UnboxedBooleanInGPR:
- if (exit.isVariable(index) && poisonedVirtualRegisters[exit.variableForIndex(index)]) {
+ if (operands.isVariable(index) && poisonedVirtualRegisters[operands.variableForIndex(index)]) {
m_jit.store32(recovery.gpr(), reinterpret_cast<char*>(scratchDataBuffer + currentPoisonIndex) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
- m_poisonScratchIndices[exit.variableForIndex(index)] = currentPoisonIndex;
+ m_poisonScratchIndices[operands.variableForIndex(index)] = currentPoisonIndex;
currentPoisonIndex++;
} else {
uint32_t tag = JSValue::EmptyValueTag;
@@ -266,10 +267,10 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
}
break;
case InPair:
- if (exit.isVariable(index) && poisonedVirtualRegisters[exit.variableForIndex(index)]) {
+ if (operands.isVariable(index) && poisonedVirtualRegisters[operands.variableForIndex(index)]) {
m_jit.store32(recovery.tagGPR(), reinterpret_cast<char*>(scratchDataBuffer + currentPoisonIndex) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
m_jit.store32(recovery.payloadGPR(), reinterpret_cast<char*>(scratchDataBuffer + currentPoisonIndex) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
- m_poisonScratchIndices[exit.variableForIndex(index)] = currentPoisonIndex;
+ m_poisonScratchIndices[operands.variableForIndex(index)] = currentPoisonIndex;
currentPoisonIndex++;
} else {
m_jit.store32(recovery.tagGPR(), AssemblyHelpers::tagFor((VirtualRegister)operand));
@@ -291,7 +292,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
m_jit.convertInt32ToDouble(recovery.gpr(), FPRInfo::fpRegT0);
m_jit.addDouble(AssemblyHelpers::AbsoluteAddress(&AssemblyHelpers::twoToThe32), FPRInfo::fpRegT0);
- if (exit.isVariable(index) && poisonedVirtualRegisters[exit.variableForIndex(index)]) {
+ if (operands.isVariable(index) && poisonedVirtualRegisters[operands.variableForIndex(index)]) {
m_jit.move(AssemblyHelpers::TrustedImmPtr(scratchDataBuffer + currentPoisonIndex), addressGPR);
m_jit.storeDouble(FPRInfo::fpRegT0, addressGPR);
} else
@@ -301,7 +302,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
positive.link(&m_jit);
- if (exit.isVariable(index) && poisonedVirtualRegisters[exit.variableForIndex(index)]) {
+ if (operands.isVariable(index) && poisonedVirtualRegisters[operands.variableForIndex(index)]) {
m_jit.store32(recovery.gpr(), reinterpret_cast<char*>(scratchDataBuffer + currentPoisonIndex) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::Int32Tag), reinterpret_cast<char*>(scratchDataBuffer + currentPoisonIndex) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
} else {
@@ -315,8 +316,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
m_jit.loadDouble(addressGPR, FPRInfo::fpRegT0);
m_jit.loadPtr(myScratch, addressGPR);
- if (exit.isVariable(index) && poisonedVirtualRegisters[exit.variableForIndex(index)]) {
- m_poisonScratchIndices[exit.variableForIndex(index)] = currentPoisonIndex;
+ if (operands.isVariable(index) && poisonedVirtualRegisters[operands.variableForIndex(index)]) {
+ m_poisonScratchIndices[operands.variableForIndex(index)] = currentPoisonIndex;
currentPoisonIndex++;
}
break;
@@ -329,16 +330,16 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
// 7) Dump all doubles into the register file, or to the scratch storage if the
// destination virtual register is poisoned.
if (haveFPRs) {
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
if (recovery.technique() != InFPR)
continue;
- if (exit.isVariable(index) && poisonedVirtualRegisters[exit.variableForIndex(index)]) {
+ if (operands.isVariable(index) && poisonedVirtualRegisters[operands.variableForIndex(index)]) {
m_jit.storeDouble(recovery.fpr(), scratchDataBuffer + currentPoisonIndex);
- m_poisonScratchIndices[exit.variableForIndex(index)] = currentPoisonIndex;
+ m_poisonScratchIndices[operands.variableForIndex(index)] = currentPoisonIndex;
currentPoisonIndex++;
} else
- m_jit.storeDouble(recovery.fpr(), AssemblyHelpers::addressFor((VirtualRegister)exit.operandForIndex(index)));
+ m_jit.storeDouble(recovery.fpr(), AssemblyHelpers::addressFor((VirtualRegister)operands.operandForIndex(index)));
}
}
@@ -356,8 +357,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
// that is far from guaranteed.
unsigned displacementIndex = 0;
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
switch (recovery.technique()) {
case DisplacedInRegisterFile:
m_jit.load32(AssemblyHelpers::payloadFor(recovery.virtualRegister()), GPRInfo::toRegister(displacementIndex++));
@@ -381,15 +382,15 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
}
displacementIndex = 0;
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
switch (recovery.technique()) {
case DisplacedInRegisterFile:
case Int32DisplacedInRegisterFile:
case CellDisplacedInRegisterFile:
case BooleanDisplacedInRegisterFile:
- m_jit.store32(GPRInfo::toRegister(displacementIndex++), AssemblyHelpers::payloadFor((VirtualRegister)exit.operandForIndex(index)));
- m_jit.store32(GPRInfo::toRegister(displacementIndex++), AssemblyHelpers::tagFor((VirtualRegister)exit.operandForIndex(index)));
+ m_jit.store32(GPRInfo::toRegister(displacementIndex++), AssemblyHelpers::payloadFor((VirtualRegister)operands.operandForIndex(index)));
+ m_jit.store32(GPRInfo::toRegister(displacementIndex++), AssemblyHelpers::tagFor((VirtualRegister)operands.operandForIndex(index)));
break;
default:
break;
@@ -414,8 +415,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
// to their new (old JIT) locations.
unsigned scratchIndex = numberOfPoisonedVirtualRegisters;
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
switch (recovery.technique()) {
case DisplacedInRegisterFile:
m_jit.load32(AssemblyHelpers::payloadFor(recovery.virtualRegister()), GPRInfo::regT0);
@@ -436,30 +437,30 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
}
scratchIndex = numberOfPoisonedVirtualRegisters;
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
switch (recovery.technique()) {
case DisplacedInRegisterFile:
m_jit.load32(reinterpret_cast<char*>(scratchDataBuffer + scratchIndex) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload), GPRInfo::regT0);
m_jit.load32(reinterpret_cast<char*>(scratchDataBuffer + scratchIndex) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag), GPRInfo::regT1);
- m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor((VirtualRegister)exit.operandForIndex(index)));
- m_jit.store32(GPRInfo::regT1, AssemblyHelpers::tagFor((VirtualRegister)exit.operandForIndex(index)));
+ m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor((VirtualRegister)operands.operandForIndex(index)));
+ m_jit.store32(GPRInfo::regT1, AssemblyHelpers::tagFor((VirtualRegister)operands.operandForIndex(index)));
scratchIndex++;
break;
case Int32DisplacedInRegisterFile:
m_jit.load32(reinterpret_cast<char*>(scratchDataBuffer + scratchIndex++) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload), GPRInfo::regT0);
- m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::Int32Tag), AssemblyHelpers::tagFor((VirtualRegister)exit.operandForIndex(index)));
- m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor((VirtualRegister)exit.operandForIndex(index)));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::Int32Tag), AssemblyHelpers::tagFor((VirtualRegister)operands.operandForIndex(index)));
+ m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor((VirtualRegister)operands.operandForIndex(index)));
break;
case CellDisplacedInRegisterFile:
m_jit.load32(reinterpret_cast<char*>(scratchDataBuffer + scratchIndex++) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload), GPRInfo::regT0);
- m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::CellTag), AssemblyHelpers::tagFor((VirtualRegister)exit.operandForIndex(index)));
- m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor((VirtualRegister)exit.operandForIndex(index)));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::CellTag), AssemblyHelpers::tagFor((VirtualRegister)operands.operandForIndex(index)));
+ m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor((VirtualRegister)operands.operandForIndex(index)));
break;
case BooleanDisplacedInRegisterFile:
m_jit.load32(reinterpret_cast<char*>(scratchDataBuffer + scratchIndex++) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload), GPRInfo::regT0);
- m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::BooleanTag), AssemblyHelpers::tagFor((VirtualRegister)exit.operandForIndex(index)));
- m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor((VirtualRegister)exit.operandForIndex(index)));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::BooleanTag), AssemblyHelpers::tagFor((VirtualRegister)operands.operandForIndex(index)));
+ m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor((VirtualRegister)operands.operandForIndex(index)));
break;
default:
break;
@@ -473,11 +474,11 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
// 9) Dump all poisoned virtual registers.
if (numberOfPoisonedVirtualRegisters) {
- for (int virtualRegister = 0; virtualRegister < (int)exit.m_variables.size(); ++virtualRegister) {
+ for (int virtualRegister = 0; virtualRegister < (int)operands.numberOfLocals(); ++virtualRegister) {
if (!poisonedVirtualRegisters[virtualRegister])
continue;
- const ValueRecovery& recovery = exit.m_variables[virtualRegister];
+ const ValueRecovery& recovery = operands.local(virtualRegister);
switch (recovery.technique()) {
case InGPR:
case UnboxedInt32InGPR:
@@ -519,16 +520,16 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
m_jit.move(AssemblyHelpers::TrustedImm32(jsUndefined().tag()), GPRInfo::regT1);
}
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
if (recovery.technique() != Constant)
continue;
if (recovery.constant().isUndefined()) {
- m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor((VirtualRegister)exit.operandForIndex(index)));
- m_jit.store32(GPRInfo::regT1, AssemblyHelpers::tagFor((VirtualRegister)exit.operandForIndex(index)));
+ m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor((VirtualRegister)operands.operandForIndex(index)));
+ m_jit.store32(GPRInfo::regT1, AssemblyHelpers::tagFor((VirtualRegister)operands.operandForIndex(index)));
} else {
- m_jit.store32(AssemblyHelpers::TrustedImm32(recovery.constant().payload()), AssemblyHelpers::payloadFor((VirtualRegister)exit.operandForIndex(index)));
- m_jit.store32(AssemblyHelpers::TrustedImm32(recovery.constant().tag()), AssemblyHelpers::tagFor((VirtualRegister)exit.operandForIndex(index)));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(recovery.constant().payload()), AssemblyHelpers::payloadFor((VirtualRegister)operands.operandForIndex(index)));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(recovery.constant().tag()), AssemblyHelpers::tagFor((VirtualRegister)operands.operandForIndex(index)));
}
}
}
@@ -611,11 +612,11 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
// registers.
if (haveArguments) {
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
if (recovery.technique() != ArgumentsThatWereNotCreated)
continue;
- int operand = exit.operandForIndex(index);
+ int operand = operands.operandForIndex(index);
// Find the right inline call frame.
InlineCallFrame* inlineCallFrame = 0;
for (InlineCallFrame* current = exit.m_codeOrigin.inlineCallFrame;
diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp
index 33ba69a35..2f38ba79b 100644
--- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp
@@ -29,10 +29,11 @@
#if ENABLE(DFG_JIT) && USE(JSVALUE64)
#include "DFGOperations.h"
+#include <wtf/DataLog.h>
namespace JSC { namespace DFG {
-void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* recovery)
+void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecovery>& operands, SpeculationRecovery* recovery)
{
// 1) Pro-forma stuff.
#if DFG_ENABLE(DEBUG_VERBOSE)
@@ -44,7 +45,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
dataLog(" -> %p ", codeOrigin.inlineCallFrame->executable.get());
}
dataLog(") ");
- exit.dump(WTF::dataFile());
+ dumpOperands(operands, WTF::dataFile());
#endif
#if DFG_ENABLE(VERBOSE_SPECULATION_FAILURE)
SpeculationFailureDebugInfo* debugInfo = new SpeculationFailureDebugInfo;
@@ -110,7 +111,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
// GPRInfo::numberOfRegisters of them. Also see if there are any constants,
// any undefined slots, any FPR slots, and any unboxed ints.
- Vector<bool> poisonedVirtualRegisters(exit.m_variables.size());
+ Vector<bool> poisonedVirtualRegisters(operands.numberOfLocals());
for (unsigned i = 0; i < poisonedVirtualRegisters.size(); ++i)
poisonedVirtualRegisters[i] = false;
@@ -129,8 +130,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
bool haveUInt32s = false;
bool haveArguments = false;
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
switch (recovery.technique()) {
case Int32DisplacedInRegisterFile:
case DoubleDisplacedInRegisterFile:
@@ -145,8 +146,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
// to ensure this happens efficiently. Note that we expect this case
// to be rare, so the handling of it is optimized for the cases in
// which it does not happen.
- if (recovery.virtualRegister() < (int)exit.m_variables.size()) {
- switch (exit.m_variables[recovery.virtualRegister()].technique()) {
+ if (recovery.virtualRegister() < (int)operands.numberOfLocals()) {
+ switch (operands.local(recovery.virtualRegister()).technique()) {
case InGPR:
case UnboxedInt32InGPR:
case UInt32InGPR:
@@ -224,8 +225,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
// 5) Perform all reboxing of integers.
if (haveUnboxedInt32s || haveUInt32s) {
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
switch (recovery.technique()) {
case UnboxedInt32InGPR:
if (recovery.gpr() != alreadyBoxed)
@@ -233,7 +234,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
break;
case AlreadyInRegisterFileAsUnboxedInt32:
- m_jit.store32(AssemblyHelpers::TrustedImm32(static_cast<uint32_t>(TagTypeNumber >> 32)), AssemblyHelpers::tagFor(static_cast<VirtualRegister>(exit.operandForIndex(index))));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(static_cast<uint32_t>(TagTypeNumber >> 32)), AssemblyHelpers::tagFor(static_cast<VirtualRegister>(operands.operandForIndex(index))));
break;
case UInt32InGPR: {
@@ -284,19 +285,19 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
// Note that GPRs do not have a fast change (like haveFPRs) because we expect that
// most OSR failure points will have at least one GPR that needs to be dumped.
- initializePoisoned(exit.m_variables.size());
+ initializePoisoned(operands.numberOfLocals());
unsigned currentPoisonIndex = 0;
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
- int operand = exit.operandForIndex(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
+ int operand = operands.operandForIndex(index);
switch (recovery.technique()) {
case InGPR:
case UnboxedInt32InGPR:
case UInt32InGPR:
- if (exit.isVariable(index) && poisonedVirtualRegisters[exit.variableForIndex(index)]) {
+ if (operands.isVariable(index) && poisonedVirtualRegisters[operands.variableForIndex(index)]) {
m_jit.storePtr(recovery.gpr(), scratchDataBuffer + currentPoisonIndex);
- m_poisonScratchIndices[exit.variableForIndex(index)] = currentPoisonIndex;
+ m_poisonScratchIndices[operands.variableForIndex(index)] = currentPoisonIndex;
currentPoisonIndex++;
} else
m_jit.storePtr(recovery.gpr(), AssemblyHelpers::addressFor((VirtualRegister)operand));
@@ -311,8 +312,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
if (haveFPRs) {
// 7) Box all doubles (relies on there being more GPRs than FPRs)
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
if (recovery.technique() != InFPR)
continue;
FPRReg fpr = recovery.fpr();
@@ -323,17 +324,17 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
// 8) Dump all doubles into the register file, or to the scratch storage if
// the destination virtual register is poisoned.
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
if (recovery.technique() != InFPR)
continue;
GPRReg gpr = GPRInfo::toRegister(FPRInfo::toIndex(recovery.fpr()));
- if (exit.isVariable(index) && poisonedVirtualRegisters[exit.variableForIndex(index)]) {
+ if (operands.isVariable(index) && poisonedVirtualRegisters[operands.variableForIndex(index)]) {
m_jit.storePtr(gpr, scratchDataBuffer + currentPoisonIndex);
- m_poisonScratchIndices[exit.variableForIndex(index)] = currentPoisonIndex;
+ m_poisonScratchIndices[operands.variableForIndex(index)] = currentPoisonIndex;
currentPoisonIndex++;
} else
- m_jit.storePtr(gpr, AssemblyHelpers::addressFor((VirtualRegister)exit.operandForIndex(index)));
+ m_jit.storePtr(gpr, AssemblyHelpers::addressFor((VirtualRegister)operands.operandForIndex(index)));
}
}
@@ -341,13 +342,13 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
// 9) Box all unboxed doubles in the register file.
if (haveUnboxedDoubles) {
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
if (recovery.technique() != AlreadyInRegisterFileAsUnboxedDouble)
continue;
- m_jit.loadDouble(AssemblyHelpers::addressFor((VirtualRegister)exit.operandForIndex(index)), FPRInfo::fpRegT0);
+ m_jit.loadDouble(AssemblyHelpers::addressFor((VirtualRegister)operands.operandForIndex(index)), FPRInfo::fpRegT0);
m_jit.boxDouble(FPRInfo::fpRegT0, GPRInfo::regT0);
- m_jit.storePtr(GPRInfo::regT0, AssemblyHelpers::addressFor((VirtualRegister)exit.operandForIndex(index)));
+ m_jit.storePtr(GPRInfo::regT0, AssemblyHelpers::addressFor((VirtualRegister)operands.operandForIndex(index)));
}
}
@@ -363,8 +364,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
// that is far from guaranteed.
unsigned displacementIndex = 0;
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
switch (recovery.technique()) {
case DisplacedInRegisterFile:
m_jit.loadPtr(AssemblyHelpers::addressFor(recovery.virtualRegister()), GPRInfo::toRegister(displacementIndex++));
@@ -390,13 +391,13 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
}
displacementIndex = 0;
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
switch (recovery.technique()) {
case DisplacedInRegisterFile:
case Int32DisplacedInRegisterFile:
case DoubleDisplacedInRegisterFile:
- m_jit.storePtr(GPRInfo::toRegister(displacementIndex++), AssemblyHelpers::addressFor((VirtualRegister)exit.operandForIndex(index)));
+ m_jit.storePtr(GPRInfo::toRegister(displacementIndex++), AssemblyHelpers::addressFor((VirtualRegister)operands.operandForIndex(index)));
break;
default:
@@ -422,8 +423,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
// to their new (old JIT) locations.
unsigned scratchIndex = numberOfPoisonedVirtualRegisters;
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
switch (recovery.technique()) {
case DisplacedInRegisterFile:
@@ -451,14 +452,14 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
}
scratchIndex = numberOfPoisonedVirtualRegisters;
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
switch (recovery.technique()) {
case DisplacedInRegisterFile:
case Int32DisplacedInRegisterFile:
case DoubleDisplacedInRegisterFile:
m_jit.loadPtr(scratchDataBuffer + scratchIndex++, GPRInfo::regT0);
- m_jit.storePtr(GPRInfo::regT0, AssemblyHelpers::addressFor((VirtualRegister)exit.operandForIndex(index)));
+ m_jit.storePtr(GPRInfo::regT0, AssemblyHelpers::addressFor((VirtualRegister)operands.operandForIndex(index)));
break;
default:
@@ -473,11 +474,11 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
// 11) Dump all poisoned virtual registers.
if (numberOfPoisonedVirtualRegisters) {
- for (int virtualRegister = 0; virtualRegister < (int)exit.m_variables.size(); ++virtualRegister) {
+ for (int virtualRegister = 0; virtualRegister < (int)operands.numberOfLocals(); ++virtualRegister) {
if (!poisonedVirtualRegisters[virtualRegister])
continue;
- const ValueRecovery& recovery = exit.m_variables[virtualRegister];
+ const ValueRecovery& recovery = operands.local(virtualRegister);
switch (recovery.technique()) {
case InGPR:
case UnboxedInt32InGPR:
@@ -500,14 +501,14 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
if (haveUndefined)
m_jit.move(AssemblyHelpers::TrustedImmPtr(JSValue::encode(jsUndefined())), GPRInfo::regT0);
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
if (recovery.technique() != Constant)
continue;
if (recovery.constant().isUndefined())
- m_jit.storePtr(GPRInfo::regT0, AssemblyHelpers::addressFor((VirtualRegister)exit.operandForIndex(index)));
+ m_jit.storePtr(GPRInfo::regT0, AssemblyHelpers::addressFor((VirtualRegister)operands.operandForIndex(index)));
else
- m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(JSValue::encode(recovery.constant())), AssemblyHelpers::addressFor((VirtualRegister)exit.operandForIndex(index)));
+ m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(JSValue::encode(recovery.constant())), AssemblyHelpers::addressFor((VirtualRegister)operands.operandForIndex(index)));
}
}
@@ -586,11 +587,11 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
// registers.
if (haveArguments) {
- for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
- const ValueRecovery& recovery = exit.valueRecovery(index);
+ for (size_t index = 0; index < operands.size(); ++index) {
+ const ValueRecovery& recovery = operands[index];
if (recovery.technique() != ArgumentsThatWereNotCreated)
continue;
- int operand = exit.operandForIndex(index);
+ int operand = operands.operandForIndex(index);
// Find the right inline call frame.
InlineCallFrame* inlineCallFrame = 0;
for (InlineCallFrame* current = exit.m_codeOrigin.inlineCallFrame;
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index 11362f432..5d6575a6f 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -140,6 +140,62 @@
"b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \
);
+#elif COMPILER(GCC) && CPU(ARM_TRADITIONAL)
+
+#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \
+ asm ( \
+ ".text" "\n" \
+ ".globl " SYMBOL_STRING(function) "\n" \
+ HIDE_SYMBOL(function) "\n" \
+ INLINE_ARM_FUNCTION(function) \
+ SYMBOL_STRING(function) ":" "\n" \
+ "mov a2, lr" "\n" \
+ "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \
+ );
+
+#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) \
+ asm ( \
+ ".text" "\n" \
+ ".globl " SYMBOL_STRING(function) "\n" \
+ HIDE_SYMBOL(function) "\n" \
+ INLINE_ARM_FUNCTION(function) \
+ SYMBOL_STRING(function) ":" "\n" \
+ "mov a4, lr" "\n" \
+ "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \
+ );
+
+// EncodedJSValue in JSVALUE32_64 is a 64-bit integer. When being compiled in ARM EABI, it must be aligned even-numbered register (r0, r2 or [sp]).
+// As a result, return address will be at a 4-byte further location in the following cases.
+#if COMPILER_SUPPORTS(EABI) && CPU(ARM)
+#define INSTRUCTION_STORE_RETURN_ADDRESS_EJI "str lr, [sp, #4]"
+#define INSTRUCTION_STORE_RETURN_ADDRESS_EJCI "str lr, [sp, #8]"
+#else
+#define INSTRUCTION_STORE_RETURN_ADDRESS_EJI "str lr, [sp, #0]"
+#define INSTRUCTION_STORE_RETURN_ADDRESS_EJCI "str lr, [sp, #4]"
+#endif
+
+#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) \
+ asm ( \
+ ".text" "\n" \
+ ".globl " SYMBOL_STRING(function) "\n" \
+ HIDE_SYMBOL(function) "\n" \
+ INLINE_ARM_FUNCTION(function) \
+ SYMBOL_STRING(function) ":" "\n" \
+ INSTRUCTION_STORE_RETURN_ADDRESS_EJI "\n" \
+ "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \
+ );
+
+#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) \
+ asm ( \
+ ".text" "\n" \
+ ".globl " SYMBOL_STRING(function) "\n" \
+ HIDE_SYMBOL(function) "\n" \
+ INLINE_ARM_FUNCTION(function) \
+ SYMBOL_STRING(function) ":" "\n" \
+ INSTRUCTION_STORE_RETURN_ADDRESS_EJCI "\n" \
+ "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \
+ );
+
#endif
#define P_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \
@@ -1250,15 +1306,13 @@ void DFG_OPERATION debugOperationPrintSpeculationFailure(ExecState* exec, void*
CodeBlock* alternative = codeBlock->alternative();
dataLog("Speculation failure in %p at @%u with executeCounter = %s, "
"reoptimizationRetryCounter = %u, optimizationDelayCounter = %u, "
- "success/fail %u/(%u+%u)\n",
+ "osrExitCounter = %u\n",
codeBlock,
debugInfo->nodeIndex,
alternative ? alternative->jitExecuteCounter().status() : 0,
alternative ? alternative->reoptimizationRetryCounter() : 0,
alternative ? alternative->optimizationDelayCounter() : 0,
- codeBlock->speculativeSuccessCounter(),
- codeBlock->speculativeFailCounter(),
- codeBlock->forcedOSRExitCounter());
+ codeBlock->osrExitCounter());
}
#endif
@@ -1324,6 +1378,17 @@ SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
"mov r0, r5" "\n"
"b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n"
);
+#elif CPU(ARM_TRADITIONAL)
+asm (
+".text" "\n"
+".globl " SYMBOL_STRING(getHostCallReturnValue) "\n"
+HIDE_SYMBOL(getHostCallReturnValue) "\n"
+INLINE_ARM_FUNCTION(getHostCallReturnValue)
+SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
+ "ldr r5, [r5, #-40]" "\n"
+ "mov r0, r5" "\n"
+ "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n"
+);
#endif
extern "C" EncodedJSValue HOST_CALL_RETURN_VALUE_OPTION getHostCallReturnValueWithExecState(ExecState* exec)
diff --git a/Source/JavaScriptCore/dfg/DFGPhase.h b/Source/JavaScriptCore/dfg/DFGPhase.h
index 53055a215..80fd6914a 100644
--- a/Source/JavaScriptCore/dfg/DFGPhase.h
+++ b/Source/JavaScriptCore/dfg/DFGPhase.h
@@ -49,6 +49,8 @@ public:
endPhase();
}
+ const char* name() const { return m_name; }
+
// Each phase must have a run() method.
protected:
@@ -76,17 +78,28 @@ private:
};
template<typename PhaseType>
+bool runAndLog(PhaseType& phase)
+{
+ bool result = phase.run();
+#if DFG_ENABLE(DEBUG_VERBOSE)
+ if (result)
+ dataLog("Phase %s changed the IR.\n", phase.name());
+#endif
+ return result;
+}
+
+template<typename PhaseType>
bool runPhase(Graph& graph)
{
PhaseType phase(graph);
- return phase.run();
+ return runAndLog(phase);
}
template<typename PhaseType, typename ArgumentType1>
bool runPhase(Graph& graph, ArgumentType1 arg1)
{
PhaseType phase(graph, arg1);
- return phase.run();
+ return runAndLog(phase);
}
} } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index 0bd81ec44..320eb6cb6 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -908,6 +908,7 @@ private:
bool performPredictionPropagation(Graph& graph)
{
+ SamplingRegion samplingRegion("DFG Prediction Propagation Phase");
return runPhase<PredictionPropagationPhase>(graph);
}
diff --git a/Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.cpp b/Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.cpp
index 5453469fe..32e4ef157 100644
--- a/Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.cpp
@@ -169,6 +169,7 @@ private:
bool performRedundantPhiElimination(Graph& graph)
{
+ SamplingRegion samplingRegion("DFG Redundant Phi Elimination Phase");
return runPhase<RedundantPhiEliminationPhase>(graph);
}
diff --git a/Source/JavaScriptCore/dfg/DFGRepatch.cpp b/Source/JavaScriptCore/dfg/DFGRepatch.cpp
index 9c3391be5..752316f9c 100644
--- a/Source/JavaScriptCore/dfg/DFGRepatch.cpp
+++ b/Source/JavaScriptCore/dfg/DFGRepatch.cpp
@@ -30,6 +30,7 @@
#include "DFGCCallHelpers.h"
#include "DFGSpeculativeJIT.h"
+#include "GCAwareJITStubRoutine.h"
#include "LinkBuffer.h"
#include "Operations.h"
#include "PolymorphicPutByIdList.h"
@@ -43,7 +44,7 @@ static void dfgRepatchCall(CodeBlock* codeblock, CodeLocationCall call, Function
repatchBuffer.relink(call, newCalleeFunction);
}
-static void dfgRepatchByIdSelfAccess(CodeBlock* codeBlock, StructureStubInfo& stubInfo, Structure* structure, size_t offset, const FunctionPtr &slowPathFunction, bool compact)
+static void dfgRepatchByIdSelfAccess(CodeBlock* codeBlock, StructureStubInfo& stubInfo, Structure* structure, PropertyOffset offset, const FunctionPtr &slowPathFunction, bool compact)
{
RepatchBuffer repatchBuffer(codeBlock);
@@ -52,18 +53,19 @@ static void dfgRepatchByIdSelfAccess(CodeBlock* codeBlock, StructureStubInfo& st
// Patch the structure check & the offset of the load.
repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelPtrAtOffset(-(intptr_t)stubInfo.patch.dfg.deltaCheckImmToCall), structure);
+ repatchBuffer.setLoadInstructionIsActive(stubInfo.callReturnLocation.convertibleLoadAtOffset(stubInfo.patch.dfg.deltaCallToStorageLoad), isOutOfLineOffset(offset));
#if USE(JSVALUE64)
if (compact)
- repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelCompactAtOffset(stubInfo.patch.dfg.deltaCallToLoadOrStore), sizeof(JSValue) * offset);
+ repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelCompactAtOffset(stubInfo.patch.dfg.deltaCallToLoadOrStore), offsetRelativeToPatchedStorage(offset));
else
- repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabel32AtOffset(stubInfo.patch.dfg.deltaCallToLoadOrStore), sizeof(JSValue) * offset);
+ repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabel32AtOffset(stubInfo.patch.dfg.deltaCallToLoadOrStore), offsetRelativeToPatchedStorage(offset));
#elif USE(JSVALUE32_64)
if (compact) {
- repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelCompactAtOffset(stubInfo.patch.dfg.deltaCallToTagLoadOrStore), sizeof(JSValue) * offset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
- repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelCompactAtOffset(stubInfo.patch.dfg.deltaCallToPayloadLoadOrStore), sizeof(JSValue) * offset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
+ repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelCompactAtOffset(stubInfo.patch.dfg.deltaCallToTagLoadOrStore), offsetRelativeToPatchedStorage(offset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
+ repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelCompactAtOffset(stubInfo.patch.dfg.deltaCallToPayloadLoadOrStore), offsetRelativeToPatchedStorage(offset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
} else {
- repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabel32AtOffset(stubInfo.patch.dfg.deltaCallToTagLoadOrStore), sizeof(JSValue) * offset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
- repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabel32AtOffset(stubInfo.patch.dfg.deltaCallToPayloadLoadOrStore), sizeof(JSValue) * offset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
+ repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabel32AtOffset(stubInfo.patch.dfg.deltaCallToTagLoadOrStore), offsetRelativeToPatchedStorage(offset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
+ repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabel32AtOffset(stubInfo.patch.dfg.deltaCallToPayloadLoadOrStore), offsetRelativeToPatchedStorage(offset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
}
#endif
}
@@ -105,7 +107,7 @@ static void linkRestoreScratch(LinkBuffer& patchBuffer, bool needToRestoreScratc
linkRestoreScratch(patchBuffer, needToRestoreScratch, success, fail, failureCases, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.dfg.deltaCallToDone), stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.dfg.deltaCallToSlowCase));
}
-static void generateProtoChainAccessStub(ExecState* exec, StructureStubInfo& stubInfo, StructureChain* chain, size_t count, size_t offset, Structure* structure, CodeLocationLabel successLabel, CodeLocationLabel slowCaseLabel, MacroAssemblerCodeRef& stubRoutine)
+static void generateProtoChainAccessStub(ExecState* exec, StructureStubInfo& stubInfo, StructureChain* chain, size_t count, PropertyOffset offset, Structure* structure, CodeLocationLabel successLabel, CodeLocationLabel slowCaseLabel, RefPtr<JITStubRoutine>& stubRoutine)
{
JSGlobalData* globalData = &exec->globalData();
@@ -139,13 +141,23 @@ static void generateProtoChainAccessStub(ExecState* exec, StructureStubInfo& stu
currStructure = it->get();
}
- stubJit.loadPtr(protoObject->addressOfPropertyStorage(), resultGPR);
+ if (isInlineOffset(offset)) {
#if USE(JSVALUE64)
- stubJit.loadPtr(MacroAssembler::Address(resultGPR, offset * sizeof(WriteBarrier<Unknown>)), resultGPR);
+ stubJit.loadPtr(protoObject->locationForOffset(offset), resultGPR);
#elif USE(JSVALUE32_64)
- stubJit.load32(MacroAssembler::Address(resultGPR, offset * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
- stubJit.load32(MacroAssembler::Address(resultGPR, offset * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultGPR);
+ stubJit.move(MacroAssembler::TrustedImmPtr(protoObject->locationForOffset(offset)), resultGPR);
+ stubJit.load32(MacroAssembler::Address(resultGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
+ stubJit.load32(MacroAssembler::Address(resultGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultGPR);
#endif
+ } else {
+ stubJit.loadPtr(protoObject->addressOfOutOfLineStorage(), resultGPR);
+#if USE(JSVALUE64)
+ stubJit.loadPtr(MacroAssembler::Address(resultGPR, offsetInOutOfLineStorage(offset) * sizeof(WriteBarrier<Unknown>)), resultGPR);
+#elif USE(JSVALUE32_64)
+ stubJit.load32(MacroAssembler::Address(resultGPR, offsetInOutOfLineStorage(offset) * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
+ stubJit.load32(MacroAssembler::Address(resultGPR, offsetInOutOfLineStorage(offset) * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultGPR);
+#endif
+ }
MacroAssembler::Jump success, fail;
@@ -155,7 +167,7 @@ static void generateProtoChainAccessStub(ExecState* exec, StructureStubInfo& stu
linkRestoreScratch(patchBuffer, needToRestoreScratch, success, fail, failureCases, successLabel, slowCaseLabel);
- stubRoutine = FINALIZE_CODE(
+ stubRoutine = FINALIZE_CODE_FOR_STUB(
patchBuffer,
("DFG prototype chain access stub for CodeBlock %p, return point %p",
exec->codeBlock(), successLabel.executableAddress()));
@@ -209,14 +221,14 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier
linkRestoreScratch(patchBuffer, needToRestoreScratch, stubInfo, success, fail, failureCases);
- stubInfo.stubRoutine = FINALIZE_CODE(
+ stubInfo.stubRoutine = FINALIZE_CODE_FOR_STUB(
patchBuffer,
("DFG GetById array length stub for CodeBlock %p, return point %p",
exec->codeBlock(), stubInfo.callReturnLocation.labelAtOffset(
stubInfo.patch.dfg.deltaCallToDone).executableAddress()));
RepatchBuffer repatchBuffer(codeBlock);
- repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine.code()));
+ repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine->code().code()));
repatchBuffer.relink(stubInfo.callReturnLocation, operationGetById);
return true;
@@ -253,7 +265,7 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier
if (slot.cachedPropertyType() != PropertySlot::Value)
return false;
- size_t offset = slot.cachedOffset();
+ PropertyOffset offset = slot.cachedOffset();
size_t count = normalizePrototypeChain(exec, baseValue, slot.slotBase(), propertyName, offset);
if (!count)
return false;
@@ -265,7 +277,7 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier
generateProtoChainAccessStub(exec, stubInfo, prototypeChain, count, offset, structure, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.dfg.deltaCallToDone), stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.dfg.deltaCallToSlowCase), stubInfo.stubRoutine);
RepatchBuffer repatchBuffer(codeBlock);
- repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine.code()));
+ repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine->code().code()));
repatchBuffer.relink(stubInfo.callReturnLocation, operationGetByIdProtoBuildList);
stubInfo.initGetByIdChain(*globalData, codeBlock->ownerExecutable(), structure, prototypeChain, count, true);
@@ -312,7 +324,7 @@ static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identi
listIndex = 0;
} else if (stubInfo.accessType == access_get_by_id_self) {
ASSERT(!stubInfo.stubRoutine);
- polymorphicStructureList = new PolymorphicAccessStructureList(*globalData, codeBlock->ownerExecutable(), MacroAssemblerCodeRef::createSelfManagedCodeRef(stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.dfg.deltaCallToSlowCase)), stubInfo.u.getByIdSelf.baseObjectStructure.get(), true);
+ polymorphicStructureList = new PolymorphicAccessStructureList(*globalData, codeBlock->ownerExecutable(), JITStubRoutine::createSelfManagedRoutine(stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.dfg.deltaCallToSlowCase)), stubInfo.u.getByIdSelf.baseObjectStructure.get(), true);
stubInfo.initGetByIdSelfList(polymorphicStructureList, 1);
listIndex = 1;
} else {
@@ -349,12 +361,20 @@ static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identi
|| slot.cachedPropertyType() == PropertySlot::Custom) {
if (slot.cachedPropertyType() == PropertySlot::Getter) {
ASSERT(baseGPR != scratchGPR);
- stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
+ if (isInlineOffset(slot.cachedOffset())) {
#if USE(JSVALUE64)
- stubJit.loadPtr(MacroAssembler::Address(scratchGPR, slot.cachedOffset() * sizeof(JSValue)), scratchGPR);
-#elif USE(JSVALUE32_64)
- stubJit.load32(MacroAssembler::Address(scratchGPR, slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), scratchGPR);
+ stubJit.loadPtr(MacroAssembler::Address(baseGPR, offsetRelativeToBase(slot.cachedOffset())), scratchGPR);
+#else
+ stubJit.load32(MacroAssembler::Address(baseGPR, offsetRelativeToBase(slot.cachedOffset())), scratchGPR);
#endif
+ } else {
+ stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR);
+#if USE(JSVALUE64)
+ stubJit.loadPtr(MacroAssembler::Address(scratchGPR, offsetRelativeToBase(slot.cachedOffset())), scratchGPR);
+#else
+ stubJit.load32(MacroAssembler::Address(scratchGPR, offsetRelativeToBase(slot.cachedOffset())), scratchGPR);
+#endif
+ }
stubJit.setupArgumentsWithExecState(baseGPR, scratchGPR);
operationFunction = operationCallGetter;
} else {
@@ -385,13 +405,27 @@ static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identi
handlerCall = stubJit.call();
stubJit.jump(GPRInfo::returnValueGPR2);
} else {
- stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), resultGPR);
+ if (isInlineOffset(slot.cachedOffset())) {
#if USE(JSVALUE64)
- stubJit.loadPtr(MacroAssembler::Address(resultGPR, slot.cachedOffset() * sizeof(JSValue)), resultGPR);
-#elif USE(JSVALUE32_64)
- stubJit.load32(MacroAssembler::Address(resultGPR, slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
- stubJit.load32(MacroAssembler::Address(resultGPR, slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultGPR);
+ stubJit.loadPtr(MacroAssembler::Address(baseGPR, offsetRelativeToBase(slot.cachedOffset())), resultGPR);
+#else
+ if (baseGPR == resultTagGPR) {
+ stubJit.load32(MacroAssembler::Address(baseGPR, offsetRelativeToBase(slot.cachedOffset()) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultGPR);
+ stubJit.load32(MacroAssembler::Address(baseGPR, offsetRelativeToBase(slot.cachedOffset()) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
+ } else {
+ stubJit.load32(MacroAssembler::Address(baseGPR, offsetRelativeToBase(slot.cachedOffset()) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
+ stubJit.load32(MacroAssembler::Address(baseGPR, offsetRelativeToBase(slot.cachedOffset()) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultGPR);
+ }
+#endif
+ } else {
+ stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), resultGPR);
+#if USE(JSVALUE64)
+ stubJit.loadPtr(MacroAssembler::Address(resultGPR, offsetRelativeToBase(slot.cachedOffset())), resultGPR);
+#else
+ stubJit.load32(MacroAssembler::Address(resultGPR, offsetRelativeToBase(slot.cachedOffset()) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
+ stubJit.load32(MacroAssembler::Address(resultGPR, offsetRelativeToBase(slot.cachedOffset()) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultGPR);
#endif
+ }
success = stubJit.jump();
isDirect = true;
}
@@ -400,7 +434,7 @@ static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identi
CodeLocationLabel lastProtoBegin;
if (listIndex)
- lastProtoBegin = CodeLocationLabel(polymorphicStructureList->list[listIndex - 1].stubRoutine.code());
+ lastProtoBegin = CodeLocationLabel(polymorphicStructureList->list[listIndex - 1].stubRoutine->code().code());
else
lastProtoBegin = stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.dfg.deltaCallToSlowCase);
ASSERT(!!lastProtoBegin);
@@ -412,17 +446,23 @@ static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identi
patchBuffer.link(handlerCall, lookupExceptionHandlerInStub);
}
- MacroAssemblerCodeRef stubRoutine = FINALIZE_CODE(
- patchBuffer,
- ("DFG GetById polymorphic list access for CodeBlock %p, return point %p",
- exec->codeBlock(), stubInfo.callReturnLocation.labelAtOffset(
- stubInfo.patch.dfg.deltaCallToDone).executableAddress()));
+ RefPtr<JITStubRoutine> stubRoutine =
+ createJITStubRoutine(
+ FINALIZE_CODE(
+ patchBuffer,
+ ("DFG GetById polymorphic list access for CodeBlock %p, return point %p",
+ exec->codeBlock(), stubInfo.callReturnLocation.labelAtOffset(
+ stubInfo.patch.dfg.deltaCallToDone).executableAddress())),
+ *globalData,
+ codeBlock->ownerExecutable(),
+ slot.cachedPropertyType() == PropertySlot::Getter
+ || slot.cachedPropertyType() == PropertySlot::Custom);
polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), stubRoutine, structure, isDirect);
CodeLocationJump jumpLocation = stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck);
RepatchBuffer repatchBuffer(codeBlock);
- repatchBuffer.relink(jumpLocation, CodeLocationLabel(stubRoutine.code()));
+ repatchBuffer.relink(jumpLocation, CodeLocationLabel(stubRoutine->code().code()));
if (listIndex < (POLYMORPHIC_LIST_CACHE_SIZE - 1))
return true;
@@ -450,7 +490,7 @@ static bool tryBuildGetByIDProtoList(ExecState* exec, JSValue baseValue, const I
ASSERT(slot.slotBase().isObject());
- size_t offset = slot.cachedOffset();
+ PropertyOffset offset = slot.cachedOffset();
size_t count = normalizePrototypeChain(exec, baseValue, slot.slotBase(), propertyName, offset);
if (!count)
return false;
@@ -466,7 +506,7 @@ static bool tryBuildGetByIDProtoList(ExecState* exec, JSValue baseValue, const I
if (stubInfo.accessType == access_get_by_id_chain) {
ASSERT(!!stubInfo.stubRoutine);
polymorphicStructureList = new PolymorphicAccessStructureList(*globalData, codeBlock->ownerExecutable(), stubInfo.stubRoutine, stubInfo.u.getByIdChain.baseObjectStructure.get(), stubInfo.u.getByIdChain.chain.get(), true);
- stubInfo.stubRoutine = MacroAssemblerCodeRef();
+ stubInfo.stubRoutine.clear();
stubInfo.initGetByIdProtoList(polymorphicStructureList, 1);
} else {
ASSERT(stubInfo.accessType == access_get_by_id_proto_list);
@@ -477,10 +517,10 @@ static bool tryBuildGetByIDProtoList(ExecState* exec, JSValue baseValue, const I
if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) {
stubInfo.u.getByIdProtoList.listSize++;
- CodeLocationLabel lastProtoBegin = CodeLocationLabel(polymorphicStructureList->list[listIndex - 1].stubRoutine.code());
+ CodeLocationLabel lastProtoBegin = CodeLocationLabel(polymorphicStructureList->list[listIndex - 1].stubRoutine->code().code());
ASSERT(!!lastProtoBegin);
- MacroAssemblerCodeRef stubRoutine;
+ RefPtr<JITStubRoutine> stubRoutine;
generateProtoChainAccessStub(exec, stubInfo, prototypeChain, count, offset, structure, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.dfg.deltaCallToDone), lastProtoBegin, stubRoutine);
@@ -488,7 +528,7 @@ static bool tryBuildGetByIDProtoList(ExecState* exec, JSValue baseValue, const I
CodeLocationJump jumpLocation = stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck);
RepatchBuffer repatchBuffer(codeBlock);
- repatchBuffer.relink(jumpLocation, CodeLocationLabel(stubRoutine.code()));
+ repatchBuffer.relink(jumpLocation, CodeLocationLabel(stubRoutine->code().code()));
if (listIndex < (POLYMORPHIC_LIST_CACHE_SIZE - 1))
return true;
@@ -548,7 +588,7 @@ static void emitPutReplaceStub(
PutKind,
Structure* structure,
CodeLocationLabel failureLabel,
- MacroAssemblerCodeRef& stubRoutine)
+ RefPtr<JITStubRoutine>& stubRoutine)
{
JSGlobalData* globalData = &exec->globalData();
GPRReg baseGPR = static_cast<GPRReg>(stubInfo.patch.dfg.baseGPR);
@@ -567,7 +607,7 @@ static void emitPutReplaceStub(
MacroAssembler stubJit;
- if (scratchGPR == InvalidGPRReg && (writeBarrierNeeded || !structure->isUsingInlineStorage())) {
+ if (scratchGPR == InvalidGPRReg && (writeBarrierNeeded || isOutOfLineOffset(slot.cachedOffset()))) {
scratchGPR = SpeculativeJIT::selectScratchGPR(baseGPR, valueGPR);
needToRestoreScratch = true;
stubJit.push(scratchGPR);
@@ -586,20 +626,20 @@ static void emitPutReplaceStub(
#endif
#if USE(JSVALUE64)
- if (structure->isUsingInlineStorage())
- stubJit.storePtr(valueGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + slot.cachedOffset() * sizeof(JSValue)));
+ if (isInlineOffset(slot.cachedOffset()))
+ stubJit.storePtr(valueGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue)));
else {
- stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
- stubJit.storePtr(valueGPR, MacroAssembler::Address(scratchGPR, slot.cachedOffset() * sizeof(JSValue)));
+ stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR);
+ stubJit.storePtr(valueGPR, MacroAssembler::Address(scratchGPR, offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue)));
}
#elif USE(JSVALUE32_64)
- if (structure->isUsingInlineStorage()) {
- stubJit.store32(valueGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
- stubJit.store32(valueTagGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
+ if (isInlineOffset(slot.cachedOffset())) {
+ stubJit.store32(valueGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
+ stubJit.store32(valueTagGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
} else {
- stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
- stubJit.store32(valueGPR, MacroAssembler::Address(scratchGPR, slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
- stubJit.store32(valueTagGPR, MacroAssembler::Address(scratchGPR, slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
+ stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR);
+ stubJit.store32(valueGPR, MacroAssembler::Address(scratchGPR, offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
+ stubJit.store32(valueTagGPR, MacroAssembler::Address(scratchGPR, offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
}
#endif
@@ -622,7 +662,7 @@ static void emitPutReplaceStub(
patchBuffer.link(success, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.dfg.deltaCallToDone));
patchBuffer.link(failure, failureLabel);
- stubRoutine = FINALIZE_CODE(
+ stubRoutine = FINALIZE_CODE_FOR_STUB(
patchBuffer,
("DFG PutById replace stub for CodeBlock %p, return point %p",
exec->codeBlock(), stubInfo.callReturnLocation.labelAtOffset(
@@ -640,7 +680,7 @@ static void emitPutTransitionStub(
Structure* oldStructure,
StructureChain* prototypeChain,
CodeLocationLabel failureLabel,
- MacroAssemblerCodeRef& stubRoutine)
+ RefPtr<JITStubRoutine>& stubRoutine)
{
JSGlobalData* globalData = &exec->globalData();
@@ -685,20 +725,20 @@ static void emitPutTransitionStub(
stubJit.storePtr(MacroAssembler::TrustedImmPtr(structure), MacroAssembler::Address(baseGPR, JSCell::structureOffset()));
#if USE(JSVALUE64)
- if (structure->isUsingInlineStorage())
- stubJit.storePtr(valueGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + slot.cachedOffset() * sizeof(JSValue)));
+ if (isInlineOffset(slot.cachedOffset()))
+ stubJit.storePtr(valueGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue)));
else {
- stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
- stubJit.storePtr(valueGPR, MacroAssembler::Address(scratchGPR, slot.cachedOffset() * sizeof(JSValue)));
+ stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR);
+ stubJit.storePtr(valueGPR, MacroAssembler::Address(scratchGPR, offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue)));
}
#elif USE(JSVALUE32_64)
- if (structure->isUsingInlineStorage()) {
- stubJit.store32(valueGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
- stubJit.store32(valueTagGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
+ if (isInlineOffset(slot.cachedOffset())) {
+ stubJit.store32(valueGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
+ stubJit.store32(valueTagGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
} else {
- stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
- stubJit.store32(valueGPR, MacroAssembler::Address(scratchGPR, slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
- stubJit.store32(valueTagGPR, MacroAssembler::Address(scratchGPR, slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
+ stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR);
+ stubJit.store32(valueGPR, MacroAssembler::Address(scratchGPR, offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
+ stubJit.store32(valueTagGPR, MacroAssembler::Address(scratchGPR, offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
}
#endif
@@ -721,8 +761,8 @@ static void emitPutTransitionStub(
patchBuffer.link(failure, failureLabel);
else
patchBuffer.link(failureCases, failureLabel);
-
- stubRoutine = FINALIZE_CODE(
+
+ stubRoutine = FINALIZE_CODE_FOR_STUB(
patchBuffer,
("DFG PutById transition stub for CodeBlock %p, return point %p",
exec->codeBlock(), stubInfo.callReturnLocation.labelAtOffset(
@@ -752,7 +792,7 @@ static bool tryCachePutByID(ExecState* exec, JSValue baseValue, const Identifier
return false;
// skip optimizing the case where we need a realloc
- if (oldStructure->propertyStorageCapacity() != structure->propertyStorageCapacity())
+ if (oldStructure->outOfLineCapacity() != structure->outOfLineCapacity())
return false;
normalizePrototypeChain(exec, baseCell);
@@ -766,7 +806,7 @@ static bool tryCachePutByID(ExecState* exec, JSValue baseValue, const Identifier
stubInfo.stubRoutine);
RepatchBuffer repatchBuffer(codeBlock);
- repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine.code()));
+ repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine->code().code()));
repatchBuffer.relink(stubInfo.callReturnLocation, appropriateListBuildingPutByIdFunction(slot, putKind));
stubInfo.initPutByIdTransition(*globalData, codeBlock->ownerExecutable(), oldStructure, structure, prototypeChain, putKind == Direct);
@@ -808,14 +848,14 @@ static bool tryBuildPutByIdList(ExecState* exec, JSValue baseValue, const Identi
// Optimize self access.
if (slot.base() == baseValue) {
PolymorphicPutByIdList* list;
- MacroAssemblerCodeRef stubRoutine;
+ RefPtr<JITStubRoutine> stubRoutine;
if (slot.type() == PutPropertySlot::NewProperty) {
if (structure->isDictionary())
return false;
// skip optimizing the case where we need a realloc
- if (oldStructure->propertyStorageCapacity() != structure->propertyStorageCapacity())
+ if (oldStructure->outOfLineCapacity() != structure->outOfLineCapacity())
return false;
normalizePrototypeChain(exec, baseCell);
@@ -855,7 +895,7 @@ static bool tryBuildPutByIdList(ExecState* exec, JSValue baseValue, const Identi
}
RepatchBuffer repatchBuffer(codeBlock);
- repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubRoutine.code()));
+ repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubRoutine->code().code()));
if (list->isFull())
repatchBuffer.relink(stubInfo.callReturnLocation, appropriateGenericPutByIdFunction(slot, putKind));
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 0c0f3260f..c6ec62129 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -45,6 +45,8 @@ SpeculativeJIT::SpeculativeJIT(JITCompiler& jit)
, m_variables(jit.graph().m_localVars)
, m_lastSetOperand(std::numeric_limits<int>::max())
, m_state(m_jit.graph())
+ , m_stream(&jit.codeBlock()->variableEventStream())
+ , m_minifiedGraph(&jit.codeBlock()->minifiedDFG())
, m_isCheckingArgumentTypes(false)
{
}
@@ -99,7 +101,7 @@ GPRReg SpeculativeJIT::fillStorage(NodeIndex nodeIndex)
GPRReg gpr = allocate();
m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
- info.fillStorage(gpr);
+ info.fillStorage(*m_stream, gpr);
return gpr;
}
@@ -780,39 +782,6 @@ FPRTemporary::FPRTemporary(SpeculativeJIT* jit, JSValueOperand& op1)
}
#endif
-void ValueSource::dump(FILE* out) const
-{
- switch (kind()) {
- case SourceNotSet:
- fprintf(out, "NotSet");
- break;
- case SourceIsDead:
- fprintf(out, "IsDead");
- break;
- case ValueInRegisterFile:
- fprintf(out, "InRegFile");
- break;
- case Int32InRegisterFile:
- fprintf(out, "Int32");
- break;
- case CellInRegisterFile:
- fprintf(out, "Cell");
- break;
- case BooleanInRegisterFile:
- fprintf(out, "Bool");
- break;
- case DoubleInRegisterFile:
- fprintf(out, "Double");
- break;
- case ArgumentsSource:
- fprintf(out, "Arguments");
- break;
- case HaveNode:
- fprintf(out, "Node(%d)", m_nodeIndex);
- break;
- }
-}
-
void SpeculativeJIT::compilePeepHoleDoubleBranch(Node& node, NodeIndex branchNodeIndex, JITCompiler::DoubleCondition condition)
{
Node& branchNode = at(branchNodeIndex);
@@ -953,12 +922,30 @@ bool SpeculativeJIT::compilePeepHoleBranch(Node& node, MacroAssembler::Relationa
return false;
}
+void SpeculativeJIT::noticeOSRBirth(NodeIndex nodeIndex, Node& node)
+{
+ if (!node.hasVirtualRegister())
+ return;
+
+ VirtualRegister virtualRegister = node.virtualRegister();
+ GenerationInfo& info = m_generationInfo[virtualRegister];
+
+ info.noticeOSRBirth(*m_stream, nodeIndex, virtualRegister);
+}
+
void SpeculativeJIT::compileMovHint(Node& node)
{
ASSERT(node.op() == SetLocal);
- setNodeIndexForOperand(node.child1().index(), node.local());
m_lastSetOperand = node.local();
+
+ Node& child = at(node.child1());
+ noticeOSRBirth(node.child1().index(), child);
+
+ if (child.op() == UInt32ToNumber)
+ noticeOSRBirth(child.child1().index(), at(child.child1()));
+
+ m_stream->appendAndLog(VariableEvent::movHint(node.child1().index(), node.local()));
}
void SpeculativeJIT::compile(BasicBlock& block)
@@ -983,11 +970,20 @@ void SpeculativeJIT::compile(BasicBlock& block)
m_jit.breakpoint();
#endif
+#if DFG_ENABLE(DEBUG_VERBOSE)
+ dataLog("Setting up state for block #%u: ", m_block);
+#endif
+
+ m_stream->appendAndLog(VariableEvent::reset());
+
m_jit.jitAssertHasValidCallFrame();
ASSERT(m_arguments.size() == block.variablesAtHead.numberOfArguments());
- for (size_t i = 0; i < m_arguments.size(); ++i)
- m_arguments[i] = ValueSource(ValueInRegisterFile);
+ for (size_t i = 0; i < m_arguments.size(); ++i) {
+ ValueSource valueSource = ValueSource(ValueInRegisterFile);
+ m_arguments[i] = valueSource;
+ m_stream->appendAndLog(VariableEvent::setLocal(argumentToOperand(i), valueSource.dataFormat()));
+ }
m_state.reset();
m_state.beginBasicBlock(&block);
@@ -995,18 +991,21 @@ void SpeculativeJIT::compile(BasicBlock& block)
ASSERT(m_variables.size() == block.variablesAtHead.numberOfLocals());
for (size_t i = 0; i < m_variables.size(); ++i) {
NodeIndex nodeIndex = block.variablesAtHead.local(i);
+ ValueSource valueSource;
if (nodeIndex == NoNode)
- m_variables[i] = ValueSource(SourceIsDead);
+ valueSource = ValueSource(SourceIsDead);
else if (at(nodeIndex).variableAccessData()->isArgumentsAlias())
- m_variables[i] = ValueSource(ArgumentsSource);
+ valueSource = ValueSource(ArgumentsSource);
else if (at(nodeIndex).variableAccessData()->isCaptured())
- m_variables[i] = ValueSource(ValueInRegisterFile);
+ valueSource = ValueSource(ValueInRegisterFile);
else if (!at(nodeIndex).refCount())
- m_variables[i] = ValueSource(SourceIsDead);
+ valueSource = ValueSource(SourceIsDead);
else if (at(nodeIndex).variableAccessData()->shouldUseDoubleFormat())
- m_variables[i] = ValueSource(DoubleInRegisterFile);
+ valueSource = ValueSource(DoubleInRegisterFile);
else
- m_variables[i] = ValueSource::forSpeculation(at(nodeIndex).variableAccessData()->argumentAwarePrediction());
+ valueSource = ValueSource::forSpeculation(at(nodeIndex).variableAccessData()->argumentAwarePrediction());
+ m_variables[i] = valueSource;
+ m_stream->appendAndLog(VariableEvent::setLocal(i, valueSource.dataFormat()));
}
m_lastSetOperand = std::numeric_limits<int>::max();
@@ -1019,6 +1018,10 @@ void SpeculativeJIT::compile(BasicBlock& block)
verificationSucceeded.link(&m_jit);
}
+#if DFG_ENABLE(DEBUG_VERBOSE)
+ dataLog("\n");
+#endif
+
for (m_indexInBlock = 0; m_indexInBlock < block.size(); ++m_indexInBlock) {
m_compileIndex = block[m_indexInBlock];
m_jit.setForNode(m_compileIndex);
@@ -1029,6 +1032,15 @@ void SpeculativeJIT::compile(BasicBlock& block)
dataLog("SpeculativeJIT skipping Node @%d (bc#%u) at JIT offset 0x%x ", (int)m_compileIndex, node.codeOrigin.bytecodeIndex, m_jit.debugOffset());
#endif
switch (node.op()) {
+ case JSConstant:
+ m_minifiedGraph->append(MinifiedNode::fromNode(m_compileIndex, node));
+ break;
+
+ case WeakJSConstant:
+ m_jit.addWeakReference(node.weakConstant());
+ m_minifiedGraph->append(MinifiedNode::fromNode(m_compileIndex, node));
+ break;
+
case SetLocal:
compileMovHint(node);
break;
@@ -1073,11 +1085,9 @@ void SpeculativeJIT::compile(BasicBlock& block)
break;
}
- case WeakJSConstant:
- m_jit.addWeakReference(node.weakConstant());
- break;
-
default:
+ if (belongsInMinifiedGraph(node.op()))
+ m_minifiedGraph->append(MinifiedNode::fromNode(m_compileIndex, node));
break;
}
} else {
@@ -1100,6 +1110,11 @@ void SpeculativeJIT::compile(BasicBlock& block)
return;
}
+ if (belongsInMinifiedGraph(node.op())) {
+ m_minifiedGraph->append(MinifiedNode::fromNode(m_compileIndex, node));
+ noticeOSRBirth(m_compileIndex, node);
+ }
+
#if DFG_ENABLE(DEBUG_VERBOSE)
if (node.hasResult()) {
GenerationInfo& info = m_generationInfo[node.virtualRegister()];
@@ -1120,16 +1135,6 @@ void SpeculativeJIT::compile(BasicBlock& block)
#endif
}
-#if DFG_ENABLE(VERBOSE_VALUE_RECOVERIES)
- for (size_t i = 0; i < m_arguments.size(); ++i)
- computeValueRecoveryFor(argumentToOperand(i)).dump(stderr);
-
- dataLog(" : ");
-
- for (int operand = 0; operand < (int)m_variables.size(); ++operand)
- computeValueRecoveryFor(operand).dump(stderr);
-#endif
-
#if DFG_ENABLE(DEBUG_VERBOSE)
dataLog("\n");
#endif
@@ -1366,154 +1371,14 @@ void SpeculativeJIT::linkOSREntries(LinkBuffer& linkBuffer)
ValueRecovery SpeculativeJIT::computeValueRecoveryFor(const ValueSource& valueSource)
{
- switch (valueSource.kind()) {
- case SourceIsDead:
- return ValueRecovery::constant(jsUndefined());
-
- case ValueInRegisterFile:
- return ValueRecovery::alreadyInRegisterFile();
+ if (valueSource.isInRegisterFile())
+ return valueSource.valueRecovery();
- case Int32InRegisterFile:
- return ValueRecovery::alreadyInRegisterFileAsUnboxedInt32();
-
- case CellInRegisterFile:
- return ValueRecovery::alreadyInRegisterFileAsUnboxedCell();
-
- case BooleanInRegisterFile:
- return ValueRecovery::alreadyInRegisterFileAsUnboxedBoolean();
-
- case DoubleInRegisterFile:
- return ValueRecovery::alreadyInRegisterFileAsUnboxedDouble();
-
- case ArgumentsSource:
- return ValueRecovery::argumentsThatWereNotCreated();
-
- case HaveNode: {
- Node* nodePtr = &at(valueSource.nodeIndex());
-
- if (nodePtr->isPhantomArguments())
- return ValueRecovery::argumentsThatWereNotCreated();
-
- if (nodePtr->hasConstant())
- return ValueRecovery::constant(valueOfJSConstant(valueSource.nodeIndex()));
-
- if (!nodePtr->shouldGenerate()) {
- // It's legitimately dead. As in, nobody will ever use this node, or operand,
- // ever. Set it to Undefined to make the GC happy after the OSR.
- return ValueRecovery::constant(jsUndefined());
- }
+ ASSERT(valueSource.kind() == HaveNode);
+ if (isConstant(valueSource.nodeIndex()))
+ return ValueRecovery::constant(valueOfJSConstant(valueSource.nodeIndex()));
- GenerationInfo* infoPtr = &m_generationInfo[nodePtr->virtualRegister()];
- if (!infoPtr->alive() || infoPtr->nodeIndex() != valueSource.nodeIndex()) {
- // Try to see if there is an alternate node that would contain the value we want.
- // There are four possibilities:
- //
- // Int32ToDouble: We can use this in place of the original node, but
- // we'd rather not; so we use it only if it is the only remaining
- // live version.
- //
- // ValueToInt32: If the only remaining live version of the value is
- // ValueToInt32, then we can use it.
- //
- // UInt32ToNumber: If the only live version of the value is a UInt32ToNumber
- // then the only remaining uses are ones that want a properly formed number
- // rather than a UInt32 intermediate.
- //
- // The reverse of the above: This node could be a UInt32ToNumber, but its
- // alternative is still alive. This means that the only remaining uses of
- // the number would be fine with a UInt32 intermediate.
- //
- // DoubleAsInt32: Same as UInt32ToNumber.
- //
-
- bool found = false;
-
- if (nodePtr->op() == UInt32ToNumber || nodePtr->op() == DoubleAsInt32) {
- NodeIndex nodeIndex = nodePtr->child1().index();
- nodePtr = &at(nodeIndex);
- infoPtr = &m_generationInfo[nodePtr->virtualRegister()];
- if (infoPtr->alive() && infoPtr->nodeIndex() == nodeIndex)
- found = true;
- }
-
- if (!found) {
- NodeIndex int32ToDoubleIndex = NoNode;
- NodeIndex valueToInt32Index = NoNode;
- NodeIndex uint32ToNumberIndex = NoNode;
- NodeIndex doubleAsInt32Index = NoNode;
-
- for (unsigned virtualRegister = 0; virtualRegister < m_generationInfo.size(); ++virtualRegister) {
- GenerationInfo& info = m_generationInfo[virtualRegister];
- if (!info.alive())
- continue;
- if (info.nodeIndex() == NoNode)
- continue;
- Node& node = at(info.nodeIndex());
- if (node.child1Unchecked() != valueSource.nodeIndex())
- continue;
- switch (node.op()) {
- case Int32ToDouble:
- int32ToDoubleIndex = info.nodeIndex();
- break;
- case ValueToInt32:
- valueToInt32Index = info.nodeIndex();
- break;
- case UInt32ToNumber:
- uint32ToNumberIndex = info.nodeIndex();
- break;
- case DoubleAsInt32:
- doubleAsInt32Index = info.nodeIndex();
- default:
- break;
- }
- }
-
- NodeIndex nodeIndexToUse;
- if (doubleAsInt32Index != NoNode)
- nodeIndexToUse = doubleAsInt32Index;
- else if (int32ToDoubleIndex != NoNode)
- nodeIndexToUse = int32ToDoubleIndex;
- else if (valueToInt32Index != NoNode)
- nodeIndexToUse = valueToInt32Index;
- else if (uint32ToNumberIndex != NoNode)
- nodeIndexToUse = uint32ToNumberIndex;
- else
- nodeIndexToUse = NoNode;
-
- if (nodeIndexToUse != NoNode) {
- nodePtr = &at(nodeIndexToUse);
- infoPtr = &m_generationInfo[nodePtr->virtualRegister()];
- ASSERT(infoPtr->alive() && infoPtr->nodeIndex() == nodeIndexToUse);
- found = true;
- }
- }
-
- if (!found)
- return ValueRecovery::constant(jsUndefined());
- }
-
- ASSERT(infoPtr->alive());
-
- if (infoPtr->registerFormat() != DataFormatNone) {
- if (infoPtr->registerFormat() == DataFormatDouble)
- return ValueRecovery::inFPR(infoPtr->fpr());
-#if USE(JSVALUE32_64)
- if (infoPtr->registerFormat() & DataFormatJS)
- return ValueRecovery::inPair(infoPtr->tagGPR(), infoPtr->payloadGPR());
-#endif
- return ValueRecovery::inGPR(infoPtr->gpr(), infoPtr->registerFormat());
- }
- if (infoPtr->spillFormat() != DataFormatNone)
- return ValueRecovery::displacedInRegisterFile(static_cast<VirtualRegister>(nodePtr->virtualRegister()), infoPtr->spillFormat());
-
- ASSERT_NOT_REACHED();
- return ValueRecovery();
- }
-
- default:
- ASSERT_NOT_REACHED();
- return ValueRecovery();
- }
+ return ValueRecovery();
}
void SpeculativeJIT::compileGetCharCodeAt(Node& node)
@@ -1652,10 +1517,11 @@ GeneratedOperandType SpeculativeJIT::checkGeneratedTypeForToInt32(NodeIndex node
case DataFormatJSDouble:
case DataFormatDouble:
return GeneratedOperandDouble;
+
+ default:
+ ASSERT_NOT_REACHED();
+ return GeneratedOperandTypeUnknown;
}
-
- ASSERT_NOT_REACHED();
- return GeneratedOperandTypeUnknown;
}
void SpeculativeJIT::compileValueToInt32(Node& node)
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 67a22b767..57bc84a12 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,6 +26,8 @@
#ifndef DFGSpeculativeJIT_h
#define DFGSpeculativeJIT_h
+#include <wtf/Platform.h>
+
#if ENABLE(DFG_JIT)
#include "DFGAbstractState.h"
@@ -34,6 +36,7 @@
#include "DFGOSRExit.h"
#include "DFGOperations.h"
#include "DFGSilentRegisterSavePlan.h"
+#include "DFGValueSource.h"
#include "MarkedAllocator.h"
#include "ValueRecovery.h"
@@ -48,87 +51,6 @@ class SpeculateDoubleOperand;
class SpeculateCellOperand;
class SpeculateBooleanOperand;
-
-enum ValueSourceKind {
- SourceNotSet,
- ValueInRegisterFile,
- Int32InRegisterFile,
- CellInRegisterFile,
- BooleanInRegisterFile,
- DoubleInRegisterFile,
- ArgumentsSource,
- SourceIsDead,
- HaveNode
-};
-
-class ValueSource {
-public:
- ValueSource()
- : m_nodeIndex(nodeIndexFromKind(SourceNotSet))
- {
- }
-
- explicit ValueSource(ValueSourceKind valueSourceKind)
- : m_nodeIndex(nodeIndexFromKind(valueSourceKind))
- {
- ASSERT(kind() != SourceNotSet);
- ASSERT(kind() != HaveNode);
- }
-
- explicit ValueSource(NodeIndex nodeIndex)
- : m_nodeIndex(nodeIndex)
- {
- ASSERT(kind() == HaveNode);
- }
-
- static ValueSource forSpeculation(SpeculatedType prediction)
- {
- if (isInt32Speculation(prediction))
- return ValueSource(Int32InRegisterFile);
- if (isArraySpeculation(prediction))
- return ValueSource(CellInRegisterFile);
- if (isBooleanSpeculation(prediction))
- return ValueSource(BooleanInRegisterFile);
- return ValueSource(ValueInRegisterFile);
- }
-
- bool isSet() const
- {
- return kindFromNodeIndex(m_nodeIndex) != SourceNotSet;
- }
-
- ValueSourceKind kind() const
- {
- return kindFromNodeIndex(m_nodeIndex);
- }
-
- NodeIndex nodeIndex() const
- {
- ASSERT(kind() == HaveNode);
- return m_nodeIndex;
- }
-
- void dump(FILE* out) const;
-
-private:
- static NodeIndex nodeIndexFromKind(ValueSourceKind kind)
- {
- ASSERT(kind >= SourceNotSet && kind < HaveNode);
- return NoNode - kind;
- }
-
- static ValueSourceKind kindFromNodeIndex(NodeIndex nodeIndex)
- {
- unsigned kind = static_cast<unsigned>(NoNode - nodeIndex);
- if (kind >= static_cast<unsigned>(HaveNode))
- return HaveNode;
- return static_cast<ValueSourceKind>(kind);
- }
-
- NodeIndex m_nodeIndex;
-};
-
-
enum GeneratedOperandType { GeneratedOperandTypeUnknown, GeneratedOperandInteger, GeneratedOperandDouble, GeneratedOperandJSValue};
// === SpeculativeJIT ===
@@ -326,7 +248,7 @@ public:
// use() returns true when the value becomes dead, and any
// associated resources may be freed.
- if (!info.use())
+ if (!info.use(*m_stream))
return;
// Release the associated machine registers.
@@ -376,6 +298,7 @@ public:
void runSlowPathGenerators();
void compile(Node&);
+ void noticeOSRBirth(NodeIndex, Node&);
void compileMovHint(Node&);
void compile(BasicBlock&);
@@ -777,7 +700,7 @@ public:
// Check the GenerationInfo to see if this value need writing
// to the RegisterFile - if not, mark it as spilled & return.
if (!info.needsSpill()) {
- info.setSpilled();
+ info.setSpilled(*m_stream, spillMe);
return;
}
@@ -787,20 +710,20 @@ public:
// This is special, since it's not a JS value - as in it's not visible to JS
// code.
m_jit.storePtr(info.gpr(), JITCompiler::addressFor(spillMe));
- info.spill(DataFormatStorage);
+ info.spill(*m_stream, spillMe, DataFormatStorage);
return;
}
case DataFormatInteger: {
m_jit.store32(info.gpr(), JITCompiler::payloadFor(spillMe));
- info.spill(DataFormatInteger);
+ info.spill(*m_stream, spillMe, DataFormatInteger);
return;
}
#if USE(JSVALUE64)
case DataFormatDouble: {
m_jit.storeDouble(info.fpr(), JITCompiler::addressFor(spillMe));
- info.spill(DataFormatDouble);
+ info.spill(*m_stream, spillMe, DataFormatDouble);
return;
}
@@ -816,13 +739,13 @@ public:
// Spill the value, and record it as spilled in its boxed form.
m_jit.storePtr(reg, JITCompiler::addressFor(spillMe));
- info.spill((DataFormat)(spillFormat | DataFormatJS));
+ info.spill(*m_stream, spillMe, (DataFormat)(spillFormat | DataFormatJS));
return;
#elif USE(JSVALUE32_64)
case DataFormatCell:
case DataFormatBoolean: {
m_jit.store32(info.gpr(), JITCompiler::payloadFor(spillMe));
- info.spill(spillFormat);
+ info.spill(*m_stream, spillMe, spillFormat);
return;
}
@@ -830,7 +753,7 @@ public:
case DataFormatJSDouble: {
// On JSVALUE32_64 boxing a double is a no-op.
m_jit.storeDouble(info.fpr(), JITCompiler::addressFor(spillMe));
- info.spill(DataFormatJSDouble);
+ info.spill(*m_stream, spillMe, DataFormatJSDouble);
return;
}
@@ -839,7 +762,7 @@ public:
ASSERT(spillFormat & DataFormatJS);
m_jit.store32(info.tagGPR(), JITCompiler::tagFor(spillMe));
m_jit.store32(info.payloadGPR(), JITCompiler::payloadFor(spillMe));
- info.spill(spillFormat);
+ info.spill(*m_stream, spillMe, spillFormat);
return;
#endif
}
@@ -1800,7 +1723,7 @@ public:
}
#endif
-#if !defined(NDEBUG) && !CPU(ARM_THUMB2)
+#if !defined(NDEBUG) && !CPU(ARM)
void prepareForExternalCall()
{
for (unsigned i = 0; i < sizeof(void*) / 4; i++)
@@ -2180,8 +2103,7 @@ public:
m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, JSObject::offsetOfInheritorID()));
// Initialize the object's property storage pointer.
- m_jit.addPtr(MacroAssembler::TrustedImm32(sizeof(JSObject)), resultGPR, scratchGPR);
- m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, ClassType::offsetOfPropertyStorage()));
+ m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, ClassType::offsetOfOutOfLineStorage()));
}
// It is acceptable to have structure be equal to scratch, so long as you're fine
@@ -2204,7 +2126,7 @@ public:
if (!m_compileOkay)
return;
ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes);
- m_jit.codeBlock()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(nodeIndex), jumpToFail, this));
+ m_jit.codeBlock()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(nodeIndex), jumpToFail, this, m_stream->size()));
}
void speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail)
{
@@ -2231,7 +2153,7 @@ public:
return;
ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes);
m_jit.codeBlock()->appendSpeculationRecovery(recovery);
- m_jit.codeBlock()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(nodeIndex), jumpToFail, this, m_jit.codeBlock()->numberOfSpeculationRecoveries()));
+ m_jit.codeBlock()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(nodeIndex), jumpToFail, this, m_stream->size(), m_jit.codeBlock()->numberOfSpeculationRecoveries()));
}
void speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)
{
@@ -2252,7 +2174,7 @@ public:
m_jit.codeBlock()->appendOSRExit(
OSRExit(kind, jsValueSource,
m_jit.graph().methodOfGettingAValueProfileFor(nodeIndex),
- JITCompiler::Jump(), this)));
+ JITCompiler::Jump(), this, m_stream->size())));
exit.m_watchpointIndex = m_jit.codeBlock()->appendWatchpoint(
Watchpoint(m_jit.watchpointLabel()));
return &m_jit.codeBlock()->watchpoint(exit.m_watchpointIndex);
@@ -2295,7 +2217,8 @@ public:
exit.m_codeOrigin = nextNode->codeOrigin;
exit.m_lastSetOperand = setLocal->local();
- exit.valueRecoveryForOperand(setLocal->local()) = valueRecovery;
+ exit.m_valueRecoveryOverride = adoptRef(
+ new ValueRecoveryOverride(setLocal->local(), valueRecovery));
}
void forwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::JumpList& jumpsToFail, const ValueRecovery& valueRecovery)
{
@@ -2362,6 +2285,13 @@ public:
return m_variables[operand];
}
+ void recordSetLocal(int operand, ValueSource valueSource)
+ {
+ valueSourceReferenceForOperand(operand) = valueSource;
+ m_stream->appendAndLog(VariableEvent::setLocal(operand, valueSource.dataFormat()));
+ }
+
+ // The JIT, while also provides MacroAssembler functionality.
JITCompiler& m_jit;
// The current node being generated.
@@ -2395,6 +2325,9 @@ public:
AbstractState m_state;
+ VariableEventStream* m_stream;
+ MinifiedGraph* m_minifiedGraph;
+
bool m_isCheckingArgumentTypes;
Vector<SlowPathGenerator*, 8> m_slowPathGenerators; // doesn't use OwnPtr<> because I don't want to include DFGSlowPathGenerator.h
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 05609baa8..bbbf3c40c 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -62,7 +62,7 @@ GPRReg SpeculativeJIT::fillInteger(NodeIndex nodeIndex, DataFormat& returnFormat
m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
}
- info.fillInteger(gpr);
+ info.fillInteger(*m_stream, gpr);
returnFormat = DataFormatInteger;
return gpr;
}
@@ -91,7 +91,7 @@ GPRReg SpeculativeJIT::fillInteger(NodeIndex nodeIndex, DataFormat& returnFormat
m_gprs.release(tagGPR);
m_gprs.release(payloadGPR);
m_gprs.retain(payloadGPR, virtualRegister, SpillOrderInteger);
- info.fillInteger(payloadGPR);
+ info.fillInteger(*m_stream, payloadGPR);
returnFormat = DataFormatInteger;
return payloadGPR;
}
@@ -103,10 +103,11 @@ GPRReg SpeculativeJIT::fillInteger(NodeIndex nodeIndex, DataFormat& returnFormat
returnFormat = DataFormatInteger;
return gpr;
}
- }
- ASSERT_NOT_REACHED();
- return InvalidGPRReg;
+ default:
+ ASSERT_NOT_REACHED();
+ return InvalidGPRReg;
+ }
}
FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex)
@@ -123,13 +124,13 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex)
GPRReg gpr = allocate();
m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
- info.fillInteger(gpr);
+ info.fillInteger(*m_stream, gpr);
unlock(gpr);
} else if (isNumberConstant(nodeIndex)) {
FPRReg fpr = fprAllocate();
m_jit.loadDouble(addressOfDoubleConstant(nodeIndex), fpr);
m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
- info.fillDouble(fpr);
+ info.fillDouble(*m_stream, fpr);
return fpr;
} else {
// FIXME: should not be reachable?
@@ -142,7 +143,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex)
FPRReg fpr = fprAllocate();
m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr);
m_fprs.retain(fpr, virtualRegister, SpillOrderSpilled);
- info.fillDouble(fpr);
+ info.fillDouble(*m_stream, fpr);
return fpr;
}
@@ -162,7 +163,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex)
hasUnboxedDouble.link(&m_jit);
m_fprs.retain(fpr, virtualRegister, SpillOrderSpilled);
- info.fillDouble(fpr);
+ info.fillDouble(*m_stream, fpr);
return fpr;
}
}
@@ -207,7 +208,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex)
m_gprs.unlock(tagGPR);
m_gprs.unlock(payloadGPR);
m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
- info.fillDouble(fpr);
+ info.fillDouble(*m_stream, fpr);
info.killSpilled();
return fpr;
}
@@ -227,10 +228,11 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex)
m_fprs.lock(fpr);
return fpr;
}
- }
- ASSERT_NOT_REACHED();
- return InvalidFPRReg;
+ default:
+ ASSERT_NOT_REACHED();
+ return InvalidFPRReg;
+ }
}
bool SpeculativeJIT::fillJSValue(NodeIndex nodeIndex, GPRReg& tagGPR, GPRReg& payloadGPR, FPRReg& fpr)
@@ -252,7 +254,7 @@ bool SpeculativeJIT::fillJSValue(NodeIndex nodeIndex, GPRReg& tagGPR, GPRReg& pa
m_jit.move(Imm32(valueOfJSConstant(nodeIndex).payload()), payloadGPR);
m_gprs.retain(tagGPR, virtualRegister, SpillOrderConstant);
m_gprs.retain(payloadGPR, virtualRegister, SpillOrderConstant);
- info.fillJSValue(tagGPR, payloadGPR, isInt32Constant(nodeIndex) ? DataFormatJSInteger : DataFormatJS);
+ info.fillJSValue(*m_stream, tagGPR, payloadGPR, isInt32Constant(nodeIndex) ? DataFormatJSInteger : DataFormatJS);
} else {
DataFormat spillFormat = info.spillFormat();
ASSERT(spillFormat != DataFormatNone && spillFormat != DataFormatStorage);
@@ -278,7 +280,7 @@ bool SpeculativeJIT::fillJSValue(NodeIndex nodeIndex, GPRReg& tagGPR, GPRReg& pa
m_jit.load32(JITCompiler::payloadFor(virtualRegister), payloadGPR);
m_gprs.retain(tagGPR, virtualRegister, SpillOrderSpilled);
m_gprs.retain(payloadGPR, virtualRegister, SpillOrderSpilled);
- info.fillJSValue(tagGPR, payloadGPR, spillFormat == DataFormatJSDouble ? DataFormatJS : spillFormat);
+ info.fillJSValue(*m_stream, tagGPR, payloadGPR, spillFormat == DataFormatJSDouble ? DataFormatJS : spillFormat);
}
return true;
@@ -320,7 +322,7 @@ bool SpeculativeJIT::fillJSValue(NodeIndex nodeIndex, GPRReg& tagGPR, GPRReg& pa
m_gprs.release(gpr);
m_gprs.retain(tagGPR, virtualRegister, SpillOrderJS);
m_gprs.retain(payloadGPR, virtualRegister, SpillOrderJS);
- info.fillJSValue(tagGPR, payloadGPR, fillFormat);
+ info.fillJSValue(*m_stream, tagGPR, payloadGPR, fillFormat);
return true;
}
@@ -335,7 +337,7 @@ bool SpeculativeJIT::fillJSValue(NodeIndex nodeIndex, GPRReg& tagGPR, GPRReg& pa
m_fprs.release(oldFPR);
m_gprs.retain(tagGPR, virtualRegister, SpillOrderJS);
m_gprs.retain(payloadGPR, virtualRegister, SpillOrderJS);
- info.fillJSValue(tagGPR, payloadGPR, DataFormatJS);
+ info.fillJSValue(*m_stream, tagGPR, payloadGPR, DataFormatJS);
return true;
}
@@ -353,10 +355,11 @@ bool SpeculativeJIT::fillJSValue(NodeIndex nodeIndex, GPRReg& tagGPR, GPRReg& pa
case DataFormatStorage:
// this type currently never occurs
ASSERT_NOT_REACHED();
- }
- ASSERT_NOT_REACHED();
- return true;
+ default:
+ ASSERT_NOT_REACHED();
+ return true;
+ }
}
class ValueToNumberSlowPathGenerator
@@ -505,7 +508,7 @@ void SpeculativeJIT::cachedGetById(CodeOrigin codeOrigin, GPRReg baseTagGPROrNon
JITCompiler::DataLabelPtr structureToCompare;
JITCompiler::PatchableJump structureCheck = m_jit.patchableBranchPtrWithPatch(JITCompiler::NotEqual, JITCompiler::Address(basePayloadGPR, JSCell::structureOffset()), structureToCompare, JITCompiler::TrustedImmPtr(reinterpret_cast<void*>(-1)));
- m_jit.loadPtr(JITCompiler::Address(basePayloadGPR, JSObject::offsetOfPropertyStorage()), resultPayloadGPR);
+ JITCompiler::ConvertibleLoadLabel propertyStorageLoad = m_jit.convertibleLoadPtr(JITCompiler::Address(basePayloadGPR, JSObject::offsetOfOutOfLineStorage()), resultPayloadGPR);
JITCompiler::DataLabelCompact tagLoadWithPatch = m_jit.load32WithCompactAddressOffsetPatch(JITCompiler::Address(resultPayloadGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
JITCompiler::DataLabelCompact payloadLoadWithPatch = m_jit.load32WithCompactAddressOffsetPatch(JITCompiler::Address(resultPayloadGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR);
@@ -547,7 +550,7 @@ void SpeculativeJIT::cachedGetById(CodeOrigin codeOrigin, GPRReg baseTagGPROrNon
}
m_jit.addPropertyAccess(
PropertyAccessRecord(
- codeOrigin, structureToCompare, structureCheck,
+ codeOrigin, structureToCompare, structureCheck, propertyStorageLoad,
tagLoadWithPatch, payloadLoadWithPatch, slowPath.get(), doneLabel,
safeCast<int8_t>(basePayloadGPR), safeCast<int8_t>(resultTagGPR),
safeCast<int8_t>(resultPayloadGPR), safeCast<int8_t>(scratchGPR),
@@ -562,7 +565,7 @@ void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg basePayloadGPR,
writeBarrier(basePayloadGPR, valueTagGPR, valueUse, WriteBarrierForPropertyAccess, scratchGPR);
- m_jit.loadPtr(JITCompiler::Address(basePayloadGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
+ JITCompiler::ConvertibleLoadLabel propertyStorageLoad = m_jit.convertibleLoadPtr(JITCompiler::Address(basePayloadGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR);
JITCompiler::DataLabel32 tagStoreWithPatch = m_jit.store32WithAddressOffsetPatch(valueTagGPR, JITCompiler::Address(scratchGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
JITCompiler::DataLabel32 payloadStoreWithPatch = m_jit.store32WithAddressOffsetPatch(valuePayloadGPR, JITCompiler::Address(scratchGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
@@ -594,7 +597,7 @@ void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg basePayloadGPR,
}
m_jit.addPropertyAccess(
PropertyAccessRecord(
- codeOrigin, structureToCompare, structureCheck,
+ codeOrigin, structureToCompare, structureCheck, propertyStorageLoad,
JITCompiler::DataLabelCompact(tagStoreWithPatch.label()),
JITCompiler::DataLabelCompact(payloadStoreWithPatch.label()),
slowPath.get(), doneLabel, safeCast<int8_t>(basePayloadGPR),
@@ -1065,7 +1068,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat&
GPRReg gpr = allocate();
m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
- info.fillInteger(gpr);
+ info.fillInteger(*m_stream, gpr);
returnFormat = DataFormatInteger;
return gpr;
}
@@ -1080,7 +1083,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat&
GPRReg gpr = allocate();
m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
- info.fillInteger(gpr);
+ info.fillInteger(*m_stream, gpr);
returnFormat = DataFormatInteger;
return gpr;
}
@@ -1098,7 +1101,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat&
m_gprs.release(tagGPR);
m_gprs.release(payloadGPR);
m_gprs.retain(payloadGPR, virtualRegister, SpillOrderInteger);
- info.fillInteger(payloadGPR);
+ info.fillInteger(*m_stream, payloadGPR);
// If !strict we're done, return.
returnFormat = DataFormatInteger;
return payloadGPR;
@@ -1119,10 +1122,11 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat&
case DataFormatJSBoolean:
case DataFormatStorage:
ASSERT_NOT_REACHED();
- }
- ASSERT_NOT_REACHED();
- return InvalidGPRReg;
+ default:
+ ASSERT_NOT_REACHED();
+ return InvalidGPRReg;
+ }
}
GPRReg SpeculativeJIT::fillSpeculateInt(NodeIndex nodeIndex, DataFormat& returnFormat)
@@ -1160,24 +1164,24 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex)
GPRReg gpr = allocate();
m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
- info.fillInteger(gpr);
+ info.fillInteger(*m_stream, gpr);
unlock(gpr);
} else if (isNumberConstant(nodeIndex)) {
FPRReg fpr = fprAllocate();
m_jit.loadDouble(addressOfDoubleConstant(nodeIndex), fpr);
m_fprs.retain(fpr, virtualRegister, SpillOrderConstant);
- info.fillDouble(fpr);
+ info.fillDouble(*m_stream, fpr);
return fpr;
} else
ASSERT_NOT_REACHED();
} else {
DataFormat spillFormat = info.spillFormat();
ASSERT((spillFormat & DataFormatJS) || spillFormat == DataFormatInteger);
- if (spillFormat == DataFormatJSDouble) {
+ if (spillFormat == DataFormatJSDouble || spillFormat == DataFormatDouble) {
FPRReg fpr = fprAllocate();
m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr);
m_fprs.retain(fpr, virtualRegister, SpillOrderSpilled);
- info.fillDouble(fpr);
+ info.fillDouble(*m_stream, fpr);
return fpr;
}
@@ -1200,7 +1204,8 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex)
hasUnboxedDouble.link(&m_jit);
m_fprs.retain(fpr, virtualRegister, SpillOrderSpilled);
- info.fillDouble(fpr);
+ info.fillDouble(*m_stream, fpr);
+ info.killSpilled();
return fpr;
}
}
@@ -1237,7 +1242,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex)
m_gprs.unlock(tagGPR);
m_gprs.unlock(payloadGPR);
m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
- info.fillDouble(fpr);
+ info.fillDouble(*m_stream, fpr);
info.killSpilled();
return fpr;
}
@@ -1265,10 +1270,11 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex)
case DataFormatBoolean:
case DataFormatJSBoolean:
ASSERT_NOT_REACHED();
- }
- ASSERT_NOT_REACHED();
- return InvalidFPRReg;
+ default:
+ ASSERT_NOT_REACHED();
+ return InvalidFPRReg;
+ }
}
GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex)
@@ -1295,7 +1301,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex)
GPRReg gpr = allocate();
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
m_jit.move(MacroAssembler::TrustedImmPtr(jsValue.asCell()), gpr);
- info.fillCell(gpr);
+ info.fillCell(*m_stream, gpr);
return gpr;
}
@@ -1305,7 +1311,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex)
GPRReg gpr = allocate();
m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
- info.fillCell(gpr);
+ info.fillCell(*m_stream, gpr);
return gpr;
}
@@ -1327,7 +1333,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex)
m_gprs.release(tagGPR);
m_gprs.release(payloadGPR);
m_gprs.retain(payloadGPR, virtualRegister, SpillOrderCell);
- info.fillCell(payloadGPR);
+ info.fillCell(*m_stream, payloadGPR);
return payloadGPR;
}
@@ -1339,10 +1345,11 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex)
case DataFormatBoolean:
case DataFormatStorage:
ASSERT_NOT_REACHED();
- }
- ASSERT_NOT_REACHED();
- return InvalidGPRReg;
+ default:
+ ASSERT_NOT_REACHED();
+ return InvalidGPRReg;
+ }
}
GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex)
@@ -1369,7 +1376,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex)
GPRReg gpr = allocate();
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
m_jit.move(MacroAssembler::TrustedImm32(jsValue.asBoolean()), gpr);
- info.fillBoolean(gpr);
+ info.fillBoolean(*m_stream, gpr);
return gpr;
}
@@ -1381,7 +1388,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex)
GPRReg gpr = allocate();
m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
- info.fillBoolean(gpr);
+ info.fillBoolean(*m_stream, gpr);
return gpr;
}
@@ -1404,7 +1411,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex)
m_gprs.release(tagGPR);
m_gprs.release(payloadGPR);
m_gprs.retain(payloadGPR, virtualRegister, SpillOrderBoolean);
- info.fillBoolean(payloadGPR);
+ info.fillBoolean(*m_stream, payloadGPR);
return payloadGPR;
}
@@ -1416,10 +1423,11 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex)
case DataFormatCell:
case DataFormatStorage:
ASSERT_NOT_REACHED();
- }
- ASSERT_NOT_REACHED();
- return InvalidGPRReg;
+ default:
+ ASSERT_NOT_REACHED();
+ return InvalidGPRReg;
+ }
}
JITCompiler::Jump SpeculativeJIT::convertToDouble(JSValueOperand& op, FPRReg result)
@@ -2003,7 +2011,7 @@ void SpeculativeJIT::compile(Node& node)
// Indicate that it's no longer necessary to retrieve the value of
// this bytecode variable from registers or other locations in the register file,
// but that it is stored as a double.
- valueSourceReferenceForOperand(node.local()) = ValueSource(DoubleInRegisterFile);
+ recordSetLocal(node.local(), ValueSource(DoubleInRegisterFile));
break;
}
SpeculatedType predictedType = node.variableAccessData()->argumentAwarePrediction();
@@ -2011,14 +2019,14 @@ void SpeculativeJIT::compile(Node& node)
DoubleOperand value(this, node.child1());
m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node.local()));
noResult(m_compileIndex);
- valueSourceReferenceForOperand(node.local()) = ValueSource(DoubleInRegisterFile);
+ recordSetLocal(node.local(), ValueSource(DoubleInRegisterFile));
break;
}
if (isInt32Speculation(predictedType)) {
SpeculateIntegerOperand value(this, node.child1());
m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local()));
noResult(m_compileIndex);
- valueSourceReferenceForOperand(node.local()) = ValueSource(Int32InRegisterFile);
+ recordSetLocal(node.local(), ValueSource(Int32InRegisterFile));
break;
}
if (isArraySpeculation(predictedType)) {
@@ -2028,14 +2036,14 @@ void SpeculativeJIT::compile(Node& node)
speculationCheck(BadType, JSValueSource::unboxedCell(cellGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
m_jit.storePtr(cellGPR, JITCompiler::payloadFor(node.local()));
noResult(m_compileIndex);
- valueSourceReferenceForOperand(node.local()) = ValueSource(CellInRegisterFile);
+ recordSetLocal(node.local(), ValueSource(CellInRegisterFile));
break;
}
if (isBooleanSpeculation(predictedType)) {
SpeculateBooleanOperand value(this, node.child1());
m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local()));
noResult(m_compileIndex);
- valueSourceReferenceForOperand(node.local()) = ValueSource(BooleanInRegisterFile);
+ recordSetLocal(node.local(), ValueSource(BooleanInRegisterFile));
break;
}
}
@@ -2043,7 +2051,7 @@ void SpeculativeJIT::compile(Node& node)
m_jit.store32(value.payloadGPR(), JITCompiler::payloadFor(node.local()));
m_jit.store32(value.tagGPR(), JITCompiler::tagFor(node.local()));
noResult(m_compileIndex);
- valueSourceReferenceForOperand(node.local()) = ValueSource(ValueInRegisterFile);
+ recordSetLocal(node.local(), ValueSource(ValueInRegisterFile));
break;
}
@@ -3542,7 +3550,7 @@ void SpeculativeJIT::compile(Node& node)
GPRReg baseGPR = base.gpr();
GPRReg resultGPR = result.gpr();
- m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), resultGPR);
+ m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), resultGPR);
storageResult(resultGPR, m_compileIndex);
break;
@@ -3883,10 +3891,15 @@ void SpeculativeJIT::compile(Node& node)
JITCompiler::Jump structuresNotMatch = m_jit.branchPtr(JITCompiler::NotEqual, resultPayloadGPR, JITCompiler::Address(globalObjectGPR, JSCell::structureOffset()));
// Fast case
- m_jit.loadPtr(JITCompiler::Address(globalObjectGPR, JSObject::offsetOfPropertyStorage()), resultPayloadGPR);
+ m_jit.loadPtr(JITCompiler::Address(globalObjectGPR, JSObject::offsetOfOutOfLineStorage()), resultPayloadGPR);
m_jit.load32(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), resolveInfoGPR);
- m_jit.load32(JITCompiler::BaseIndex(resultPayloadGPR, resolveInfoGPR, JITCompiler::TimesEight, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
- m_jit.load32(JITCompiler::BaseIndex(resultPayloadGPR, resolveInfoGPR, JITCompiler::TimesEight, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR);
+#if DFG_ENABLE(JIT_ASSERT)
+ JITCompiler::Jump isOutOfLine = m_jit.branch32(JITCompiler::GreaterThanOrEqual, resolveInfoGPR, TrustedImm32(inlineStorageCapacity));
+ m_jit.breakpoint();
+ isOutOfLine.link(&m_jit);
+#endif
+ m_jit.load32(JITCompiler::BaseIndex(resultPayloadGPR, resolveInfoGPR, JITCompiler::TimesEight, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag) - inlineStorageCapacity * static_cast<ptrdiff_t>(sizeof(JSValue))), resultTagGPR);
+ m_jit.load32(JITCompiler::BaseIndex(resultPayloadGPR, resolveInfoGPR, JITCompiler::TimesEight, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload) - inlineStorageCapacity * static_cast<ptrdiff_t>(sizeof(JSValue))), resultPayloadGPR);
addSlowPathGenerator(
slowPathCall(
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 215f8013d..27eb28fa7 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -48,7 +48,7 @@ GPRReg SpeculativeJIT::fillInteger(NodeIndex nodeIndex, DataFormat& returnFormat
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
if (isInt32Constant(nodeIndex)) {
m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
- info.fillInteger(gpr);
+ info.fillInteger(*m_stream, gpr);
returnFormat = DataFormatInteger;
return gpr;
}
@@ -74,7 +74,7 @@ GPRReg SpeculativeJIT::fillInteger(NodeIndex nodeIndex, DataFormat& returnFormat
// Since we statically know that we're filling an integer, and values
// in the RegisterFile are boxed, this must be DataFormatJSInteger.
// We will check this with a jitAssert below.
- info.fillJSValue(gpr, DataFormatJSInteger);
+ info.fillJSValue(*m_stream, gpr, DataFormatJSInteger);
unlock(gpr);
}
@@ -107,10 +107,11 @@ GPRReg SpeculativeJIT::fillInteger(NodeIndex nodeIndex, DataFormat& returnFormat
returnFormat = DataFormatInteger;
return gpr;
}
+
+ default:
+ ASSERT_NOT_REACHED();
+ return InvalidGPRReg;
}
-
- ASSERT_NOT_REACHED();
- return InvalidGPRReg;
}
FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex)
@@ -127,7 +128,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex)
// FIXME: should not be reachable?
m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
- info.fillInteger(gpr);
+ info.fillInteger(*m_stream, gpr);
unlock(gpr);
} else if (isNumberConstant(nodeIndex)) {
FPRReg fpr = fprAllocate();
@@ -136,7 +137,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex)
unlock(gpr);
m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
- info.fillDouble(fpr);
+ info.fillDouble(*m_stream, fpr);
return fpr;
} else {
// FIXME: should not be reachable?
@@ -144,7 +145,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex)
JSValue jsValue = valueOfJSConstant(nodeIndex);
m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsValue)), gpr);
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
- info.fillJSValue(gpr, DataFormatJS);
+ info.fillJSValue(*m_stream, gpr, DataFormatJS);
unlock(gpr);
}
} else {
@@ -154,7 +155,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex)
FPRReg fpr = fprAllocate();
m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr);
m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
- info.fillDouble(fpr);
+ info.fillDouble(*m_stream, fpr);
return fpr;
}
@@ -163,7 +164,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex)
m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
m_jit.load32(JITCompiler::addressFor(virtualRegister), gpr);
- info.fillInteger(gpr);
+ info.fillInteger(*m_stream, gpr);
unlock(gpr);
break;
}
@@ -174,7 +175,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex)
ASSERT(spillFormat & DataFormatJS);
m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
- info.fillJSValue(gpr, spillFormat);
+ info.fillJSValue(*m_stream, gpr, spillFormat);
unlock(gpr);
break;
}
@@ -216,7 +217,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex)
m_gprs.unlock(jsValueGpr);
m_gprs.unlock(tempGpr);
m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
- info.fillDouble(fpr);
+ info.fillDouble(*m_stream, fpr);
info.killSpilled();
return fpr;
}
@@ -247,7 +248,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex)
m_gprs.release(gpr);
m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
- info.fillDouble(fpr);
+ info.fillDouble(*m_stream, fpr);
return fpr;
}
@@ -256,10 +257,11 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex)
m_fprs.lock(fpr);
return fpr;
}
+
+ default:
+ ASSERT_NOT_REACHED();
+ return InvalidFPRReg;
}
-
- ASSERT_NOT_REACHED();
- return InvalidFPRReg;
}
GPRReg SpeculativeJIT::fillJSValue(NodeIndex nodeIndex)
@@ -274,18 +276,18 @@ GPRReg SpeculativeJIT::fillJSValue(NodeIndex nodeIndex)
if (node.hasConstant()) {
if (isInt32Constant(nodeIndex)) {
- info.fillJSValue(gpr, DataFormatJSInteger);
+ info.fillJSValue(*m_stream, gpr, DataFormatJSInteger);
JSValue jsValue = jsNumber(valueOfInt32Constant(nodeIndex));
m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
} else if (isNumberConstant(nodeIndex)) {
- info.fillJSValue(gpr, DataFormatJSDouble);
+ info.fillJSValue(*m_stream, gpr, DataFormatJSDouble);
JSValue jsValue(JSValue::EncodeAsDouble, valueOfNumberConstant(nodeIndex));
m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
} else {
ASSERT(isJSConstant(nodeIndex));
JSValue jsValue = valueOfJSConstant(nodeIndex);
m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsValue)), gpr);
- info.fillJSValue(gpr, DataFormatJS);
+ info.fillJSValue(*m_stream, gpr, DataFormatJS);
}
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
@@ -305,7 +307,7 @@ GPRReg SpeculativeJIT::fillJSValue(NodeIndex nodeIndex)
} else
ASSERT(spillFormat & DataFormatJS);
}
- info.fillJSValue(gpr, spillFormat);
+ info.fillJSValue(*m_stream, gpr, spillFormat);
}
return gpr;
}
@@ -321,7 +323,7 @@ GPRReg SpeculativeJIT::fillJSValue(NodeIndex nodeIndex)
}
m_gprs.lock(gpr);
m_jit.orPtr(GPRInfo::tagTypeNumberRegister, gpr);
- info.fillJSValue(gpr, DataFormatJSInteger);
+ info.fillJSValue(*m_stream, gpr, DataFormatJSInteger);
return gpr;
}
@@ -330,7 +332,7 @@ GPRReg SpeculativeJIT::fillJSValue(NodeIndex nodeIndex)
GPRReg gpr = boxDouble(fpr);
// Update all info
- info.fillJSValue(gpr, DataFormatJSDouble);
+ info.fillJSValue(*m_stream, gpr, DataFormatJSDouble);
m_fprs.release(fpr);
m_gprs.retain(gpr, virtualRegister, SpillOrderJS);
@@ -353,10 +355,11 @@ GPRReg SpeculativeJIT::fillJSValue(NodeIndex nodeIndex)
case DataFormatStorage:
// this type currently never occurs
ASSERT_NOT_REACHED();
+
+ default:
+ ASSERT_NOT_REACHED();
+ return InvalidGPRReg;
}
-
- ASSERT_NOT_REACHED();
- return InvalidGPRReg;
}
class ValueToNumberSlowPathGenerator
@@ -494,7 +497,8 @@ void SpeculativeJIT::cachedGetById(CodeOrigin codeOrigin, GPRReg baseGPR, GPRReg
JITCompiler::DataLabelPtr structureToCompare;
JITCompiler::PatchableJump structureCheck = m_jit.patchableBranchPtrWithPatch(JITCompiler::NotEqual, JITCompiler::Address(baseGPR, JSCell::structureOffset()), structureToCompare, JITCompiler::TrustedImmPtr(reinterpret_cast<void*>(-1)));
- m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), resultGPR);
+ JITCompiler::ConvertibleLoadLabel propertyStorageLoad =
+ m_jit.convertibleLoadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), resultGPR);
JITCompiler::DataLabelCompact loadWithPatch = m_jit.loadPtrWithCompactAddressOffsetPatch(JITCompiler::Address(resultGPR, 0), resultGPR);
JITCompiler::Label doneLabel = m_jit.label();
@@ -514,8 +518,8 @@ void SpeculativeJIT::cachedGetById(CodeOrigin codeOrigin, GPRReg baseGPR, GPRReg
}
m_jit.addPropertyAccess(
PropertyAccessRecord(
- codeOrigin, structureToCompare, structureCheck, loadWithPatch, slowPath.get(),
- doneLabel, safeCast<int8_t>(baseGPR), safeCast<int8_t>(resultGPR),
+ codeOrigin, structureToCompare, structureCheck, propertyStorageLoad, loadWithPatch,
+ slowPath.get(), doneLabel, safeCast<int8_t>(baseGPR), safeCast<int8_t>(resultGPR),
safeCast<int8_t>(scratchGPR),
spillMode == NeedToSpill ? PropertyAccessRecord::RegistersInUse : PropertyAccessRecord::RegistersFlushed));
addSlowPathGenerator(slowPath.release());
@@ -533,7 +537,8 @@ void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg baseGPR, GPRReg
writeBarrier(baseGPR, valueGPR, valueUse, WriteBarrierForPropertyAccess, scratchGPR);
- m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
+ JITCompiler::ConvertibleLoadLabel propertyStorageLoad =
+ m_jit.convertibleLoadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR);
JITCompiler::DataLabel32 storeWithPatch = m_jit.storePtrWithAddressOffsetPatch(valueGPR, JITCompiler::Address(scratchGPR, 0));
JITCompiler::Label doneLabel = m_jit.label();
@@ -563,7 +568,11 @@ void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg baseGPR, GPRReg
slowCases, this, optimizedCall, NoResult, valueGPR, baseGPR,
identifier(identifierNumber));
}
- m_jit.addPropertyAccess(PropertyAccessRecord(codeOrigin, structureToCompare, structureCheck, JITCompiler::DataLabelCompact(storeWithPatch.label()), slowPath.get(), doneLabel, safeCast<int8_t>(baseGPR), safeCast<int8_t>(valueGPR), safeCast<int8_t>(scratchGPR)));
+ m_jit.addPropertyAccess(
+ PropertyAccessRecord(
+ codeOrigin, structureToCompare, structureCheck, propertyStorageLoad,
+ JITCompiler::DataLabelCompact(storeWithPatch.label()), slowPath.get(), doneLabel,
+ safeCast<int8_t>(baseGPR), safeCast<int8_t>(valueGPR), safeCast<int8_t>(scratchGPR)));
addSlowPathGenerator(slowPath.release());
}
@@ -1047,7 +1056,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat&
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
ASSERT(isInt32Constant(nodeIndex));
m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
- info.fillInteger(gpr);
+ info.fillInteger(*m_stream, gpr);
returnFormat = DataFormatInteger;
return gpr;
}
@@ -1062,7 +1071,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat&
// If we know this was spilled as an integer we can fill without checking.
if (strict) {
m_jit.load32(JITCompiler::addressFor(virtualRegister), gpr);
- info.fillInteger(gpr);
+ info.fillInteger(*m_stream, gpr);
returnFormat = DataFormatInteger;
return gpr;
}
@@ -1071,14 +1080,14 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat&
m_jit.orPtr(GPRInfo::tagTypeNumberRegister, gpr);
} else
m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
- info.fillJSValue(gpr, DataFormatJSInteger);
+ info.fillJSValue(*m_stream, gpr, DataFormatJSInteger);
returnFormat = DataFormatJSInteger;
return gpr;
}
m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
// Fill as JSValue, and fall through.
- info.fillJSValue(gpr, DataFormatJSInteger);
+ info.fillJSValue(*m_stream, gpr, DataFormatJSInteger);
m_gprs.unlock(gpr);
}
@@ -1088,7 +1097,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat&
m_gprs.lock(gpr);
if (!isInt32Speculation(type))
speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchPtr(MacroAssembler::Below, gpr, GPRInfo::tagTypeNumberRegister));
- info.fillJSValue(gpr, DataFormatJSInteger);
+ info.fillJSValue(*m_stream, gpr, DataFormatJSInteger);
// If !strict we're done, return.
if (!strict) {
returnFormat = DataFormatJSInteger;
@@ -1109,7 +1118,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat&
result = allocate();
else {
m_gprs.lock(gpr);
- info.fillInteger(gpr);
+ info.fillInteger(*m_stream, gpr);
result = gpr;
}
m_jit.zeroExtend32ToPtr(gpr, result);
@@ -1151,10 +1160,11 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat&
case DataFormatStorage:
ASSERT_NOT_REACHED();
+
+ default:
+ ASSERT_NOT_REACHED();
+ return InvalidGPRReg;
}
-
- ASSERT_NOT_REACHED();
- return InvalidGPRReg;
}
GPRReg SpeculativeJIT::fillSpeculateInt(NodeIndex nodeIndex, DataFormat& returnFormat)
@@ -1191,7 +1201,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex)
unlock(gpr);
m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
- info.fillDouble(fpr);
+ info.fillDouble(*m_stream, fpr);
return fpr;
}
if (isNumberConstant(nodeIndex)) {
@@ -1201,7 +1211,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex)
unlock(gpr);
m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
- info.fillDouble(fpr);
+ info.fillDouble(*m_stream, fpr);
return fpr;
}
terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
@@ -1214,7 +1224,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex)
FPRReg fpr = fprAllocate();
m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr);
m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
- info.fillDouble(fpr);
+ info.fillDouble(*m_stream, fpr);
return fpr;
}
@@ -1223,7 +1233,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex)
m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
m_jit.load32(JITCompiler::addressFor(virtualRegister), gpr);
- info.fillInteger(gpr);
+ info.fillInteger(*m_stream, gpr);
unlock(gpr);
break;
}
@@ -1234,7 +1244,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex)
ASSERT(spillFormat & DataFormatJS);
m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
- info.fillJSValue(gpr, spillFormat);
+ info.fillJSValue(*m_stream, gpr, spillFormat);
unlock(gpr);
break;
}
@@ -1277,7 +1287,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex)
m_gprs.unlock(jsValueGpr);
m_gprs.unlock(tempGpr);
m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
- info.fillDouble(fpr);
+ info.fillDouble(*m_stream, fpr);
info.killSpilled();
return fpr;
}
@@ -1308,7 +1318,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex)
m_gprs.release(gpr);
m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
- info.fillDouble(fpr);
+ info.fillDouble(*m_stream, fpr);
return fpr;
}
@@ -1317,10 +1327,11 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex)
m_fprs.lock(fpr);
return fpr;
}
+
+ default:
+ ASSERT_NOT_REACHED();
+ return InvalidFPRReg;
}
-
- ASSERT_NOT_REACHED();
- return InvalidFPRReg;
}
GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex)
@@ -1347,7 +1358,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex)
if (jsValue.isCell()) {
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
m_jit.move(MacroAssembler::TrustedImmPtr(jsValue.asCell()), gpr);
- info.fillJSValue(gpr, DataFormatJSCell);
+ info.fillJSValue(*m_stream, gpr, DataFormatJSCell);
return gpr;
}
terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
@@ -1357,10 +1368,10 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex)
m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
- info.fillJSValue(gpr, DataFormatJS);
+ info.fillJSValue(*m_stream, gpr, DataFormatJS);
if (!isCellSpeculation(type))
speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister));
- info.fillJSValue(gpr, DataFormatJSCell);
+ info.fillJSValue(*m_stream, gpr, DataFormatJSCell);
return gpr;
}
@@ -1376,7 +1387,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex)
m_gprs.lock(gpr);
if (!isCellSpeculation(type))
speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister));
- info.fillJSValue(gpr, DataFormatJSCell);
+ info.fillJSValue(*m_stream, gpr, DataFormatJSCell);
return gpr;
}
@@ -1392,10 +1403,11 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex)
case DataFormatStorage:
ASSERT_NOT_REACHED();
+
+ default:
+ ASSERT_NOT_REACHED();
+ return InvalidGPRReg;
}
-
- ASSERT_NOT_REACHED();
- return InvalidGPRReg;
}
GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex)
@@ -1422,7 +1434,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex)
if (jsValue.isBoolean()) {
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsValue)), gpr);
- info.fillJSValue(gpr, DataFormatJSBoolean);
+ info.fillJSValue(*m_stream, gpr, DataFormatJSBoolean);
return gpr;
}
terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
@@ -1432,13 +1444,13 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex)
m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
- info.fillJSValue(gpr, DataFormatJS);
+ info.fillJSValue(*m_stream, gpr, DataFormatJS);
if (!isBooleanSpeculation(type)) {
m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr);
speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg));
m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr);
}
- info.fillJSValue(gpr, DataFormatJSBoolean);
+ info.fillJSValue(*m_stream, gpr, DataFormatJSBoolean);
return gpr;
}
@@ -1457,7 +1469,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex)
speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg));
m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr);
}
- info.fillJSValue(gpr, DataFormatJSBoolean);
+ info.fillJSValue(*m_stream, gpr, DataFormatJSBoolean);
return gpr;
}
@@ -1473,10 +1485,11 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex)
case DataFormatStorage:
ASSERT_NOT_REACHED();
+
+ default:
+ ASSERT_NOT_REACHED();
+ return InvalidGPRReg;
}
-
- ASSERT_NOT_REACHED();
- return InvalidGPRReg;
}
JITCompiler::Jump SpeculativeJIT::convertToDouble(GPRReg value, FPRReg result, GPRReg tmp)
@@ -2055,7 +2068,7 @@ void SpeculativeJIT::compile(Node& node)
// Indicate that it's no longer necessary to retrieve the value of
// this bytecode variable from registers or other locations in the register file,
// but that it is stored as a double.
- valueSourceReferenceForOperand(node.local()) = ValueSource(DoubleInRegisterFile);
+ recordSetLocal(node.local(), ValueSource(DoubleInRegisterFile));
break;
}
@@ -2064,7 +2077,7 @@ void SpeculativeJIT::compile(Node& node)
SpeculateIntegerOperand value(this, node.child1());
m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local()));
noResult(m_compileIndex);
- valueSourceReferenceForOperand(node.local()) = ValueSource(Int32InRegisterFile);
+ recordSetLocal(node.local(), ValueSource(Int32InRegisterFile));
break;
}
if (isArraySpeculation(predictedType)) {
@@ -2074,14 +2087,14 @@ void SpeculativeJIT::compile(Node& node)
speculationCheck(BadType, JSValueRegs(cellGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
m_jit.storePtr(cellGPR, JITCompiler::addressFor(node.local()));
noResult(m_compileIndex);
- valueSourceReferenceForOperand(node.local()) = ValueSource(CellInRegisterFile);
+ recordSetLocal(node.local(), ValueSource(CellInRegisterFile));
break;
}
if (isBooleanSpeculation(predictedType)) {
SpeculateBooleanOperand boolean(this, node.child1());
m_jit.storePtr(boolean.gpr(), JITCompiler::addressFor(node.local()));
noResult(m_compileIndex);
- valueSourceReferenceForOperand(node.local()) = ValueSource(BooleanInRegisterFile);
+ recordSetLocal(node.local(), ValueSource(BooleanInRegisterFile));
break;
}
}
@@ -2090,7 +2103,7 @@ void SpeculativeJIT::compile(Node& node)
m_jit.storePtr(value.gpr(), JITCompiler::addressFor(node.local()));
noResult(m_compileIndex);
- valueSourceReferenceForOperand(node.local()) = ValueSource(ValueInRegisterFile);
+ recordSetLocal(node.local(), ValueSource(ValueInRegisterFile));
break;
}
@@ -3567,7 +3580,7 @@ void SpeculativeJIT::compile(Node& node)
GPRReg baseGPR = base.gpr();
GPRReg resultGPR = result.gpr();
- m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), resultGPR);
+ m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), resultGPR);
storageResult(resultGPR, m_compileIndex);
break;
@@ -3883,9 +3896,14 @@ void SpeculativeJIT::compile(Node& node)
JITCompiler::Jump structuresDontMatch = m_jit.branchPtr(JITCompiler::NotEqual, resultGPR, JITCompiler::Address(globalObjectGPR, JSCell::structureOffset()));
// Fast case
- m_jit.loadPtr(JITCompiler::Address(globalObjectGPR, JSObject::offsetOfPropertyStorage()), resultGPR);
m_jit.load32(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), resolveInfoGPR);
- m_jit.loadPtr(JITCompiler::BaseIndex(resultGPR, resolveInfoGPR, JITCompiler::ScalePtr), resultGPR);
+#if DFG_ENABLE(JIT_ASSERT)
+ JITCompiler::Jump isOutOfLine = m_jit.branch32(JITCompiler::GreaterThanOrEqual, resolveInfoGPR, TrustedImm32(inlineStorageCapacity));
+ m_jit.breakpoint();
+ isOutOfLine.link(&m_jit);
+#endif
+ m_jit.loadPtr(JITCompiler::Address(globalObjectGPR, JSObject::offsetOfOutOfLineStorage()), resultGPR);
+ m_jit.loadPtr(JITCompiler::BaseIndex(resultGPR, resolveInfoGPR, JITCompiler::ScalePtr, -inlineStorageCapacity * static_cast<ptrdiff_t>(sizeof(JSValue))), resultGPR);
addSlowPathGenerator(
slowPathCall(
diff --git a/Source/JavaScriptCore/dfg/DFGValueRecoveryOverride.h b/Source/JavaScriptCore/dfg/DFGValueRecoveryOverride.h
new file mode 100644
index 000000000..317111aec
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGValueRecoveryOverride.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGValueRecoveryOverride_h
+#define DFGValueRecoveryOverride_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(DFG_JIT)
+
+#include "ValueRecovery.h"
+#include <wtf/RefCounted.h>
+
+namespace JSC { namespace DFG {
+
+class ValueRecoveryOverride : public RefCounted<ValueRecoveryOverride> {
+public:
+ ValueRecoveryOverride() { }
+
+ ValueRecoveryOverride(int operand, const ValueRecovery& recovery)
+ : operand(operand)
+ , recovery(recovery)
+ {
+ }
+
+ int operand;
+ ValueRecovery recovery;
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGValueRecoveryOverride_h
+
diff --git a/Source/JavaScriptCore/dfg/DFGValueSource.cpp b/Source/JavaScriptCore/dfg/DFGValueSource.cpp
new file mode 100644
index 000000000..25d43ee6b
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGValueSource.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DFGValueSource.h"
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+void ValueSource::dump(FILE* out) const
+{
+ switch (kind()) {
+ case SourceNotSet:
+ fprintf(out, "NotSet");
+ break;
+ case SourceIsDead:
+ fprintf(out, "IsDead");
+ break;
+ case ValueInRegisterFile:
+ fprintf(out, "InRegFile");
+ break;
+ case Int32InRegisterFile:
+ fprintf(out, "Int32");
+ break;
+ case CellInRegisterFile:
+ fprintf(out, "Cell");
+ break;
+ case BooleanInRegisterFile:
+ fprintf(out, "Bool");
+ break;
+ case DoubleInRegisterFile:
+ fprintf(out, "Double");
+ break;
+ case ArgumentsSource:
+ fprintf(out, "Arguments");
+ break;
+ case HaveNode:
+ fprintf(out, "Node(%d)", m_nodeIndex);
+ break;
+ }
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
diff --git a/Source/JavaScriptCore/dfg/DFGValueSource.h b/Source/JavaScriptCore/dfg/DFGValueSource.h
new file mode 100644
index 000000000..be4a6e081
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGValueSource.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGValueSource_h
+#define DFGValueSource_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGCommon.h"
+#include "DataFormat.h"
+#include "SpeculatedType.h"
+#include "ValueRecovery.h"
+
+namespace JSC { namespace DFG {
+
+enum ValueSourceKind {
+ SourceNotSet,
+ ValueInRegisterFile,
+ Int32InRegisterFile,
+ CellInRegisterFile,
+ BooleanInRegisterFile,
+ DoubleInRegisterFile,
+ ArgumentsSource,
+ SourceIsDead,
+ HaveNode
+};
+
+static inline ValueSourceKind dataFormatToValueSourceKind(DataFormat dataFormat)
+{
+ switch (dataFormat) {
+ case DataFormatInteger:
+ return Int32InRegisterFile;
+ case DataFormatDouble:
+ return DoubleInRegisterFile;
+ case DataFormatBoolean:
+ return BooleanInRegisterFile;
+ case DataFormatCell:
+ return CellInRegisterFile;
+ case DataFormatDead:
+ return SourceIsDead;
+ case DataFormatArguments:
+ return ArgumentsSource;
+ default:
+ ASSERT(dataFormat & DataFormatJS);
+ return ValueInRegisterFile;
+ }
+}
+
+static inline DataFormat valueSourceKindToDataFormat(ValueSourceKind kind)
+{
+ switch (kind) {
+ case ValueInRegisterFile:
+ return DataFormatJS;
+ case Int32InRegisterFile:
+ return DataFormatInteger;
+ case CellInRegisterFile:
+ return DataFormatCell;
+ case BooleanInRegisterFile:
+ return DataFormatBoolean;
+ case DoubleInRegisterFile:
+ return DataFormatDouble;
+ case ArgumentsSource:
+ return DataFormatArguments;
+ case SourceIsDead:
+ return DataFormatDead;
+ default:
+ return DataFormatNone;
+ }
+}
+
+static inline bool isInRegisterFile(ValueSourceKind kind)
+{
+ DataFormat format = valueSourceKindToDataFormat(kind);
+ return format != DataFormatNone && format < DataFormatOSRMarker;
+}
+
+// Can this value be recovered without having to look at register allocation state or
+// DFG node liveness?
+static inline bool isTriviallyRecoverable(ValueSourceKind kind)
+{
+ return valueSourceKindToDataFormat(kind) != DataFormatNone;
+}
+
+class ValueSource {
+public:
+ ValueSource()
+ : m_nodeIndex(nodeIndexFromKind(SourceNotSet))
+ {
+ }
+
+ explicit ValueSource(ValueSourceKind valueSourceKind)
+ : m_nodeIndex(nodeIndexFromKind(valueSourceKind))
+ {
+ ASSERT(kind() != SourceNotSet);
+ ASSERT(kind() != HaveNode);
+ }
+
+ explicit ValueSource(NodeIndex nodeIndex)
+ : m_nodeIndex(nodeIndex)
+ {
+ ASSERT(nodeIndex != NoNode);
+ ASSERT(kind() == HaveNode);
+ }
+
+ static ValueSource forSpeculation(SpeculatedType prediction)
+ {
+ if (isInt32Speculation(prediction))
+ return ValueSource(Int32InRegisterFile);
+ if (isArraySpeculation(prediction))
+ return ValueSource(CellInRegisterFile);
+ if (isBooleanSpeculation(prediction))
+ return ValueSource(BooleanInRegisterFile);
+ return ValueSource(ValueInRegisterFile);
+ }
+
+ static ValueSource forDataFormat(DataFormat dataFormat)
+ {
+ return ValueSource(dataFormatToValueSourceKind(dataFormat));
+ }
+
+ bool isSet() const
+ {
+ return kindFromNodeIndex(m_nodeIndex) != SourceNotSet;
+ }
+
+ ValueSourceKind kind() const
+ {
+ return kindFromNodeIndex(m_nodeIndex);
+ }
+
+ bool isInRegisterFile() const { return JSC::DFG::isInRegisterFile(kind()); }
+ bool isTriviallyRecoverable() const { return JSC::DFG::isTriviallyRecoverable(kind()); }
+
+ DataFormat dataFormat() const
+ {
+ return valueSourceKindToDataFormat(kind());
+ }
+
+ ValueRecovery valueRecovery() const
+ {
+ ASSERT(isTriviallyRecoverable());
+ switch (kind()) {
+ case ValueInRegisterFile:
+ return ValueRecovery::alreadyInRegisterFile();
+
+ case Int32InRegisterFile:
+ return ValueRecovery::alreadyInRegisterFileAsUnboxedInt32();
+
+ case CellInRegisterFile:
+ return ValueRecovery::alreadyInRegisterFileAsUnboxedCell();
+
+ case BooleanInRegisterFile:
+ return ValueRecovery::alreadyInRegisterFileAsUnboxedBoolean();
+
+ case DoubleInRegisterFile:
+ return ValueRecovery::alreadyInRegisterFileAsUnboxedDouble();
+
+ case SourceIsDead:
+ return ValueRecovery::constant(jsUndefined());
+
+ case ArgumentsSource:
+ return ValueRecovery::argumentsThatWereNotCreated();
+
+ default:
+ ASSERT_NOT_REACHED();
+ return ValueRecovery();
+ }
+ }
+
+ NodeIndex nodeIndex() const
+ {
+ ASSERT(kind() == HaveNode);
+ return m_nodeIndex;
+ }
+
+ void dump(FILE* out) const;
+
+private:
+ static NodeIndex nodeIndexFromKind(ValueSourceKind kind)
+ {
+ ASSERT(kind >= SourceNotSet && kind < HaveNode);
+ return NoNode - kind;
+ }
+
+ static ValueSourceKind kindFromNodeIndex(NodeIndex nodeIndex)
+ {
+ unsigned kind = static_cast<unsigned>(NoNode - nodeIndex);
+ if (kind >= static_cast<unsigned>(HaveNode))
+ return HaveNode;
+ return static_cast<ValueSourceKind>(kind);
+ }
+
+ NodeIndex m_nodeIndex;
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGValueSource_h
+
diff --git a/Source/JavaScriptCore/dfg/DFGVariableAccessData.h b/Source/JavaScriptCore/dfg/DFGVariableAccessData.h
index 382907d27..e734e6387 100644
--- a/Source/JavaScriptCore/dfg/DFGVariableAccessData.h
+++ b/Source/JavaScriptCore/dfg/DFGVariableAccessData.h
@@ -176,7 +176,7 @@ public:
// If the variable has been voted to become a double, then make it a
// double.
- if (doubleVoteRatio() >= Options::doubleVoteRatioForDoubleFormat)
+ if (doubleVoteRatio() >= Options::doubleVoteRatioForDoubleFormat())
return true;
return false;
diff --git a/Source/JavaScriptCore/dfg/DFGVariableEvent.cpp b/Source/JavaScriptCore/dfg/DFGVariableEvent.cpp
new file mode 100644
index 000000000..3e84a6ba1
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGVariableEvent.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DFGVariableEvent.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGFPRInfo.h"
+#include "DFGGPRInfo.h"
+
+namespace JSC { namespace DFG {
+
+void VariableEvent::dump(FILE* out) const
+{
+ switch (kind()) {
+ case Reset:
+ fprintf(out, "Reset");
+ break;
+ case BirthToFill:
+ dumpFillInfo("BirthToFill", out);
+ break;
+ case BirthToSpill:
+ dumpSpillInfo("BirthToSpill", out);
+ break;
+ case Fill:
+ dumpFillInfo("Fill", out);
+ break;
+ case Spill:
+ dumpSpillInfo("Spill", out);
+ break;
+ case Death:
+ fprintf(out, "Death(@%u)", nodeIndex());
+ break;
+ case MovHint:
+ fprintf(out, "MovHint(@%u, r%d)", nodeIndex(), operand());
+ break;
+ case SetLocalEvent:
+ fprintf(out, "SetLocal(r%d, %s)", operand(), dataFormatToString(dataFormat()));
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+}
+
+void VariableEvent::dumpFillInfo(const char* name, FILE* out) const
+{
+ fprintf(out, "%s(@%u, ", name, nodeIndex());
+ if (dataFormat() == DataFormatDouble)
+ fprintf(out, "%s", FPRInfo::debugName(fpr()));
+#if USE(JSVALUE32_64)
+ else if (dataFormat() & DataFormatJS)
+ fprintf(out, "%s:%s", GPRInfo::debugName(tagGPR()), GPRInfo::debugName(payloadGPR()));
+#endif
+ else
+ fprintf(out, "%s", GPRInfo::debugName(gpr()));
+ fprintf(out, ", %s)", dataFormatToString(dataFormat()));
+}
+
+void VariableEvent::dumpSpillInfo(const char* name, FILE* out) const
+{
+ fprintf(out, "%s(@%u, r%d, %s)", name, nodeIndex(), virtualRegister(), dataFormatToString(dataFormat()));
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
diff --git a/Source/JavaScriptCore/dfg/DFGVariableEvent.h b/Source/JavaScriptCore/dfg/DFGVariableEvent.h
new file mode 100644
index 000000000..a491a3ebf
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGVariableEvent.h
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGVariableEvent_h
+#define DFGVariableEvent_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGCommon.h"
+#include "DataFormat.h"
+#include "MacroAssembler.h"
+#include <stdio.h>
+
+namespace JSC { namespace DFG {
+
+enum VariableEventKind {
+ // Marks the beginning of a checkpoint. If you interpret the variable
+ // events starting at a Reset point then you'll get everything you need.
+ Reset,
+
+ // Node births. Points in the code where a node becomes relevant for OSR.
+ // It may be the point where it is actually born (i.e. assigned) or it may
+ // be a later point, if it's only later in the sequence of instructions
+ // that we start to care about this node.
+ BirthToFill,
+ BirthToSpill,
+
+ // Events related to how a node is represented.
+ Fill,
+ Spill,
+
+ // Death of a node - after this we no longer care about this node.
+ Death,
+
+ // A MovHint means that a node is being associated with a bytecode operand,
+ // but that it has not been stored into that operand.
+ MovHint,
+
+ // A SetLocalEvent means that a node's value has actually been stored into the
+ // bytecode operand that it's associated with.
+ SetLocalEvent,
+
+ // Used to indicate an uninitialized VariableEvent. Don't use for other
+ // purposes.
+ InvalidEventKind
+};
+
+union VariableRepresentation {
+ MacroAssembler::RegisterID gpr;
+ MacroAssembler::FPRegisterID fpr;
+#if USE(JSVALUE32_64)
+ struct {
+ MacroAssembler::RegisterID tagGPR;
+ MacroAssembler::RegisterID payloadGPR;
+ } pair;
+#endif
+ int32_t virtualReg;
+};
+
+class VariableEvent {
+public:
+ VariableEvent()
+ : m_kind(InvalidEventKind)
+ {
+ }
+
+ static VariableEvent reset()
+ {
+ VariableEvent event;
+ event.m_kind = Reset;
+ return event;
+ }
+
+ static VariableEvent fillGPR(VariableEventKind kind, NodeIndex nodeIndex, MacroAssembler::RegisterID gpr, DataFormat dataFormat)
+ {
+ ASSERT(kind == BirthToFill || kind == Fill);
+ ASSERT(dataFormat != DataFormatDouble);
+#if USE(JSVALUE32_64)
+ ASSERT(!(dataFormat & DataFormatJS));
+#endif
+ VariableEvent event;
+ event.m_index = nodeIndex;
+ event.u.gpr = gpr;
+ event.m_kind = kind;
+ event.m_dataFormat = dataFormat;
+ return event;
+ }
+
+#if USE(JSVALUE32_64)
+ static VariableEvent fillPair(VariableEventKind kind, NodeIndex nodeIndex, MacroAssembler::RegisterID tagGPR, MacroAssembler::RegisterID payloadGPR)
+ {
+ ASSERT(kind == BirthToFill || kind == Fill);
+ VariableEvent event;
+ event.m_index = nodeIndex;
+ event.u.pair.tagGPR = tagGPR;
+ event.u.pair.payloadGPR = payloadGPR;
+ event.m_kind = kind;
+ event.m_dataFormat = DataFormatJS;
+ return event;
+ }
+#endif // USE(JSVALUE32_64)
+
+ static VariableEvent fillFPR(VariableEventKind kind, NodeIndex nodeIndex, MacroAssembler::FPRegisterID fpr)
+ {
+ ASSERT(kind == BirthToFill || kind == Fill);
+ VariableEvent event;
+ event.m_index = nodeIndex;
+ event.u.fpr = fpr;
+ event.m_kind = kind;
+ event.m_dataFormat = DataFormatDouble;
+ return event;
+ }
+
+ static VariableEvent spill(VariableEventKind kind, NodeIndex nodeIndex, VirtualRegister virtualRegister, DataFormat format)
+ {
+ ASSERT(kind == BirthToSpill || kind == Spill);
+ VariableEvent event;
+ event.m_index = nodeIndex;
+ event.u.virtualReg = virtualRegister;
+ event.m_kind = kind;
+ event.m_dataFormat = format;
+ return event;
+ }
+
+ static VariableEvent death(NodeIndex nodeIndex)
+ {
+ VariableEvent event;
+ event.m_index = nodeIndex;
+ event.m_kind = Death;
+ return event;
+ }
+
+ static VariableEvent setLocal(int operand, DataFormat format)
+ {
+ VariableEvent event;
+ event.u.virtualReg = operand;
+ event.m_kind = SetLocalEvent;
+ event.m_dataFormat = format;
+ return event;
+ }
+
+ static VariableEvent movHint(NodeIndex nodeIndex, int operand)
+ {
+ VariableEvent event;
+ event.m_index = nodeIndex;
+ event.u.virtualReg = operand;
+ event.m_kind = MovHint;
+ return event;
+ }
+
+ VariableEventKind kind() const
+ {
+ return static_cast<VariableEventKind>(m_kind);
+ }
+
+ NodeIndex nodeIndex() const
+ {
+ ASSERT(m_kind == BirthToFill || m_kind == Fill
+ || m_kind == BirthToSpill || m_kind == Spill
+ || m_kind == Death || m_kind == MovHint);
+ return m_index;
+ }
+
+ DataFormat dataFormat() const
+ {
+ ASSERT(m_kind == BirthToFill || m_kind == Fill
+ || m_kind == BirthToSpill || m_kind == Spill
+ || m_kind == SetLocalEvent);
+ return static_cast<DataFormat>(m_dataFormat);
+ }
+
+ MacroAssembler::RegisterID gpr() const
+ {
+ ASSERT(m_kind == BirthToFill || m_kind == Fill);
+ ASSERT(m_dataFormat);
+ ASSERT(m_dataFormat != DataFormatDouble);
+#if USE(JSVALUE32_64)
+ ASSERT(!(m_dataFormat & DataFormatJS));
+#endif
+ return u.gpr;
+ }
+
+#if USE(JSVALUE32_64)
+ MacroAssembler::RegisterID tagGPR() const
+ {
+ ASSERT(m_kind == BirthToFill || m_kind == Fill);
+ ASSERT(m_dataFormat & DataFormatJS);
+ return u.pair.tagGPR;
+ }
+ MacroAssembler::RegisterID payloadGPR() const
+ {
+ ASSERT(m_kind == BirthToFill || m_kind == Fill);
+ ASSERT(m_dataFormat & DataFormatJS);
+ return u.pair.payloadGPR;
+ }
+#endif // USE(JSVALUE32_64)
+
+ MacroAssembler::FPRegisterID fpr() const
+ {
+ ASSERT(m_kind == BirthToFill || m_kind == Fill);
+ ASSERT(m_dataFormat == DataFormatDouble);
+ return u.fpr;
+ }
+
+ VirtualRegister virtualRegister() const
+ {
+ ASSERT(m_kind == BirthToSpill || m_kind == Spill);
+ return static_cast<VirtualRegister>(u.virtualReg);
+ }
+
+ int operand() const
+ {
+ ASSERT(m_kind == SetLocalEvent || m_kind == MovHint);
+ return u.virtualReg;
+ }
+
+ const VariableRepresentation& variableRepresentation() const { return u; }
+
+ void dump(FILE*) const;
+
+private:
+ void dumpFillInfo(const char* name, FILE*) const;
+ void dumpSpillInfo(const char* name, FILE*) const;
+
+ NodeIndex m_index;
+
+ // For BirthToFill, Fill:
+ // - The GPR or FPR, or a GPR pair.
+ // For BirthToSpill, Spill:
+ // - The virtual register.
+ // For MovHint, SetLocalEvent:
+ // - The bytecode operand.
+ // For Death:
+ // - Unused.
+ VariableRepresentation u;
+
+ int8_t m_kind;
+ int8_t m_dataFormat;
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGVariableEvent_h
+
diff --git a/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp b/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp
new file mode 100644
index 000000000..5d548a755
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DFGVariableEventStream.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "CodeBlock.h"
+#include "DFGValueSource.h"
+#include <wtf/DataLog.h>
+
+namespace JSC { namespace DFG {
+
+void VariableEventStream::logEvent(const VariableEvent& event)
+{
+ dataLog("seq#%u:", static_cast<unsigned>(size()));
+ event.dump(WTF::dataFile());
+ dataLog(" ");
+}
+
+struct MinifiedGenerationInfo {
+ bool filled; // true -> in gpr/fpr/pair, false -> spilled
+ VariableRepresentation u;
+ DataFormat format;
+
+ MinifiedGenerationInfo()
+ : format(DataFormatNone)
+ {
+ }
+
+ void update(const VariableEvent& event)
+ {
+ switch (event.kind()) {
+ case BirthToFill:
+ case Fill:
+ filled = true;
+ break;
+ case BirthToSpill:
+ case Spill:
+ filled = false;
+ break;
+ case Death:
+ format = DataFormatNone;
+ return;
+ default:
+ return;
+ }
+
+ u = event.variableRepresentation();
+ format = event.dataFormat();
+ }
+};
+
+void VariableEventStream::reconstruct(
+ CodeBlock* codeBlock, CodeOrigin codeOrigin, MinifiedGraph& graph,
+ unsigned index, Operands<ValueRecovery>& valueRecoveries) const
+{
+ ASSERT(codeBlock->getJITType() == JITCode::DFGJIT);
+ CodeBlock* baselineCodeBlock = codeBlock->baselineVersion();
+
+ unsigned numVariables;
+ if (codeOrigin.inlineCallFrame)
+ numVariables = baselineCodeBlockForInlineCallFrame(codeOrigin.inlineCallFrame)->m_numCalleeRegisters + codeOrigin.inlineCallFrame->stackOffset;
+ else
+ numVariables = baselineCodeBlock->m_numCalleeRegisters;
+
+ // Crazy special case: if we're at index == 0 then this must be an argument check
+ // failure, in which case all variables are already set up. The recoveries should
+ // reflect this.
+ if (!index) {
+ valueRecoveries = Operands<ValueRecovery>(codeBlock->numParameters(), numVariables);
+ for (size_t i = 0; i < valueRecoveries.size(); ++i)
+ valueRecoveries[i] = ValueRecovery::alreadyInRegisterFile();
+ return;
+ }
+
+ // Step 1: Find the last checkpoint, and figure out the number of virtual registers as we go.
+ unsigned startIndex = index - 1;
+ while (at(startIndex).kind() != Reset)
+ startIndex--;
+
+ // Step 2: Create a mock-up of the DFG's state and execute the events.
+ Operands<ValueSource> operandSources(codeBlock->numParameters(), numVariables);
+ Vector<MinifiedGenerationInfo, 32> generationInfos(graph.originalGraphSize());
+ for (unsigned i = startIndex; i < index; ++i) {
+ const VariableEvent& event = at(i);
+ switch (event.kind()) {
+ case Reset:
+ // nothing to do.
+ break;
+ case BirthToFill:
+ case BirthToSpill:
+ case Fill:
+ case Spill:
+ case Death:
+ generationInfos[event.nodeIndex()].update(event);
+ break;
+ case MovHint:
+ if (operandSources.hasOperand(event.operand()))
+ operandSources.setOperand(event.operand(), ValueSource(event.nodeIndex()));
+ break;
+ case SetLocalEvent:
+ if (operandSources.hasOperand(event.operand()))
+ operandSources.setOperand(event.operand(), ValueSource::forDataFormat(event.dataFormat()));
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ }
+
+ // Step 3: Record the things that are live, so we can get to them more quickly.
+ Vector<unsigned, 16> indicesOfLiveThings;
+ for (unsigned i = 0; i < generationInfos.size(); ++i) {
+ if (generationInfos[i].format != DataFormatNone)
+ indicesOfLiveThings.append(i);
+ }
+
+ // Step 4: Compute value recoveries!
+ valueRecoveries = Operands<ValueRecovery>(codeBlock->numParameters(), numVariables);
+ for (unsigned i = 0; i < operandSources.size(); ++i) {
+ ValueSource& source = operandSources[i];
+ if (source.isTriviallyRecoverable()) {
+ valueRecoveries[i] = source.valueRecovery();
+ continue;
+ }
+
+ ASSERT(source.kind() == HaveNode);
+ MinifiedNode* node = graph.at(source.nodeIndex());
+ if (node) {
+ if (node->hasConstantNumber()) {
+ valueRecoveries[i] = ValueRecovery::constant(
+ codeBlock->constantRegister(
+ FirstConstantRegisterIndex + node->constantNumber()).get());
+ continue;
+ }
+ if (node->hasWeakConstant()) {
+ valueRecoveries[i] = ValueRecovery::constant(node->weakConstant());
+ continue;
+ }
+ if (node->op() == PhantomArguments) {
+ valueRecoveries[i] = ValueRecovery::argumentsThatWereNotCreated();
+ continue;
+ }
+ }
+
+ MinifiedGenerationInfo* info = &generationInfos[source.nodeIndex()];
+ if (info->format == DataFormatNone) {
+ // Try to see if there is an alternate node that would contain the value we want.
+ // There are four possibilities:
+ //
+ // Int32ToDouble: We can use this in place of the original node, but
+ // we'd rather not; so we use it only if it is the only remaining
+ // live version.
+ //
+ // ValueToInt32: If the only remaining live version of the value is
+ // ValueToInt32, then we can use it.
+ //
+ // UInt32ToNumber: If the only live version of the value is a UInt32ToNumber
+ // then the only remaining uses are ones that want a properly formed number
+ // rather than a UInt32 intermediate.
+ //
+ // DoubleAsInt32: Same as UInt32ToNumber.
+ //
+ // The reverse of the above: This node could be a UInt32ToNumber, but its
+ // alternative is still alive. This means that the only remaining uses of
+ // the number would be fine with a UInt32 intermediate.
+
+ bool found = false;
+
+ if (node && node->op() == UInt32ToNumber) {
+ NodeIndex nodeIndex = node->child1();
+ node = graph.at(nodeIndex);
+ info = &generationInfos[nodeIndex];
+ if (info->format != DataFormatNone)
+ found = true;
+ }
+
+ if (!found) {
+ NodeIndex int32ToDoubleIndex = NoNode;
+ NodeIndex valueToInt32Index = NoNode;
+ NodeIndex uint32ToNumberIndex = NoNode;
+ NodeIndex doubleAsInt32Index = NoNode;
+
+ for (unsigned i = 0; i < indicesOfLiveThings.size(); ++i) {
+ NodeIndex nodeIndex = indicesOfLiveThings[i];
+ node = graph.at(nodeIndex);
+ if (!node)
+ continue;
+ if (!node->hasChild1())
+ continue;
+ if (node->child1() != source.nodeIndex())
+ continue;
+ ASSERT(generationInfos[nodeIndex].format != DataFormatNone);
+ switch (node->op()) {
+ case Int32ToDouble:
+ int32ToDoubleIndex = nodeIndex;
+ break;
+ case ValueToInt32:
+ valueToInt32Index = nodeIndex;
+ break;
+ case UInt32ToNumber:
+ uint32ToNumberIndex = nodeIndex;
+ break;
+ case DoubleAsInt32:
+ doubleAsInt32Index = nodeIndex;
+ break;
+ default:
+ break;
+ }
+ }
+
+ NodeIndex nodeIndexToUse;
+ if (doubleAsInt32Index != NoNode)
+ nodeIndexToUse = doubleAsInt32Index;
+ else if (int32ToDoubleIndex != NoNode)
+ nodeIndexToUse = int32ToDoubleIndex;
+ else if (valueToInt32Index != NoNode)
+ nodeIndexToUse = valueToInt32Index;
+ else if (uint32ToNumberIndex != NoNode)
+ nodeIndexToUse = uint32ToNumberIndex;
+ else
+ nodeIndexToUse = NoNode;
+
+ if (nodeIndexToUse != NoNode) {
+ info = &generationInfos[nodeIndexToUse];
+ ASSERT(info->format != DataFormatNone);
+ found = true;
+ }
+ }
+
+ if (!found) {
+ valueRecoveries[i] = ValueRecovery::constant(jsUndefined());
+ continue;
+ }
+ }
+
+ ASSERT(info->format != DataFormatNone);
+
+ if (info->filled) {
+ if (info->format == DataFormatDouble) {
+ valueRecoveries[i] = ValueRecovery::inFPR(info->u.fpr);
+ continue;
+ }
+#if USE(JSVALUE32_64)
+ if (info->format & DataFormatJS) {
+ valueRecoveries[i] = ValueRecovery::inPair(info->u.pair.tagGPR, info->u.pair.payloadGPR);
+ continue;
+ }
+#endif
+ valueRecoveries[i] = ValueRecovery::inGPR(info->u.gpr, info->format);
+ continue;
+ }
+
+ valueRecoveries[i] =
+ ValueRecovery::displacedInRegisterFile(static_cast<VirtualRegister>(info->u.virtualReg), info->format);
+ }
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
diff --git a/Source/JavaScriptCore/dfg/DFGVariableEventStream.h b/Source/JavaScriptCore/dfg/DFGVariableEventStream.h
new file mode 100644
index 000000000..0d10eb048
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGVariableEventStream.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGVariableEventStream_h
+#define DFGVariableEventStream_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGCommon.h"
+#include "DFGMinifiedGraph.h"
+#include "DFGVariableEvent.h"
+#include "Operands.h"
+#include <wtf/Vector.h>
+
+namespace JSC { namespace DFG {
+
+class VariableEventStream : public Vector<VariableEvent> {
+public:
+ void appendAndLog(const VariableEvent& event)
+ {
+#if DFG_ENABLE(DEBUG_VERBOSE)
+ logEvent(event);
+#endif
+ append(event);
+ }
+
+ void reconstruct(
+ CodeBlock*, CodeOrigin, MinifiedGraph&,
+ unsigned index, Operands<ValueRecovery>&) const;
+
+private:
+ void logEvent(const VariableEvent&);
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGVariableEventStream_h
+
diff --git a/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp b/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp
index 2d7ce33c9..86b33835d 100644
--- a/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp
@@ -132,6 +132,7 @@ public:
bool performVirtualRegisterAllocation(Graph& graph)
{
+ SamplingRegion samplingRegion("DFG Virtual Register Allocation Phase");
return runPhase<VirtualRegisterAllocationPhase>(graph);
}