summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/dfg')
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractState.cpp253
-rw-r--r--Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp4
-rw-r--r--Source/JavaScriptCore/dfg/DFGArrayMode.cpp16
-rw-r--r--Source/JavaScriptCore/dfg/DFGArrayMode.h25
-rw-r--r--Source/JavaScriptCore/dfg/DFGByteCodeCache.h2
-rw-r--r--Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp64
-rw-r--r--Source/JavaScriptCore/dfg/DFGCCallHelpers.h23
-rw-r--r--Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp6
-rw-r--r--Source/JavaScriptCore/dfg/DFGCSEPhase.cpp64
-rw-r--r--Source/JavaScriptCore/dfg/DFGCSEPhase.h2
-rw-r--r--Source/JavaScriptCore/dfg/DFGCommon.h2
-rw-r--r--Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp11
-rw-r--r--Source/JavaScriptCore/dfg/DFGDriver.cpp9
-rw-r--r--Source/JavaScriptCore/dfg/DFGFPRInfo.h5
-rw-r--r--Source/JavaScriptCore/dfg/DFGFixupPhase.cpp116
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.cpp26
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.h33
-rw-r--r--Source/JavaScriptCore/dfg/DFGNode.h25
-rw-r--r--Source/JavaScriptCore/dfg/DFGNodeType.h3
-rw-r--r--Source/JavaScriptCore/dfg/DFGOperations.cpp92
-rw-r--r--Source/JavaScriptCore/dfg/DFGOperations.h2
-rw-r--r--Source/JavaScriptCore/dfg/DFGPhase.h7
-rw-r--r--Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp9
-rw-r--r--Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.cpp178
-rw-r--r--Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.h49
-rw-r--r--Source/JavaScriptCore/dfg/DFGRepatch.cpp8
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp363
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h41
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp382
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp369
-rw-r--r--Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp46
-rw-r--r--Source/JavaScriptCore/dfg/DFGThunks.cpp3
32 files changed, 1177 insertions, 1061 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index 43b5a03f3..5f79f666f 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -108,24 +108,6 @@ void AbstractState::initialize(Graph& graph)
root->valuesAtHead.argument(i).set(SpecInt32);
else if (isBooleanSpeculation(prediction))
root->valuesAtHead.argument(i).set(SpecBoolean);
- else if (isInt8ArraySpeculation(prediction))
- root->valuesAtHead.argument(i).set(SpecInt8Array);
- else if (isInt16ArraySpeculation(prediction))
- root->valuesAtHead.argument(i).set(SpecInt16Array);
- else if (isInt32ArraySpeculation(prediction))
- root->valuesAtHead.argument(i).set(SpecInt32Array);
- else if (isUint8ArraySpeculation(prediction))
- root->valuesAtHead.argument(i).set(SpecUint8Array);
- else if (isUint8ClampedArraySpeculation(prediction))
- root->valuesAtHead.argument(i).set(SpecUint8ClampedArray);
- else if (isUint16ArraySpeculation(prediction))
- root->valuesAtHead.argument(i).set(SpecUint16Array);
- else if (isUint32ArraySpeculation(prediction))
- root->valuesAtHead.argument(i).set(SpecUint32Array);
- else if (isFloat32ArraySpeculation(prediction))
- root->valuesAtHead.argument(i).set(SpecFloat32Array);
- else if (isFloat64ArraySpeculation(prediction))
- root->valuesAtHead.argument(i).set(SpecFloat64Array);
else if (isCellSpeculation(prediction))
root->valuesAtHead.argument(i).set(SpecCell);
else
@@ -626,14 +608,9 @@ bool AbstractState::execute(unsigned indexInBlock)
Node& child = m_graph[node.child1()];
if (isBooleanSpeculation(child.prediction()))
speculateBooleanUnary(node);
- else if (child.shouldSpeculateFinalObjectOrOther()) {
- node.setCanExit(
- !isFinalObjectOrOtherSpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecFinalObject | SpecOther);
- } else if (child.shouldSpeculateArrayOrOther()) {
- node.setCanExit(
- !isArrayOrOtherSpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecArray | SpecOther);
+ else if (child.shouldSpeculateNonStringCellOrOther()) {
+ node.setCanExit(true);
+ forNode(node.child1()).filter((SpecCell & ~SpecString) | SpecOther);
} else if (child.shouldSpeculateInteger())
speculateInt32Unary(node);
else if (child.shouldSpeculateNumber())
@@ -751,45 +728,32 @@ bool AbstractState::execute(unsigned indexInBlock)
break;
}
- if (Node::shouldSpeculateFinalObject(left, right)) {
- filter = SpecFinalObject;
- checker = isFinalObjectSpeculation;
- } else if (Node::shouldSpeculateArray(left, right)) {
- filter = SpecArray;
- checker = isArraySpeculation;
- } else if (left.shouldSpeculateFinalObject() && right.shouldSpeculateFinalObjectOrOther()) {
- node.setCanExit(
- !isFinalObjectSpeculation(forNode(node.child1()).m_type)
- || !isFinalObjectOrOtherSpeculation(forNode(node.child2()).m_type));
- forNode(node.child1()).filter(SpecFinalObject);
- forNode(node.child2()).filter(SpecFinalObject | SpecOther);
+ if (left.shouldSpeculateString() || right.shouldSpeculateString()) {
+ node.setCanExit(false);
break;
- } else if (right.shouldSpeculateFinalObject() && left.shouldSpeculateFinalObjectOrOther()) {
- node.setCanExit(
- !isFinalObjectOrOtherSpeculation(forNode(node.child1()).m_type)
- || !isFinalObjectSpeculation(forNode(node.child2()).m_type));
- forNode(node.child1()).filter(SpecFinalObject | SpecOther);
- forNode(node.child2()).filter(SpecFinalObject);
+ }
+ if (left.shouldSpeculateNonStringCell() && right.shouldSpeculateNonStringCellOrOther()) {
+ node.setCanExit(true);
+ forNode(node.child1()).filter(SpecCell & ~SpecString);
+ forNode(node.child2()).filter((SpecCell & ~SpecString) | SpecOther);
break;
- } else if (left.shouldSpeculateArray() && right.shouldSpeculateArrayOrOther()) {
- node.setCanExit(
- !isArraySpeculation(forNode(node.child1()).m_type)
- || !isArrayOrOtherSpeculation(forNode(node.child2()).m_type));
- forNode(node.child1()).filter(SpecArray);
- forNode(node.child2()).filter(SpecArray | SpecOther);
+ }
+ if (left.shouldSpeculateNonStringCellOrOther() && right.shouldSpeculateNonStringCell()) {
+ node.setCanExit(true);
+ forNode(node.child1()).filter((SpecCell & ~SpecString) | SpecOther);
+ forNode(node.child2()).filter(SpecCell & ~SpecString);
break;
- } else if (right.shouldSpeculateArray() && left.shouldSpeculateArrayOrOther()) {
- node.setCanExit(
- !isArrayOrOtherSpeculation(forNode(node.child1()).m_type)
- || !isArraySpeculation(forNode(node.child2()).m_type));
- forNode(node.child1()).filter(SpecArray | SpecOther);
- forNode(node.child2()).filter(SpecArray);
+ }
+ if (left.shouldSpeculateNonStringCell() && right.shouldSpeculateNonStringCell()) {
+ node.setCanExit(true);
+ forNode(node.child1()).filter(SpecCell & ~SpecString);
+ forNode(node.child2()).filter(SpecCell & ~SpecString);
break;
- } else {
- filter = SpecTop;
- checker = isAnySpeculation;
- clobberWorld(node.codeOrigin, indexInBlock);
}
+
+ filter = SpecTop;
+ checker = isAnySpeculation;
+ clobberWorld(node.codeOrigin, indexInBlock);
} else {
filter = SpecTop;
checker = isAnySpeculation;
@@ -837,22 +801,16 @@ bool AbstractState::execute(unsigned indexInBlock)
speculateNumberBinary(node);
break;
}
- if (Node::shouldSpeculateFinalObject(
- m_graph[node.child1()], m_graph[node.child2()])) {
- node.setCanExit(
- !isFinalObjectSpeculation(forNode(node.child1()).m_type)
- || !isFinalObjectSpeculation(forNode(node.child2()).m_type));
- forNode(node.child1()).filter(SpecFinalObject);
- forNode(node.child2()).filter(SpecFinalObject);
+ Node& leftNode = m_graph[node.child1()];
+ Node& rightNode = m_graph[node.child2()];
+ if (leftNode.shouldSpeculateString() || rightNode.shouldSpeculateString()) {
+ node.setCanExit(false);
break;
}
- if (Node::shouldSpeculateArray(
- m_graph[node.child1()], m_graph[node.child2()])) {
- node.setCanExit(
- !isArraySpeculation(forNode(node.child1()).m_type)
- || !isArraySpeculation(forNode(node.child2()).m_type));
- forNode(node.child1()).filter(SpecArray);
- forNode(node.child2()).filter(SpecArray);
+ if (leftNode.shouldSpeculateNonStringCell() && rightNode.shouldSpeculateNonStringCell()) {
+ node.setCanExit(true);
+ forNode(node.child1()).filter((SpecCell & ~SpecString) | SpecOther);
+ forNode(node.child2()).filter((SpecCell & ~SpecString) | SpecOther);
break;
}
node.setCanExit(false);
@@ -887,55 +845,47 @@ bool AbstractState::execute(unsigned indexInBlock)
forNode(nodeIndex).makeTop();
break;
case Array::String:
- forNode(node.child1()).filter(SpecString);
forNode(node.child2()).filter(SpecInt32);
forNode(nodeIndex).set(SpecString);
break;
case Array::Arguments:
- forNode(node.child1()).filter(SpecArguments);
forNode(node.child2()).filter(SpecInt32);
forNode(nodeIndex).makeTop();
break;
case Array::JSArray:
+ forNode(node.child2()).filter(SpecInt32);
+ forNode(nodeIndex).makeTop();
+ break;
case Array::JSArrayOutOfBounds:
- // FIXME: We should have more conservative handling of the out-of-bounds
- // case.
- forNode(node.child1()).filter(SpecCell);
forNode(node.child2()).filter(SpecInt32);
+ clobberWorld(node.codeOrigin, indexInBlock);
forNode(nodeIndex).makeTop();
break;
case Array::Int8Array:
- forNode(node.child1()).filter(SpecInt8Array);
forNode(node.child2()).filter(SpecInt32);
forNode(nodeIndex).set(SpecInt32);
break;
case Array::Int16Array:
- forNode(node.child1()).filter(SpecInt16Array);
forNode(node.child2()).filter(SpecInt32);
forNode(nodeIndex).set(SpecInt32);
break;
case Array::Int32Array:
- forNode(node.child1()).filter(SpecInt32Array);
forNode(node.child2()).filter(SpecInt32);
forNode(nodeIndex).set(SpecInt32);
break;
case Array::Uint8Array:
- forNode(node.child1()).filter(SpecUint8Array);
forNode(node.child2()).filter(SpecInt32);
forNode(nodeIndex).set(SpecInt32);
break;
case Array::Uint8ClampedArray:
- forNode(node.child1()).filter(SpecUint8ClampedArray);
forNode(node.child2()).filter(SpecInt32);
forNode(nodeIndex).set(SpecInt32);
break;
case Array::Uint16Array:
- forNode(node.child1()).filter(SpecUint16Array);
forNode(node.child2()).filter(SpecInt32);
forNode(nodeIndex).set(SpecInt32);
break;
case Array::Uint32Array:
- forNode(node.child1()).filter(SpecUint32Array);
forNode(node.child2()).filter(SpecInt32);
if (node.shouldSpeculateInteger())
forNode(nodeIndex).set(SpecInt32);
@@ -943,12 +893,10 @@ bool AbstractState::execute(unsigned indexInBlock)
forNode(nodeIndex).set(SpecDouble);
break;
case Array::Float32Array:
- forNode(node.child1()).filter(SpecFloat32Array);
forNode(node.child2()).filter(SpecInt32);
forNode(nodeIndex).set(SpecDouble);
break;
case Array::Float64Array:
- forNode(node.child1()).filter(SpecFloat64Array);
forNode(node.child2()).filter(SpecInt32);
forNode(nodeIndex).set(SpecDouble);
break;
@@ -959,7 +907,6 @@ bool AbstractState::execute(unsigned indexInBlock)
case PutByVal:
case PutByValAlias: {
node.setCanExit(true);
- Edge child1 = m_graph.varArgChild(node, 0);
Edge child2 = m_graph.varArgChild(node, 1);
Edge child3 = m_graph.varArgChild(node, 2);
switch (modeForPut(node.arrayMode())) {
@@ -970,20 +917,16 @@ bool AbstractState::execute(unsigned indexInBlock)
clobberWorld(node.codeOrigin, indexInBlock);
break;
case Array::JSArray:
- forNode(child1).filter(SpecCell);
forNode(child2).filter(SpecInt32);
break;
case Array::JSArrayOutOfBounds:
- forNode(child1).filter(SpecCell);
forNode(child2).filter(SpecInt32);
clobberWorld(node.codeOrigin, indexInBlock);
break;
case Array::Arguments:
- forNode(child1).filter(SpecArguments);
forNode(child2).filter(SpecInt32);
break;
case Array::Int8Array:
- forNode(child1).filter(SpecInt8Array);
forNode(child2).filter(SpecInt32);
if (m_graph[child3].shouldSpeculateInteger())
forNode(child3).filter(SpecInt32);
@@ -991,7 +934,6 @@ bool AbstractState::execute(unsigned indexInBlock)
forNode(child3).filter(SpecNumber);
break;
case Array::Int16Array:
- forNode(child1).filter(SpecInt16Array);
forNode(child2).filter(SpecInt32);
if (m_graph[child3].shouldSpeculateInteger())
forNode(child3).filter(SpecInt32);
@@ -999,7 +941,6 @@ bool AbstractState::execute(unsigned indexInBlock)
forNode(child3).filter(SpecNumber);
break;
case Array::Int32Array:
- forNode(child1).filter(SpecInt32Array);
forNode(child2).filter(SpecInt32);
if (m_graph[child3].shouldSpeculateInteger())
forNode(child3).filter(SpecInt32);
@@ -1007,7 +948,6 @@ bool AbstractState::execute(unsigned indexInBlock)
forNode(child3).filter(SpecNumber);
break;
case Array::Uint8Array:
- forNode(child1).filter(SpecUint8Array);
forNode(child2).filter(SpecInt32);
if (m_graph[child3].shouldSpeculateInteger())
forNode(child3).filter(SpecInt32);
@@ -1015,7 +955,6 @@ bool AbstractState::execute(unsigned indexInBlock)
forNode(child3).filter(SpecNumber);
break;
case Array::Uint8ClampedArray:
- forNode(child1).filter(SpecUint8ClampedArray);
forNode(child2).filter(SpecInt32);
if (m_graph[child3].shouldSpeculateInteger())
forNode(child3).filter(SpecInt32);
@@ -1023,7 +962,6 @@ bool AbstractState::execute(unsigned indexInBlock)
forNode(child3).filter(SpecNumber);
break;
case Array::Uint16Array:
- forNode(child1).filter(SpecUint16Array);
forNode(child2).filter(SpecInt32);
if (m_graph[child3].shouldSpeculateInteger())
forNode(child3).filter(SpecInt32);
@@ -1031,7 +969,6 @@ bool AbstractState::execute(unsigned indexInBlock)
forNode(child3).filter(SpecNumber);
break;
case Array::Uint32Array:
- forNode(child1).filter(SpecUint32Array);
forNode(child2).filter(SpecInt32);
if (m_graph[child3].shouldSpeculateInteger())
forNode(child3).filter(SpecInt32);
@@ -1039,12 +976,10 @@ bool AbstractState::execute(unsigned indexInBlock)
forNode(child3).filter(SpecNumber);
break;
case Array::Float32Array:
- forNode(child1).filter(SpecFloat32Array);
forNode(child2).filter(SpecInt32);
forNode(child3).filter(SpecNumber);
break;
case Array::Float64Array:
- forNode(child1).filter(SpecFloat64Array);
forNode(child2).filter(SpecInt32);
forNode(child3).filter(SpecNumber);
break;
@@ -1057,13 +992,11 @@ bool AbstractState::execute(unsigned indexInBlock)
case ArrayPush:
node.setCanExit(true);
- forNode(node.child1()).filter(SpecCell);
forNode(nodeIndex).set(SpecNumber);
break;
case ArrayPop:
node.setCanExit(true);
- forNode(node.child1()).filter(SpecCell);
forNode(nodeIndex).makeTop();
break;
@@ -1102,14 +1035,9 @@ bool AbstractState::execute(unsigned indexInBlock)
Node& child = m_graph[node.child1()];
if (child.shouldSpeculateBoolean())
speculateBooleanUnary(node);
- else if (child.shouldSpeculateFinalObjectOrOther()) {
- node.setCanExit(
- !isFinalObjectOrOtherSpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecFinalObject | SpecOther);
- } else if (child.shouldSpeculateArrayOrOther()) {
- node.setCanExit(
- !isArrayOrOtherSpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecArray | SpecOther);
+ else if (child.shouldSpeculateNonStringCellOrOther()) {
+ node.setCanExit(true);
+ forNode(node.child1()).filter((SpecCell & ~SpecString) | SpecOther);
} else if (child.shouldSpeculateInteger())
speculateInt32Unary(node);
else if (child.shouldSpeculateNumber())
@@ -1235,7 +1163,7 @@ bool AbstractState::execute(unsigned indexInBlock)
case CreateActivation:
node.setCanExit(false);
- forNode(nodeIndex).set(m_graph.m_globalData.activationStructure.get());
+ forNode(nodeIndex).set(m_codeBlock->globalObjectFor(node.codeOrigin)->activationStructure());
m_haveStructures = true;
break;
@@ -1347,80 +1275,8 @@ bool AbstractState::execute(unsigned indexInBlock)
break;
case GetArrayLength:
- switch (node.arrayMode()) {
- case Array::Undecided:
- ASSERT_NOT_REACHED();
- break;
- case Array::ForceExit:
- m_isValid = false;
- break;
- case Array::Generic:
- ASSERT_NOT_REACHED();
- break;
- case Array::String:
- node.setCanExit(!isStringSpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecString);
- forNode(nodeIndex).set(SpecInt32);
- break;
- case Array::JSArray:
- node.setCanExit(true);
- forNode(node.child1()).filter(SpecCell);
- forNode(nodeIndex).set(SpecInt32);
- break;
- case Array::JSArrayOutOfBounds:
- ASSERT_NOT_REACHED();
- break;
- case Array::Arguments:
- node.setCanExit(true);
- forNode(node.child1()).filter(SpecArguments);
- forNode(nodeIndex).set(SpecInt32);
- break;
- case Array::Int8Array:
- node.setCanExit(!isInt8ArraySpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecInt8Array);
- forNode(nodeIndex).set(SpecInt32);
- break;
- case Array::Int16Array:
- node.setCanExit(!isInt16ArraySpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecInt16Array);
- forNode(nodeIndex).set(SpecInt32);
- break;
- case Array::Int32Array:
- node.setCanExit(!isInt32ArraySpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecInt32Array);
- forNode(nodeIndex).set(SpecInt32);
- break;
- case Array::Uint8Array:
- node.setCanExit(!isUint8ArraySpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecUint8Array);
- forNode(nodeIndex).set(SpecInt32);
- break;
- case Array::Uint8ClampedArray:
- node.setCanExit(!isUint8ClampedArraySpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecUint8ClampedArray);
- forNode(nodeIndex).set(SpecInt32);
- break;
- case Array::Uint16Array:
- node.setCanExit(!isUint16ArraySpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecUint16Array);
- forNode(nodeIndex).set(SpecInt32);
- break;
- case Array::Uint32Array:
- node.setCanExit(!isUint32ArraySpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecUint32Array);
- forNode(nodeIndex).set(SpecInt32);
- break;
- case Array::Float32Array:
- node.setCanExit(!isFloat32ArraySpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecFloat32Array);
- forNode(nodeIndex).set(SpecInt32);
- break;
- case Array::Float64Array:
- node.setCanExit(!isFloat64ArraySpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecFloat64Array);
- forNode(nodeIndex).set(SpecInt32);
- break;
- }
+ node.setCanExit(true); // Lies, but it's true for the common case of JSArray, so it's good enough.
+ forNode(nodeIndex).set(SpecInt32);
break;
case CheckStructure:
@@ -1492,8 +1348,13 @@ bool AbstractState::execute(unsigned indexInBlock)
forNode(node.child1()).filter(SpecCell);
forNode(nodeIndex).clear(); // The result is not a JS value.
break;
- case GetIndexedPropertyStorage: {
- node.setCanExit(true); // Lies, but this is (almost) always followed by GetByVal, which does exit. So no point in trying to be more precise.
+ case CheckArray: {
+ if (modeAlreadyChecked(forNode(node.child1()), node.arrayMode())) {
+ m_foundConstants = true;
+ node.setCanExit(false);
+ break;
+ }
+ node.setCanExit(true); // Lies, but this is followed by operations (like GetByVal) that always exit, so there is no point in us trying to be clever here.
switch (node.arrayMode()) {
case Array::String:
forNode(node.child1()).filter(SpecString);
@@ -1504,6 +1365,9 @@ bool AbstractState::execute(unsigned indexInBlock)
// CFA tracking of array mode speculations, but we don't have that, yet.
forNode(node.child1()).filter(SpecCell);
break;
+ case Array::Arguments:
+ forNode(node.child1()).filter(SpecArguments);
+ break;
case Array::Int8Array:
forNode(node.child1()).filter(SpecInt8Array);
break;
@@ -1535,6 +1399,19 @@ bool AbstractState::execute(unsigned indexInBlock)
ASSERT_NOT_REACHED();
break;
}
+ break;
+ }
+ case GetIndexedPropertyStorage: {
+ switch (node.arrayMode()) {
+ case Array::String:
+ // Strings are weird - we may spec fail if the string was a rope. That is of course
+ // stupid, and we should fix that, but for now let's at least be honest about it.
+ node.setCanExit(true);
+ break;
+ default:
+ node.setCanExit(false);
+ break;
+ }
forNode(nodeIndex).clear();
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
index 2f535ba22..640a0a966 100644
--- a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
@@ -312,6 +312,7 @@ public:
case ForwardCheckStructure:
case StructureTransitionWatchpoint:
case ForwardStructureTransitionWatchpoint:
+ case CheckArray:
// We don't care about these because if we get uses of the relevant
// variable then we can safely get rid of these, too. This of course
// relies on there not being any information transferred by the CFA
@@ -476,7 +477,8 @@ public:
case CheckStructure:
case ForwardCheckStructure:
case StructureTransitionWatchpoint:
- case ForwardStructureTransitionWatchpoint: {
+ case ForwardStructureTransitionWatchpoint:
+ case CheckArray: {
// We can just get rid of this node, if it references a phantom argument.
if (!isOKToOptimize(m_graph[node.child1()]))
break;
diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
index ec4edc2e8..cd3944fb4 100644
--- a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
+++ b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
@@ -51,6 +51,11 @@ Array::Mode fromObserved(ArrayModes modes, bool makeSafe)
}
}
+Array::Mode fromStructure(Structure* structure, bool makeSafe)
+{
+ return fromObserved(arrayModeFromStructure(structure), makeSafe);
+}
+
Array::Mode refineArrayMode(Array::Mode arrayMode, SpeculatedType base, SpeculatedType index)
{
if (!base || !index) {
@@ -64,17 +69,8 @@ Array::Mode refineArrayMode(Array::Mode arrayMode, SpeculatedType base, Speculat
if (!isInt32Speculation(index) || !isCellSpeculation(base))
return Array::Generic;
- // Pass through any array modes that would have been decided by the array profile, since
- // the predictions of the inputs will not tell us anything useful that we didn't already
- // get from the array profile.
- switch (arrayMode) {
- case Array::ForceExit:
- case Array::JSArray:
- case Array::JSArrayOutOfBounds:
+ if (arrayMode != Array::Undecided)
return arrayMode;
- default:
- break;
- }
if (isStringSpeculation(base))
return Array::String;
diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.h b/Source/JavaScriptCore/dfg/DFGArrayMode.h
index 6ce62ae72..36a8637f5 100644
--- a/Source/JavaScriptCore/dfg/DFGArrayMode.h
+++ b/Source/JavaScriptCore/dfg/DFGArrayMode.h
@@ -63,12 +63,25 @@ enum Mode {
Array::Mode fromObserved(ArrayModes modes, bool makeSafe);
+Array::Mode fromStructure(Structure*, bool makeSafe);
+
Array::Mode refineArrayMode(Array::Mode, SpeculatedType base, SpeculatedType index);
bool modeAlreadyChecked(AbstractValue&, Array::Mode);
const char* modeToString(Array::Mode);
+inline bool modeIsJSArray(Array::Mode arrayMode)
+{
+ switch (arrayMode) {
+ case Array::JSArray:
+ case Array::JSArrayOutOfBounds:
+ return true;
+ default:
+ return false;
+ }
+}
+
inline bool canCSEStorage(Array::Mode arrayMode)
{
switch (arrayMode) {
@@ -82,6 +95,11 @@ inline bool canCSEStorage(Array::Mode arrayMode)
}
}
+inline bool lengthNeedsStorage(Array::Mode arrayMode)
+{
+ return modeIsJSArray(arrayMode);
+}
+
inline Array::Mode modeForPut(Array::Mode arrayMode)
{
switch (arrayMode) {
@@ -115,7 +133,7 @@ inline bool modesCompatibleForStorageLoad(Array::Mode left, Array::Mode right)
return false;
}
-inline bool modeSupportsLength(Array::Mode mode)
+inline bool modeIsSpecific(Array::Mode mode)
{
switch (mode) {
case Array::Undecided:
@@ -127,6 +145,11 @@ inline bool modeSupportsLength(Array::Mode mode)
}
}
+inline bool modeSupportsLength(Array::Mode mode)
+{
+ return modeIsSpecific(mode);
+}
+
} } // namespace JSC::DFG
#endif // ENABLE(DFG_JIT)
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeCache.h b/Source/JavaScriptCore/dfg/DFGByteCodeCache.h
index f6a745c66..ab88e99e5 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeCache.h
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeCache.h
@@ -141,7 +141,7 @@ public:
}
}
- CodeBlock* get(const CodeBlockKey& key, ScopeChainNode* scope)
+ CodeBlock* get(const CodeBlockKey& key, JSScope* scope)
{
Map::iterator iter = m_map.find(key);
if (iter != m_map.end())
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index f9b1db9ab..b96b8d9a3 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -71,6 +71,7 @@ public:
, m_inlineStackTop(0)
, m_haveBuiltOperandMaps(false)
, m_emptyJSValueIndex(UINT_MAX)
+ , m_currentInstruction(0)
{
ASSERT(m_profiledBlock);
@@ -141,6 +142,9 @@ private:
return getJSConstant(constant);
}
+ if (operand == RegisterFile::Callee)
+ return getCallee();
+
// Is this an argument?
if (operandIsArgument(operand))
return getArgument(operand);
@@ -364,11 +368,11 @@ private:
InlineCallFrame* inlineCallFrame = stack->m_inlineCallFrame;
if (!inlineCallFrame)
break;
- if (operand >= inlineCallFrame->stackOffset - RegisterFile::CallFrameHeaderSize)
+ if (operand >= static_cast<int>(inlineCallFrame->stackOffset - RegisterFile::CallFrameHeaderSize))
continue;
if (operand == inlineCallFrame->stackOffset + CallFrame::thisArgumentOffset())
continue;
- if (static_cast<unsigned>(operand) < inlineCallFrame->stackOffset - RegisterFile::CallFrameHeaderSize - inlineCallFrame->arguments.size())
+ if (operand < static_cast<int>(inlineCallFrame->stackOffset - RegisterFile::CallFrameHeaderSize - inlineCallFrame->arguments.size()))
continue;
int argument = operandToArgument(operand - inlineCallFrame->stackOffset);
return stack->m_argumentPositions[argument];
@@ -520,6 +524,11 @@ private:
return resultIndex;
}
+ NodeIndex getCallee()
+ {
+ return addToGraph(GetCallee);
+ }
+
// Helper functions to get/set the this value.
NodeIndex getThis()
{
@@ -818,9 +827,14 @@ private:
return getPrediction(m_graph.size(), m_currentProfilingIndex);
}
- Array::Mode getArrayModeWithoutOSRExit(Instruction* currentInstruction, NodeIndex base)
+ Array::Mode getArrayMode(ArrayProfile* profile)
+ {
+ profile->computeUpdatedPrediction();
+ return fromObserved(profile->observedArrayModes(), false);
+ }
+
+ Array::Mode getArrayModeAndEmitChecks(ArrayProfile* profile, NodeIndex base)
{
- ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
profile->computeUpdatedPrediction();
if (profile->hasDefiniteStructure())
addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(profile->expectedStructure())), base);
@@ -838,16 +852,6 @@ private:
return fromObserved(profile->observedArrayModes(), makeSafe);
}
- Array::Mode getArrayMode(Instruction* currentInstruction, NodeIndex base)
- {
- Array::Mode result = getArrayModeWithoutOSRExit(currentInstruction, base);
-
- if (result == Array::ForceExit)
- addToGraph(ForceOSRExit);
-
- return result;
- }
-
NodeIndex makeSafe(NodeIndex nodeIndex)
{
Node& node = m_graph[nodeIndex];
@@ -1130,7 +1134,10 @@ private:
ASSERT(result >= FirstConstantRegisterIndex);
return result;
}
-
+
+ if (operand == RegisterFile::Callee)
+ return m_calleeVR;
+
return operand + m_inlineCallFrame->stackOffset;
}
};
@@ -1150,6 +1157,8 @@ private:
// Cache of code blocks that we've generated bytecode for.
ByteCodeCache<canInlineFunctionFor> m_codeBlockCache;
+
+ Instruction* m_currentInstruction;
};
#define NEXT_OPCODE(name) \
@@ -1553,7 +1562,10 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins
if (argumentCountIncludingThis != 2)
return false;
- NodeIndex arrayPush = addToGraph(ArrayPush, OpInfo(0), OpInfo(prediction), get(registerOffset + argumentToOperand(0)), get(registerOffset + argumentToOperand(1)));
+ Array::Mode arrayMode = getArrayMode(m_currentInstruction[5].u.arrayProfile);
+ if (!modeIsJSArray(arrayMode))
+ return false;
+ NodeIndex arrayPush = addToGraph(ArrayPush, OpInfo(arrayMode), OpInfo(prediction), get(registerOffset + argumentToOperand(0)), get(registerOffset + argumentToOperand(1)));
if (usesResult)
set(resultOperand, arrayPush);
@@ -1564,7 +1576,10 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins
if (argumentCountIncludingThis != 1)
return false;
- NodeIndex arrayPop = addToGraph(ArrayPop, OpInfo(0), OpInfo(prediction), get(registerOffset + argumentToOperand(0)));
+ Array::Mode arrayMode = getArrayMode(m_currentInstruction[5].u.arrayProfile);
+ if (!modeIsJSArray(arrayMode))
+ return false;
+ NodeIndex arrayPop = addToGraph(ArrayPop, OpInfo(arrayMode), OpInfo(prediction), get(registerOffset + argumentToOperand(0)));
if (usesResult)
set(resultOperand, arrayPop);
return true;
@@ -1792,6 +1807,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
// Switch on the current bytecode opcode.
Instruction* currentInstruction = instructionsBegin + m_currentIndex;
+ m_currentInstruction = currentInstruction; // Some methods want to use this, and we'd rather not thread it through calls.
OpcodeID opcodeID = interpreter->getOpcodeID(currentInstruction->u.opcode);
switch (opcodeID) {
@@ -1830,10 +1846,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
}
case op_create_this: {
- if (m_inlineStackTop->m_inlineCallFrame)
- set(currentInstruction[1].u.operand, addToGraph(CreateThis, getDirect(m_inlineStackTop->m_calleeVR)));
- else
- set(currentInstruction[1].u.operand, addToGraph(CreateThis, addToGraph(GetCallee)));
+ set(currentInstruction[1].u.operand, addToGraph(CreateThis, get(RegisterFile::Callee)));
NEXT_OPCODE(op_create_this);
}
@@ -2177,7 +2190,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
SpeculatedType prediction = getPrediction();
NodeIndex base = get(currentInstruction[2].u.operand);
- Array::Mode arrayMode = getArrayMode(currentInstruction, base);
+ Array::Mode arrayMode = getArrayModeAndEmitChecks(currentInstruction[4].u.arrayProfile, base);
NodeIndex property = get(currentInstruction[3].u.operand);
NodeIndex getByVal = addToGraph(GetByVal, OpInfo(arrayMode), OpInfo(prediction), base, property);
set(currentInstruction[1].u.operand, getByVal);
@@ -2188,7 +2201,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
case op_put_by_val: {
NodeIndex base = get(currentInstruction[1].u.operand);
- Array::Mode arrayMode = getArrayMode(currentInstruction, base);
+ Array::Mode arrayMode = getArrayModeAndEmitChecks(currentInstruction[4].u.arrayProfile, base);
NodeIndex property = get(currentInstruction[2].u.operand);
NodeIndex value = get(currentInstruction[3].u.operand);
@@ -2196,6 +2209,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
addVarArgChild(base);
addVarArgChild(property);
addVarArgChild(value);
+ addVarArgChild(NoNode); // Leave room for property storage.
addToGraph(Node::VarArg, PutByVal, OpInfo(arrayMode), OpInfo(0));
NEXT_OPCODE(op_put_by_val);
@@ -2406,7 +2420,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand];
Identifier identifier = m_codeBlock->identifier(identifierNumber);
- SymbolTableEntry entry = globalObject->symbolTable().get(identifier.impl());
+ SymbolTableEntry entry = globalObject->symbolTable()->get(identifier.impl());
if (!entry.couldBeWatched()) {
NodeIndex getGlobalVar = addToGraph(
GetGlobalVar,
@@ -2459,7 +2473,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
JSGlobalObject* globalObject = codeBlock->globalObject();
unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[4].u.operand];
Identifier identifier = m_codeBlock->identifier(identifierNumber);
- SymbolTableEntry entry = globalObject->symbolTable().get(identifier.impl());
+ SymbolTableEntry entry = globalObject->symbolTable()->get(identifier.impl());
if (!entry.couldBeWatched()) {
addToGraph(
PutGlobalVar,
diff --git a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
index fd4e1cae0..5cd0baab2 100644
--- a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
+++ b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
@@ -456,6 +456,28 @@ public:
setupTwoStubArgs<FPRInfo::argumentFPR0, FPRInfo::argumentFPR1>(arg1, arg2);
}
#elif CPU(ARM)
+#if CPU(ARM_HARDFP)
+ ALWAYS_INLINE void setupArguments(FPRReg arg1)
+ {
+ moveDouble(arg1, FPRInfo::argumentFPR0);
+ }
+
+ ALWAYS_INLINE void setupArguments(FPRReg arg1, FPRReg arg2)
+ {
+ if (arg2 != FPRInfo::argumentFPR0) {
+ moveDouble(arg1, FPRInfo::argumentFPR0);
+ moveDouble(arg2, FPRInfo::argumentFPR1);
+ } else if (arg1 != FPRInfo::argumentFPR1) {
+ moveDouble(arg2, FPRInfo::argumentFPR1);
+ moveDouble(arg1, FPRInfo::argumentFPR0);
+ } else {
+ // Swap arg1, arg2.
+ moveDouble(FPRInfo::argumentFPR0, ARMRegisters::d2);
+ moveDouble(FPRInfo::argumentFPR1, FPRInfo::argumentFPR0);
+ moveDouble(ARMRegisters::d2, FPRInfo::argumentFPR1);
+ }
+ }
+#else
ALWAYS_INLINE void setupArguments(FPRReg arg1)
{
assembler().vmov(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, arg1);
@@ -466,6 +488,7 @@ public:
assembler().vmov(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, arg1);
assembler().vmov(GPRInfo::argumentGPR2, GPRInfo::argumentGPR3, arg2);
}
+#endif // CPU(ARM_HARDFP)
#else
#error "DFG JIT not supported on this platform."
#endif
diff --git a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
index aecce83ed..e0d973992 100644
--- a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
@@ -659,8 +659,10 @@ private:
if (node.flags() & NodeHasVarArgs) {
for (unsigned childIdx = node.firstChild();
childIdx < node.firstChild() + node.numChildren();
- ++childIdx)
- fixPossibleGetLocal(firstBlock, m_graph.m_varArgChildren[childIdx], changeRef);
+ ++childIdx) {
+ if (!!m_graph.m_varArgChildren[childIdx])
+ fixPossibleGetLocal(firstBlock, m_graph.m_varArgChildren[childIdx], changeRef);
+ }
} else if (!!node.child1()) {
fixPossibleGetLocal(firstBlock, node.children.child1(), changeRef);
if (!!node.child2()) {
diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
index dce57d520..b3681975d 100644
--- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
@@ -35,9 +35,8 @@ namespace JSC { namespace DFG {
class CSEPhase : public Phase {
public:
- CSEPhase(Graph& graph, OptimizationFixpointState fixpointState)
+ CSEPhase(Graph& graph)
: Phase(graph, "common subexpression elimination")
- , m_fixpointState(fixpointState)
{
// Replacements are used to implement local common subexpression elimination.
m_replacements.resize(m_graph.size());
@@ -327,7 +326,7 @@ private:
return false;
}
- bool checkStructureLoadElimination(const StructureSet& structureSet, NodeIndex child1)
+ bool checkStructureElimination(const StructureSet& structureSet, NodeIndex child1)
{
for (unsigned i = m_indexInBlock; i--;) {
NodeIndex index = m_currentBlock->at(i);
@@ -624,8 +623,37 @@ private:
}
return NoNode;
}
+
+ bool checkArrayElimination(NodeIndex child1, Array::Mode arrayMode)
+ {
+ for (unsigned i = m_indexInBlock; i--;) {
+ NodeIndex index = m_currentBlock->at(i);
+ if (index == child1)
+ break;
- NodeIndex getIndexedPropertyStorageLoadElimination(NodeIndex child1, bool hasIntegerIndexPrediction)
+ Node& node = m_graph[index];
+ switch (node.op()) {
+ case PutByOffset:
+ case PutStructure:
+ // Changing the structure or putting to the storage cannot
+ // change the property storage pointer.
+ break;
+
+ case CheckArray:
+ if (node.child1() == child1 && node.arrayMode() == arrayMode)
+ return true;
+ break;
+
+ default:
+ if (m_graph.clobbersWorld(index))
+ return false;
+ break;
+ }
+ }
+ return false;
+ }
+
+ NodeIndex getIndexedPropertyStorageLoadElimination(NodeIndex child1, Array::Mode arrayMode)
{
for (unsigned i = m_indexInBlock; i--;) {
NodeIndex index = m_currentBlock->at(i);
@@ -635,9 +663,7 @@ private:
Node& node = m_graph[index];
switch (node.op()) {
case GetIndexedPropertyStorage: {
- SpeculatedType basePrediction = m_graph[node.child2()].prediction();
- bool nodeHasIntegerIndexPrediction = !(!(basePrediction & SpecInt32) && basePrediction);
- if (node.child1() == child1 && hasIntegerIndexPrediction == nodeHasIntegerIndexPrediction)
+ if (node.child1() == child1 && node.arrayMode() == arrayMode)
return index;
break;
}
@@ -988,7 +1014,7 @@ private:
ASSERT(replacement.variableAccessData() == variableAccessData);
// FIXME: We should be able to remove SetLocals that can exit; we just need
// to replace them with appropriate type checks.
- if (m_fixpointState == FixpointNotConverged) {
+ if (m_graph.m_fixpointState == FixpointNotConverged) {
// Need to be conservative at this time; if the SetLocal has any chance of performing
// any speculations then we cannot do anything.
if (variableAccessData->isCaptured()) {
@@ -1077,7 +1103,7 @@ private:
case PutGlobalVar:
case PutGlobalVarCheck:
- if (m_fixpointState == FixpointNotConverged)
+ if (m_graph.m_fixpointState == FixpointNotConverged)
break;
eliminate(globalVarStoreElimination(node.registerPointer()));
break;
@@ -1103,7 +1129,7 @@ private:
case CheckStructure:
case ForwardCheckStructure:
- if (checkStructureLoadElimination(node.structureSet(), node.child1().index()))
+ if (checkStructureElimination(node.structureSet(), node.child1().index()))
eliminate();
break;
@@ -1114,7 +1140,7 @@ private:
break;
case PutStructure:
- if (m_fixpointState == FixpointNotConverged)
+ if (m_graph.m_fixpointState == FixpointNotConverged)
break;
eliminate(putStructureStoreElimination(node.child1().index()), PhantomPutStructure);
break;
@@ -1124,10 +1150,13 @@ private:
eliminate();
break;
+ case CheckArray:
+ if (checkArrayElimination(node.child1().index(), node.arrayMode()))
+ eliminate();
+ break;
+
case GetIndexedPropertyStorage: {
- SpeculatedType basePrediction = m_graph[node.child2()].prediction();
- bool nodeHasIntegerIndexPrediction = !(!(basePrediction & SpecInt32) && basePrediction);
- setReplacement(getIndexedPropertyStorageLoadElimination(node.child1().index(), nodeHasIntegerIndexPrediction));
+ setReplacement(getIndexedPropertyStorageLoadElimination(node.child1().index(), node.arrayMode()));
break;
}
@@ -1140,7 +1169,7 @@ private:
break;
case PutByOffset:
- if (m_fixpointState == FixpointNotConverged)
+ if (m_graph.m_fixpointState == FixpointNotConverged)
break;
eliminate(putByOffsetStoreElimination(m_graph.m_storageAccessData[node.storageAccessDataIndex()].identifierNumber, node.child1().index()));
break;
@@ -1178,14 +1207,13 @@ private:
unsigned m_indexInBlock;
Vector<NodeIndex, 16> m_replacements;
FixedArray<unsigned, LastNodeType> m_lastSeen;
- OptimizationFixpointState m_fixpointState;
bool m_changed; // Only tracks changes that have a substantive effect on other optimizations.
};
-bool performCSE(Graph& graph, OptimizationFixpointState fixpointState)
+bool performCSE(Graph& graph)
{
SamplingRegion samplingRegion("DFG CSE Phase");
- return runPhase<CSEPhase>(graph, fixpointState);
+ return runPhase<CSEPhase>(graph);
}
} } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.h b/Source/JavaScriptCore/dfg/DFGCSEPhase.h
index 7e33c2243..017bf5a4b 100644
--- a/Source/JavaScriptCore/dfg/DFGCSEPhase.h
+++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.h
@@ -41,7 +41,7 @@ class Graph;
// a wide range of subexpression similarities. It's known to produce big wins
// on a few benchmarks, and is relatively cheap to run.
-bool performCSE(Graph&, OptimizationFixpointState);
+bool performCSE(Graph&);
} } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGCommon.h b/Source/JavaScriptCore/dfg/DFGCommon.h
index 1a64a248c..ddbefd2d5 100644
--- a/Source/JavaScriptCore/dfg/DFGCommon.h
+++ b/Source/JavaScriptCore/dfg/DFGCommon.h
@@ -132,7 +132,7 @@ enum SpillRegistersMode { NeedToSpill, DontSpill };
enum NoResultTag { NoResult };
-enum OptimizationFixpointState { FixpointConverged, FixpointNotConverged };
+enum OptimizationFixpointState { BeforeFixpoint, FixpointNotConverged, FixpointConverged };
inline bool shouldShowDisassembly()
{
diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
index 68d5534e0..dfb62cbc4 100644
--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
@@ -101,7 +101,16 @@ private:
node.convertToStructureTransitionWatchpoint(structureValue.singleton());
break;
}
-
+
+ case CheckArray: {
+ if (!modeAlreadyChecked(m_state.forNode(node.child1()), node.arrayMode()))
+ break;
+ ASSERT(node.refCount() == 1);
+ node.setOpAndDefaultFlags(Phantom);
+ eliminated = true;
+ break;
+ }
+
default:
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGDriver.cpp b/Source/JavaScriptCore/dfg/DFGDriver.cpp
index ccef65208..eb68fa344 100644
--- a/Source/JavaScriptCore/dfg/DFGDriver.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDriver.cpp
@@ -28,7 +28,7 @@
#include "JSObject.h"
#include "JSString.h"
-#include "ScopeChain.h"
+
#if ENABLE(DFG_JIT)
@@ -41,7 +41,6 @@
#include "DFGFixupPhase.h"
#include "DFGJITCompiler.h"
#include "DFGPredictionPropagationPhase.h"
-#include "DFGRedundantPhiEliminationPhase.h"
#include "DFGStructureCheckHoistingPhase.h"
#include "DFGValidate.h"
#include "DFGVirtualRegisterAllocationPhase.h"
@@ -117,6 +116,7 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo
performFixup(dfg);
performStructureCheckHoisting(dfg);
unsigned cnt = 1;
+ dfg.m_fixpointState = FixpointNotConverged;
for (;; ++cnt) {
#if DFG_ENABLE(DEBUG_VERBOSE)
dataLog("DFG beginning optimization fixpoint iteration #%u.\n", cnt);
@@ -126,13 +126,14 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo
changed |= performConstantFolding(dfg);
changed |= performArgumentsSimplification(dfg);
changed |= performCFGSimplification(dfg);
- changed |= performCSE(dfg, FixpointNotConverged);
+ changed |= performCSE(dfg);
if (!changed)
break;
dfg.resetExitStates();
performFixup(dfg);
}
- performCSE(dfg, FixpointConverged);
+ dfg.m_fixpointState = FixpointConverged;
+ performCSE(dfg);
#if DFG_ENABLE(DEBUG_VERBOSE)
dataLog("DFG optimization fixpoint converged in %u iterations.\n", cnt);
#endif
diff --git a/Source/JavaScriptCore/dfg/DFGFPRInfo.h b/Source/JavaScriptCore/dfg/DFGFPRInfo.h
index e817ed396..5ee87bce1 100644
--- a/Source/JavaScriptCore/dfg/DFGFPRInfo.h
+++ b/Source/JavaScriptCore/dfg/DFGFPRInfo.h
@@ -122,6 +122,11 @@ public:
// we'll return in d0 for simplicity.
static const FPRReg returnValueFPR = ARMRegisters::d0; // fpRegT0
+#if CPU(ARM_HARDFP)
+ static const FPRReg argumentFPR0 = ARMRegisters::d0; // fpRegT0
+ static const FPRReg argumentFPR1 = ARMRegisters::d1; // fpRegT1
+#endif
+
// FPRReg mapping is direct, the machine regsiter numbers can
// be used directly as indices into the FPR RegisterBank.
COMPILE_ASSERT(ARMRegisters::d0 == 0, d0_is_0);
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index fe7cae8a9..7700b4b86 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -74,6 +74,9 @@ private:
switch (op) {
case GetById: {
+ if (m_graph.m_fixpointState > BeforeFixpoint)
+ break;
+
Node* nodePtr = &node;
if (!isInt32Speculation(m_graph[m_compileIndex].prediction()))
@@ -90,8 +93,7 @@ private:
fromObserved(arrayProfile->observedArrayModes(), false),
m_graph[node.child1()].prediction(),
m_graph[m_compileIndex].prediction());
- if (modeSupportsLength(arrayMode)
- && arrayProfile->hasDefiniteStructure()) {
+ if (modeSupportsLength(arrayMode) && arrayProfile->hasDefiniteStructure()) {
m_graph.ref(nodePtr->child1());
Node checkStructure(CheckStructure, nodePtr->codeOrigin, OpInfo(m_graph.addStructureSet(arrayProfile->expectedStructure())), nodePtr->child1().index());
checkStructure.ref();
@@ -113,17 +115,16 @@ private:
nodePtr->clearFlags(NodeMustGenerate);
m_graph.deref(m_compileIndex);
nodePtr->setArrayMode(arrayMode);
+
+ NodeIndex storage = checkArray(arrayMode, nodePtr->codeOrigin, nodePtr->child1().index(), lengthNeedsStorage, nodePtr->shouldGenerate());
+ if (storage == NoNode)
+ break;
+
+ nodePtr = &m_graph[m_compileIndex];
+ nodePtr->children.child2() = Edge(storage);
break;
}
case GetIndexedPropertyStorage: {
- node.setArrayMode(
- refineArrayMode(
- node.arrayMode(),
- m_graph[node.child1()].prediction(),
- m_graph[node.child2()].prediction()));
- // Predictions should only become more, rather than less, refined. Hence
- // if we were ever able to CSE the storage pointer for this operation,
- // then we should always continue to be able to do so.
ASSERT(canCSEStorage(node.arrayMode()));
break;
}
@@ -136,30 +137,19 @@ private:
m_graph[node.child1()].prediction(),
m_graph[node.child2()].prediction()));
- if (canCSEStorage(node.arrayMode())) {
- if (node.child3()) {
- ASSERT(m_graph[node.child3()].op() == GetIndexedPropertyStorage);
- ASSERT(modesCompatibleForStorageLoad(m_graph[node.child3()].arrayMode(), node.arrayMode()));
- } else {
- // Make sure we don't use the node reference after we do the append.
- Node getIndexedPropertyStorage(
- GetIndexedPropertyStorage, node.codeOrigin, OpInfo(node.arrayMode()),
- node.child1().index(), node.child2().index());
- NodeIndex getIndexedPropertyStorageIndex = m_graph.size();
- node.children.child3() = Edge(getIndexedPropertyStorageIndex);
- m_graph.append(getIndexedPropertyStorage);
- m_graph.ref(getIndexedPropertyStorageIndex); // Once because it's MustGenerate.
- m_graph.ref(getIndexedPropertyStorageIndex); // And again because it's referenced from the GetByVal.
- m_insertionSet.append(m_indexInBlock, getIndexedPropertyStorageIndex);
- }
- } else {
- // See above. Continued fixup of the graph should not regress our ability
- // to speculate.
- ASSERT(!node.child3());
- }
+ blessArrayOperation(node.child1(), 2);
+ break;
+ }
+
+ case ArrayPush: {
+ blessArrayOperation(node.child1(), 2);
break;
}
+ case ArrayPop: {
+ blessArrayOperation(node.child1(), 1);
+ }
+
case ValueToInt32: {
if (m_graph[node.child1()].shouldSpeculateNumber()
&& node.mustGenerate()) {
@@ -330,11 +320,18 @@ private:
Edge child1 = m_graph.varArgChild(node, 0);
Edge child2 = m_graph.varArgChild(node, 1);
Edge child3 = m_graph.varArgChild(node, 2);
+
node.setArrayMode(
refineArrayMode(
- node.arrayMode(), m_graph[child1].prediction(), m_graph[child2].prediction()));
+ node.arrayMode(),
+ m_graph[child1].prediction(),
+ m_graph[child2].prediction()));
+
+ blessArrayOperation(child1, 3);
- switch (modeForPut(node.arrayMode())) {
+ Node* nodePtr = &m_graph[m_compileIndex];
+
+ switch (modeForPut(nodePtr->arrayMode())) {
case Array::Int8Array:
case Array::Int16Array:
case Array::Int32Array:
@@ -368,6 +365,59 @@ private:
#endif
}
+ NodeIndex checkArray(Array::Mode arrayMode, CodeOrigin codeOrigin, NodeIndex array, bool (*storageCheck)(Array::Mode) = canCSEStorage, bool shouldGenerate = true)
+ {
+ ASSERT(modeIsSpecific(arrayMode));
+
+ m_graph.ref(array);
+ Node checkArray(CheckArray, codeOrigin, OpInfo(arrayMode), array);
+ checkArray.ref();
+ NodeIndex checkArrayIndex = m_graph.size();
+ m_graph.append(checkArray);
+ m_insertionSet.append(m_indexInBlock, checkArrayIndex);
+
+ if (!storageCheck(arrayMode))
+ return NoNode;
+
+ if (shouldGenerate)
+ m_graph.ref(array);
+ Node getIndexedPropertyStorage(
+ GetIndexedPropertyStorage, codeOrigin, OpInfo(arrayMode), array);
+ if (shouldGenerate)
+ getIndexedPropertyStorage.ref();
+ NodeIndex getIndexedPropertyStorageIndex = m_graph.size();
+ m_graph.append(getIndexedPropertyStorage);
+ m_insertionSet.append(m_indexInBlock, getIndexedPropertyStorageIndex);
+
+ return getIndexedPropertyStorageIndex;
+ }
+
+ void blessArrayOperation(Edge base, unsigned storageChildIdx)
+ {
+ if (m_graph.m_fixpointState > BeforeFixpoint)
+ return;
+
+ Node* nodePtr = &m_graph[m_compileIndex];
+
+ if (nodePtr->arrayMode() == Array::ForceExit) {
+ Node forceExit(ForceOSRExit, nodePtr->codeOrigin);
+ forceExit.ref();
+ NodeIndex forceExitIndex = m_graph.size();
+ m_graph.append(forceExit);
+ m_insertionSet.append(m_indexInBlock, forceExitIndex);
+ return;
+ }
+
+ if (!modeIsSpecific(nodePtr->arrayMode()))
+ return;
+
+ NodeIndex storage = checkArray(nodePtr->arrayMode(), nodePtr->codeOrigin, base.index());
+ if (storage == NoNode)
+ return;
+
+ m_graph.child(m_graph[m_compileIndex], storageChildIdx) = Edge(storage);
+ }
+
void fixIntEdge(Edge& edge)
{
Node& node = m_graph[edge];
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp
index 8e80ff2fc..f4d260b9e 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.cpp
+++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp
@@ -40,6 +40,18 @@ static const char* dfgOpNames[] = {
#undef STRINGIZE_DFG_OP_ENUM
};
+Graph::Graph(JSGlobalData& globalData, CodeBlock* codeBlock, unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues)
+ : m_globalData(globalData)
+ , m_codeBlock(codeBlock)
+ , m_profiledBlock(codeBlock->alternative())
+ , m_hasArguments(false)
+ , m_osrEntryBytecodeIndex(osrEntryBytecodeIndex)
+ , m_mustHandleValues(mustHandleValues)
+ , m_fixpointState(BeforeFixpoint)
+{
+ ASSERT(m_profiledBlock);
+}
+
const char *Graph::opName(NodeType op)
{
return dfgOpNames[op];
@@ -179,6 +191,8 @@ void Graph::dump(const char* prefix, NodeIndex nodeIndex)
dataLog(", ");
else
hasPrinted = true;
+ if (!m_varArgChildren[childIdx])
+ continue;
dataLog("%s@%u%s",
useKindToString(m_varArgChildren[childIdx].useKind()),
m_varArgChildren[childIdx].index(),
@@ -227,7 +241,7 @@ void Graph::dump(const char* prefix, NodeIndex nodeIndex)
hasPrinted = true;
}
if (node.hasIdentifier()) {
- dataLog("%sid%u{%s}", hasPrinted ? ", " : "", node.identifierNumber(), m_codeBlock->identifier(node.identifierNumber()).ustring().utf8().data());
+ dataLog("%sid%u{%s}", hasPrinted ? ", " : "", node.identifierNumber(), m_codeBlock->identifier(node.identifierNumber()).string().utf8().data());
hasPrinted = true;
}
if (node.hasStructureSet()) {
@@ -246,7 +260,7 @@ void Graph::dump(const char* prefix, NodeIndex nodeIndex)
}
if (node.hasStorageAccessData()) {
StorageAccessData& storageAccessData = m_storageAccessData[node.storageAccessDataIndex()];
- dataLog("%sid%u{%s}", hasPrinted ? ", " : "", storageAccessData.identifierNumber, m_codeBlock->identifier(storageAccessData.identifierNumber).ustring().utf8().data());
+ dataLog("%sid%u{%s}", hasPrinted ? ", " : "", storageAccessData.identifierNumber, m_codeBlock->identifier(storageAccessData.identifierNumber).string().utf8().data());
dataLog(", %lu", static_cast<unsigned long>(storageAccessData.offset));
hasPrinted = true;
@@ -392,8 +406,10 @@ void Graph::dump()
if (_node.flags() & NodeHasVarArgs) { \
for (unsigned _childIdx = _node.firstChild(); \
_childIdx < _node.firstChild() + _node.numChildren(); \
- _childIdx++) \
- thingToDo(m_varArgChildren[_childIdx]); \
+ _childIdx++) { \
+ if (!!m_varArgChildren[_childIdx]) \
+ thingToDo(m_varArgChildren[_childIdx]); \
+ } \
} else { \
if (!_node.child1()) { \
ASSERT(!_node.child2() \
@@ -483,6 +499,8 @@ void Graph::collectGarbage()
for (unsigned childIdx = node.firstChild();
childIdx < node.firstChild() + node.numChildren();
++childIdx) {
+ if (!m_varArgChildren[childIdx])
+ continue;
NodeIndex childNodeIndex = m_varArgChildren[childIdx].index();
if (!at(childNodeIndex).ref())
continue;
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index ba5d86f81..70cbbaf07 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -53,14 +53,6 @@ namespace DFG {
struct StorageAccessData {
size_t offset;
unsigned identifierNumber;
-
- // NOTE: the offset and identifierNumber do not by themselves
- // uniquely identify a property. The identifierNumber and a
- // Structure* do. If those two match, then the offset should
- // be the same, as well. For any Node that has a StorageAccessData,
- // it is possible to retrieve the Structure* by looking at the
- // first child. It should be a CheckStructure, which has the
- // Structure*.
};
struct ResolveGlobalData {
@@ -76,16 +68,7 @@ struct ResolveGlobalData {
// Nodes that are 'dead' remain in the vector with refCount 0.
class Graph : public Vector<Node, 64> {
public:
- Graph(JSGlobalData& globalData, CodeBlock* codeBlock, unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues)
- : m_globalData(globalData)
- , m_codeBlock(codeBlock)
- , m_profiledBlock(codeBlock->alternative())
- , m_hasArguments(false)
- , m_osrEntryBytecodeIndex(osrEntryBytecodeIndex)
- , m_mustHandleValues(mustHandleValues)
- {
- ASSERT(m_profiledBlock);
- }
+ Graph(JSGlobalData&, CodeBlock*, unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues);
using Vector<Node, 64>::operator[];
using Vector<Node, 64>::at;
@@ -585,8 +568,10 @@ public:
if (node.flags() & NodeHasVarArgs) {
for (unsigned childIdx = node.firstChild();
childIdx < node.firstChild() + node.numChildren();
- childIdx++)
- vote(m_varArgChildren[childIdx], ballot);
+ childIdx++) {
+ if (!!m_varArgChildren[childIdx])
+ vote(m_varArgChildren[childIdx], ballot);
+ }
return;
}
@@ -608,8 +593,10 @@ public:
NodeIndex nodeIndex = block[indexInBlock];
Node& node = at(nodeIndex);
if (node.flags() & NodeHasVarArgs) {
- for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); ++childIdx)
- compareAndSwap(m_varArgChildren[childIdx], oldThing, newThing, node.shouldGenerate());
+ for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); ++childIdx) {
+ if (!!m_varArgChildren[childIdx])
+ compareAndSwap(m_varArgChildren[childIdx], oldThing, newThing, node.shouldGenerate());
+ }
continue;
}
if (!node.child1())
@@ -685,6 +672,8 @@ public:
unsigned m_parameterSlots;
unsigned m_osrEntryBytecodeIndex;
Operands<JSValue> m_mustHandleValues;
+
+ OptimizationFixpointState m_fixpointState;
private:
void handleSuccessor(Vector<BlockIndex, 16>& worklist, BlockIndex blockIndex, BlockIndex successorIndex);
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index 7ca4d8d48..fb31f935e 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -743,6 +743,9 @@ struct Node {
case GetByVal:
case StringCharAt:
case StringCharCodeAt:
+ case CheckArray:
+ case ArrayPush:
+ case ArrayPop:
return true;
default:
return false;
@@ -755,10 +758,13 @@ struct Node {
return static_cast<Array::Mode>(m_opInfo);
}
- void setArrayMode(Array::Mode arrayMode)
+ bool setArrayMode(Array::Mode arrayMode)
{
ASSERT(hasArrayMode());
+ if (this->arrayMode() == arrayMode)
+ return false;
m_opInfo = arrayMode;
+ return true;
}
bool hasVirtualRegister()
@@ -910,12 +916,27 @@ struct Node {
{
return isBooleanSpeculation(prediction());
}
-
+
+ bool shouldSpeculateString()
+ {
+ return isStringSpeculation(prediction());
+ }
+
bool shouldSpeculateFinalObject()
{
return isFinalObjectSpeculation(prediction());
}
+ bool shouldSpeculateNonStringCell()
+ {
+ return isNonStringCellSpeculation(prediction());
+ }
+
+ bool shouldSpeculateNonStringCellOrOther()
+ {
+ return isNonStringCellOrOtherSpeculation(prediction());
+ }
+
bool shouldSpeculateFinalObjectOrOther()
{
return isFinalObjectOrOtherSpeculation(prediction());
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index ee5ad9013..d86b9b356 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -138,7 +138,8 @@ namespace JSC { namespace DFG {
macro(AllocatePropertyStorage, NodeMustGenerate | NodeDoesNotExit | NodeResultStorage) \
macro(ReallocatePropertyStorage, NodeMustGenerate | NodeDoesNotExit | NodeResultStorage) \
macro(GetPropertyStorage, NodeResultStorage) \
- macro(GetIndexedPropertyStorage, NodeMustGenerate | NodeResultStorage) \
+ macro(CheckArray, NodeMustGenerate) \
+ macro(GetIndexedPropertyStorage, NodeResultStorage) \
macro(GetByOffset, NodeResultJS) \
macro(PutByOffset, NodeMustGenerate) \
macro(GetArrayLength, NodeResultInt32) \
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index b5c3b961b..824a0a37a 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -39,11 +39,13 @@
#include "JITExceptions.h"
#include "JSActivation.h"
#include "JSGlobalData.h"
-#include "JSStaticScopeObject.h"
+#include "JSNameScope.h"
#include "NameInstance.h"
#include "Operations.h"
#include <wtf/InlineASM.h>
+#if ENABLE(JIT)
+
#if ENABLE(DFG_JIT)
#if CPU(X86_64)
@@ -407,6 +409,20 @@ EncodedJSValue DFG_OPERATION operationGetByValCell(ExecState* exec, JSCell* base
return JSValue::encode(JSValue(base).get(exec, ident));
}
+EncodedJSValue DFG_OPERATION operationGetByValArrayInt(ExecState* exec, JSArray* base, int32_t index)
+{
+ JSGlobalData* globalData = &exec->globalData();
+ NativeCallFrameTracer tracer(globalData, exec);
+
+ if (index < 0) {
+ // Go the slowest way possible becase negative indices don't use indexed storage.
+ return JSValue::encode(JSValue(base).get(exec, Identifier::from(exec, index)));
+ }
+
+ // Use this since we know that the value is out of bounds.
+ return JSValue::encode(JSValue(base).get(exec, index));
+}
+
EncodedJSValue DFG_OPERATION operationGetById(ExecState* exec, EncodedJSValue base, Identifier* propertyName)
{
JSGlobalData* globalData = &exec->globalData();
@@ -575,6 +591,14 @@ EncodedJSValue DFG_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue
return JSValue::encode(jsNumber(array->length()));
}
+EncodedJSValue DFG_OPERATION operationArrayPop(ExecState* exec, JSArray* array)
+{
+ JSGlobalData* globalData = &exec->globalData();
+ NativeCallFrameTracer tracer(globalData, exec);
+
+ return JSValue::encode(array->pop(exec));
+}
+
EncodedJSValue DFG_OPERATION operationRegExpExec(ExecState* exec, JSCell* base, JSCell* argument)
{
JSGlobalData& globalData = exec->globalData();
@@ -603,14 +627,6 @@ size_t DFG_OPERATION operationRegExpTest(ExecState* exec, JSCell* base, JSCell*
return asRegExpObject(base)->test(exec, input);
}
-EncodedJSValue DFG_OPERATION operationArrayPop(ExecState* exec, JSArray* array)
-{
- JSGlobalData* globalData = &exec->globalData();
- NativeCallFrameTracer tracer(globalData, exec);
-
- return JSValue::encode(array->pop(exec));
-}
-
void DFG_OPERATION operationPutByIdStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName)
{
JSGlobalData* globalData = &exec->globalData();
@@ -899,7 +915,7 @@ static void* handleHostCall(ExecState* execCallee, JSValue callee, CodeSpecializ
ExecState* exec = execCallee->callerFrame();
JSGlobalData* globalData = &exec->globalData();
- execCallee->setScopeChain(exec->scopeChain());
+ execCallee->setScope(exec->scope());
execCallee->setCodeBlock(0);
if (kind == CodeForCall) {
@@ -957,7 +973,7 @@ inline char* linkFor(ExecState* execCallee, CodeSpecializationKind kind)
return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind));
JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell);
- execCallee->setScopeChain(callee->scopeUnchecked());
+ execCallee->setScope(callee->scopeUnchecked());
ExecutableBase* executable = callee->executable();
MacroAssemblerCodePtr codePtr;
@@ -1007,7 +1023,7 @@ inline char* virtualFor(ExecState* execCallee, CodeSpecializationKind kind)
return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind));
JSFunction* function = jsCast<JSFunction*>(calleeAsFunctionCell);
- execCallee->setScopeChain(function->scopeUnchecked());
+ execCallee->setScope(function->scopeUnchecked());
ExecutableBase* executable = function->executable();
if (UNLIKELY(!executable->hasJITCodeFor(kind))) {
FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
@@ -1039,20 +1055,7 @@ EncodedJSValue DFG_OPERATION operationResolve(ExecState* exec, Identifier* prope
{
JSGlobalData* globalData = &exec->globalData();
NativeCallFrameTracer tracer(globalData, exec);
-
- ScopeChainNode* scopeChain = exec->scopeChain();
- ScopeChainIterator iter = scopeChain->begin();
- ScopeChainIterator end = scopeChain->end();
- ASSERT(iter != end);
-
- do {
- JSObject* record = iter->get();
- PropertySlot slot(record);
- if (record->getPropertySlot(exec, *propertyName, slot))
- return JSValue::encode(slot.getValue(exec, *propertyName));
- } while (++iter != end);
-
- return throwVMError(exec, createUndefinedVariableError(exec, *propertyName));
+ return JSValue::encode(JSScope::resolve(exec, *propertyName));
}
EncodedJSValue DFG_OPERATION operationResolveBase(ExecState* exec, Identifier* propertyName)
@@ -1060,7 +1063,7 @@ EncodedJSValue DFG_OPERATION operationResolveBase(ExecState* exec, Identifier* p
JSGlobalData* globalData = &exec->globalData();
NativeCallFrameTracer tracer(globalData, exec);
- return JSValue::encode(resolveBase(exec, *propertyName, exec->scopeChain(), false));
+ return JSValue::encode(JSScope::resolveBase(exec, *propertyName, false));
}
EncodedJSValue DFG_OPERATION operationResolveBaseStrictPut(ExecState* exec, Identifier* propertyName)
@@ -1068,30 +1071,15 @@ EncodedJSValue DFG_OPERATION operationResolveBaseStrictPut(ExecState* exec, Iden
JSGlobalData* globalData = &exec->globalData();
NativeCallFrameTracer tracer(globalData, exec);
- JSValue base = resolveBase(exec, *propertyName, exec->scopeChain(), true);
- if (!base)
- throwError(exec, createErrorForInvalidGlobalAssignment(exec, propertyName->ustring()));
- return JSValue::encode(base);
+ return JSValue::encode(JSScope::resolveBase(exec, *propertyName, true));
}
EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState* exec, GlobalResolveInfo* resolveInfo, JSGlobalObject* globalObject, Identifier* propertyName)
{
JSGlobalData* globalData = &exec->globalData();
NativeCallFrameTracer tracer(globalData, exec);
-
- PropertySlot slot(globalObject);
- if (globalObject->getPropertySlot(exec, *propertyName, slot)) {
- JSValue result = slot.getValue(exec, *propertyName);
-
- if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
- resolveInfo->structure.set(exec->globalData(), exec->codeBlock()->ownerExecutable(), globalObject->structure());
- resolveInfo->offset = slot.cachedOffset();
- }
- return JSValue::encode(result);
- }
-
- return throwVMError(exec, createUndefinedVariableError(exec, *propertyName));
+ return JSValue::encode(JSScope::resolveGlobal(exec, *propertyName, globalObject, &resolveInfo->structure, &resolveInfo->offset));
}
EncodedJSValue DFG_OPERATION operationToPrimitive(ExecState* exec, EncodedJSValue value)
@@ -1154,7 +1142,7 @@ JSCell* DFG_OPERATION operationCreateActivation(ExecState* exec)
NativeCallFrameTracer tracer(&globalData, exec);
JSActivation* activation = JSActivation::create(
globalData, exec, static_cast<FunctionExecutable*>(exec->codeBlock()->ownerExecutable()));
- exec->setScopeChain(exec->scopeChain()->push(activation));
+ exec->setScope(activation);
return activation;
}
@@ -1255,7 +1243,7 @@ JSCell* DFG_OPERATION operationNewFunction(ExecState* exec, JSCell* functionExec
ASSERT(functionExecutable->inherits(&FunctionExecutable::s_info));
JSGlobalData& globalData = exec->globalData();
NativeCallFrameTracer tracer(&globalData, exec);
- return static_cast<FunctionExecutable*>(functionExecutable)->make(exec, exec->scopeChain());
+ return JSFunction::create(exec, static_cast<FunctionExecutable*>(functionExecutable), exec->scope());
}
JSCell* DFG_OPERATION operationNewFunctionExpression(ExecState* exec, JSCell* functionExecutableAsCell)
@@ -1263,14 +1251,7 @@ JSCell* DFG_OPERATION operationNewFunctionExpression(ExecState* exec, JSCell* fu
ASSERT(functionExecutableAsCell->inherits(&FunctionExecutable::s_info));
FunctionExecutable* functionExecutable =
static_cast<FunctionExecutable*>(functionExecutableAsCell);
- JSFunction *function = functionExecutable->make(exec, exec->scopeChain());
- if (!functionExecutable->name().isNull()) {
- JSStaticScopeObject* functionScopeObject =
- JSStaticScopeObject::create(
- exec, functionExecutable->name(), function, ReadOnly | DontDelete);
- function->setScope(exec->globalData(), function->scope()->push(functionScopeObject));
- }
- return function;
+ return JSFunction::create(exec, functionExecutable, exec->scope());
}
size_t DFG_OPERATION operationIsObject(ExecState* exec, EncodedJSValue value)
@@ -1416,7 +1397,7 @@ extern "C" void DFG_OPERATION triggerReoptimizationNow(CodeBlock* codeBlock)
} // extern "C"
} } // namespace JSC::DFG
-#endif
+#endif // ENABLE(DFG_JIT)
#if COMPILER(GCC)
@@ -1478,3 +1459,4 @@ extern "C" EncodedJSValue HOST_CALL_RETURN_VALUE_OPTION getHostCallReturnValueWi
#endif // COMPILER(GCC)
+#endif // ENABLE(JIT)
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h
index 455c2bcc3..82babe875 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.h
+++ b/Source/JavaScriptCore/dfg/DFGOperations.h
@@ -62,6 +62,7 @@ extern "C" {
*/
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_E)(ExecState*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EA)(ExecState*, JSArray*);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EAZ)(ExecState*, JSArray*, int32_t);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECC)(ExecState*, JSCell*, JSCell*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECI)(ExecState*, JSCell*, Identifier*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECJ)(ExecState*, JSCell*, EncodedJSValue);
@@ -116,6 +117,7 @@ EncodedJSValue DFG_OPERATION operationValueAdd(ExecState*, EncodedJSValue encode
EncodedJSValue DFG_OPERATION operationValueAddNotNumber(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationGetByVal(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationGetByValCell(ExecState*, JSCell*, EncodedJSValue encodedProperty) WTF_INTERNAL;
+EncodedJSValue DFG_OPERATION operationGetByValArrayInt(ExecState*, JSArray*, int32_t) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationGetById(ExecState*, EncodedJSValue, Identifier*) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationGetByIdBuildList(ExecState*, EncodedJSValue, Identifier*) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationGetByIdProtoBuildList(ExecState*, EncodedJSValue, Identifier*) WTF_INTERNAL;
diff --git a/Source/JavaScriptCore/dfg/DFGPhase.h b/Source/JavaScriptCore/dfg/DFGPhase.h
index 80fd6914a..a73d26baf 100644
--- a/Source/JavaScriptCore/dfg/DFGPhase.h
+++ b/Source/JavaScriptCore/dfg/DFGPhase.h
@@ -95,13 +95,6 @@ bool runPhase(Graph& graph)
return runAndLog(phase);
}
-template<typename PhaseType, typename ArgumentType1>
-bool runPhase(Graph& graph, ArgumentType1 arg1)
-{
- PhaseType phase(graph, arg1);
- return runAndLog(phase);
-}
-
} } // namespace JSC::DFG
#endif // ENABLE(DFG_JIT)
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index 258d1199a..af57ab8fe 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -618,7 +618,8 @@ private:
case GetMyArgumentsLength:
case GetMyArgumentByVal:
case PhantomPutStructure:
- case PhantomArguments: {
+ case PhantomArguments:
+ case CheckArray: {
// This node should never be visible at this stage of compilation. It is
// inserted by fixup(), which follows this phase.
ASSERT_NOT_REACHED();
@@ -703,8 +704,10 @@ private:
if (node.flags() & NodeHasVarArgs) {
for (unsigned childIdx = node.firstChild();
childIdx < node.firstChild() + node.numChildren();
- childIdx++)
- changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeFlags(NodeUsedAsValue);
+ childIdx++) {
+ if (!!m_graph.m_varArgChildren[childIdx])
+ changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeFlags(NodeUsedAsValue);
+ }
} else {
if (!node.child1())
return changed;
diff --git a/Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.cpp b/Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.cpp
deleted file mode 100644
index 32e4ef157..000000000
--- a/Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2012 Intel Corporation. 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 "DFGRedundantPhiEliminationPhase.h"
-
-#if ENABLE(DFG_JIT)
-
-#include "DFGGraph.h"
-
-namespace JSC { namespace DFG {
-
-class RedundantPhiEliminationPhase : public Phase {
-public:
- RedundantPhiEliminationPhase(Graph& graph)
- : Phase(graph, "redundant phi elimination")
- {
- }
-
- bool run()
- {
- bool changed = false;
- do {
- changed = fixupPhis();
- } while (changed);
-
- updateBlockVariableInformation();
-
- // Update the Phi references from non-Phi nodes, e.g., the GetLocals.
- for (NodeIndex index = 0; index < m_graph.size(); ++index) {
- Node& node = m_graph[index];
-
- if (!node.shouldGenerate())
- continue;
-
- switch (node.op()) {
- case GetLocal:
- replacePhiChild(node, 0);
- break;
- default:
- break;
- }
- }
-
- return true;
- }
-
-private:
- NodeIndex getRedundantReplacement(NodeIndex phi)
- {
- NodeIndex child1 = m_graph[phi].child1().indexUnchecked();
- NodeIndex candidate = child1 == phi ? NoNode : child1;
-
- NodeIndex child2 = m_graph[phi].child2().indexUnchecked();
- if (candidate != NoNode) {
- if (child2 != NoNode && child2 != candidate && child2 != phi)
- return NoNode;
- } else if (child2 != phi)
- candidate = child2;
-
- NodeIndex child3 = m_graph[phi].child3().indexUnchecked();
- if (candidate != NoNode) {
- if (child3 != NoNode && child3 != candidate && child3 != phi)
- return NoNode;
- } else if (child3 != phi)
- candidate = child3;
-
- return candidate;
- }
-
- bool replacePhiChild(Node& node, unsigned childIndex)
- {
- ASSERT(childIndex < 3);
-
- bool replaced = false;
- NodeIndex child = node.children.child(childIndex).indexUnchecked();
- if (child != NoNode && m_graph[child].op() == Phi) {
- NodeIndex childReplacement = getRedundantReplacement(child);
- if (childReplacement != NoNode) {
- node.children.child(childIndex).setIndex(childReplacement);
- replaced = true;
- if (node.refCount()) {
- m_graph[childReplacement].ref();
- m_graph.deref(child);
- }
- }
- }
- return replaced;
- }
-
- bool fixupPhis()
- {
- bool changed = false;
-
- for (BlockIndex block = 0; block < m_graph.m_blocks.size(); ++block) {
- Vector<NodeIndex>& phis = m_graph.m_blocks[block]->phis;
-
- for (size_t i = 0; i < phis.size(); ++i) {
- NodeIndex phi = phis[i];
- Node& phiNode = m_graph[phi];
-
- changed |= (replacePhiChild(phiNode, 0) && phiNode.refCount());
- changed |= (replacePhiChild(phiNode, 1) && phiNode.refCount());
- changed |= (replacePhiChild(phiNode, 2) && phiNode.refCount());
- }
- }
-
- return changed;
- }
-
- void updateBlockVariableInformation()
- {
- // Redundant Phi nodes are eliminated, we need to update
- // the variable information if it references them.
- for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
- BasicBlock* basicBlock = m_graph.m_blocks[blockIndex].get();
-
- for (size_t arg = 0; arg < basicBlock->variablesAtHead.numberOfArguments(); ++arg) {
- NodeIndex nodeIndex = basicBlock->variablesAtHead.argument(arg);
- if (nodeIndex != NoNode && m_graph[nodeIndex].op() == Phi && !m_graph[nodeIndex].refCount()) {
- NodeIndex replacement = getRedundantReplacement(nodeIndex);
- if (replacement != NoNode) {
- // This argument must be unused in this block.
- ASSERT(basicBlock->variablesAtTail.argument(arg) == nodeIndex);
- basicBlock->variablesAtHead.argument(arg) = replacement;
- basicBlock->variablesAtTail.argument(arg) = replacement;
- }
- }
- }
-
- for (size_t local = 0; local < basicBlock->variablesAtHead.numberOfLocals(); ++local) {
- NodeIndex nodeIndex = basicBlock->variablesAtHead.local(local);
- if (nodeIndex != NoNode && m_graph[nodeIndex].op() == Phi && !m_graph[nodeIndex].refCount()) {
- NodeIndex replacement = getRedundantReplacement(nodeIndex);
- if (replacement != NoNode) {
- // This local variable must be unused in this block.
- ASSERT(basicBlock->variablesAtTail.local(local) == nodeIndex);
- basicBlock->variablesAtHead.local(local) = replacement;
- basicBlock->variablesAtTail.local(local) = replacement;
- }
- }
- }
- }
- }
-
-};
-
-bool performRedundantPhiElimination(Graph& graph)
-{
- SamplingRegion samplingRegion("DFG Redundant Phi Elimination Phase");
- return runPhase<RedundantPhiEliminationPhase>(graph);
-}
-
-} } // namespace JSC::DFG
-
-#endif // ENABLE(DFG_JIT)
diff --git a/Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.h b/Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.h
deleted file mode 100644
index fd6634a88..000000000
--- a/Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2012 Intel Corporation. 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 DFGRedundantPhiEliminationPhase_h
-#define DFGRedundantPhiEliminationPhase_h
-
-#include <wtf/Platform.h>
-
-#if ENABLE(DFG_JIT)
-
-#include "DFGPhase.h"
-
-namespace JSC { namespace DFG {
-
-class Graph;
-
-// We inserted many can-be-redundant Phi nodes when building the graph.
-// This phase will just remove them.
-
-bool performRedundantPhiElimination(Graph&);
-
-} } // namespace JSC::DFG
-
-#endif // ENABLE(DFG_JIT)
-
-#endif // DFGRedundantPhiEliminationPhase_h
-
diff --git a/Source/JavaScriptCore/dfg/DFGRepatch.cpp b/Source/JavaScriptCore/dfg/DFGRepatch.cpp
index 23e8db03b..1af4999e8 100644
--- a/Source/JavaScriptCore/dfg/DFGRepatch.cpp
+++ b/Source/JavaScriptCore/dfg/DFGRepatch.cpp
@@ -252,8 +252,12 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier
}
MacroAssembler::JumpList failureCases;
-
- failureCases.append(stubJit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
+
+ stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSCell::structureOffset()), scratchGPR);
+ failureCases.append(stubJit.branchPtr(
+ MacroAssembler::NotEqual,
+ MacroAssembler::Address(scratchGPR, Structure::classInfoOffset()),
+ MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), scratchGPR);
stubJit.load32(MacroAssembler::Address(scratchGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), scratchGPR);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index d74207420..c9c07da80 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -295,20 +295,23 @@ const TypedArrayDescriptor* SpeculativeJIT::typedArrayDescriptor(Array::Mode arr
}
}
-const TypedArrayDescriptor* SpeculativeJIT::speculateArray(Array::Mode arrayMode, Edge edge, GPRReg baseReg)
+void SpeculativeJIT::checkArray(Node& node)
{
- const TypedArrayDescriptor* result = typedArrayDescriptor(arrayMode);
+ ASSERT(modeIsSpecific(node.arrayMode()));
- if (modeAlreadyChecked(m_state.forNode(edge), arrayMode))
- return result;
+ SpeculateCellOperand base(this, node.child1());
+ GPRReg baseReg = base.gpr();
+
+ const TypedArrayDescriptor* result = typedArrayDescriptor(node.arrayMode());
+
+ if (modeAlreadyChecked(m_state.forNode(node.child1()), node.arrayMode())) {
+ noResult(m_compileIndex);
+ return;
+ }
const ClassInfo* expectedClassInfo = 0;
- switch (arrayMode) {
- case Array::ForceExit:
- ASSERT_NOT_REACHED();
- terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode);
- return result;
+ switch (node.arrayMode()) {
case Array::String:
expectedClassInfo = &JSString::s_info;
break;
@@ -325,7 +328,9 @@ const TypedArrayDescriptor* SpeculativeJIT::speculateArray(Array::Mode arrayMode
MacroAssembler::NotEqual,
MacroAssembler::Address(temp.gpr(), Structure::classInfoOffset()),
MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
- return result;
+
+ noResult(m_compileIndex);
+ return;
}
case Array::Arguments:
expectedClassInfo = &Arguments::s_info;
@@ -356,7 +361,7 @@ const TypedArrayDescriptor* SpeculativeJIT::speculateArray(Array::Mode arrayMode
MacroAssembler::Address(temp.gpr(), Structure::classInfoOffset()),
MacroAssembler::TrustedImmPtr(expectedClassInfo)));
- return result;
+ noResult(m_compileIndex);
}
GPRReg SpeculativeJIT::fillStorage(NodeIndex nodeIndex)
@@ -393,8 +398,10 @@ GPRReg SpeculativeJIT::fillStorage(NodeIndex nodeIndex)
void SpeculativeJIT::useChildren(Node& node)
{
if (node.flags() & NodeHasVarArgs) {
- for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
- use(m_jit.graph().m_varArgChildren[childIdx]);
+ for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++) {
+ if (!!m_jit.graph().m_varArgChildren[childIdx])
+ use(m_jit.graph().m_varArgChildren[childIdx]);
+ }
} else {
Edge child1 = node.child1();
if (!child1) {
@@ -1065,7 +1072,7 @@ void SpeculativeJIT::compilePeepHoleDoubleBranch(Node& node, NodeIndex branchNod
jump(notTaken);
}
-void SpeculativeJIT::compilePeepHoleObjectEquality(Node& node, NodeIndex branchNodeIndex, const ClassInfo* classInfo, SpeculatedTypeChecker speculatedTypeChecker)
+void SpeculativeJIT::compilePeepHoleObjectEquality(Node& node, NodeIndex branchNodeIndex)
{
Node& branchNode = at(branchNodeIndex);
BlockIndex taken = branchNode.takenBlockIndex();
@@ -1086,11 +1093,47 @@ void SpeculativeJIT::compilePeepHoleObjectEquality(Node& node, NodeIndex branchN
GPRReg op1GPR = op1.gpr();
GPRReg op2GPR = op2.gpr();
- if (!speculatedTypeChecker(m_state.forNode(node.child1()).m_type))
- speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node.child1().index(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo)));
- if (!speculatedTypeChecker(m_state.forNode(node.child2()).m_type))
- speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node.child2().index(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op2GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo)));
-
+ if (m_jit.graph().globalObjectFor(node.codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
+ m_jit.graph().globalObjectFor(node.codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+ speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node.child1().index(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op1GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node.child2().index(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op2GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ } else {
+ GPRTemporary structure(this);
+ GPRReg structureGPR = structure.gpr();
+
+ m_jit.loadPtr(MacroAssembler::Address(op1GPR, JSCell::structureOffset()), structureGPR);
+ speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node.child1().index(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node.child1().index(),
+ m_jit.branchTest8(
+ MacroAssembler::NonZero,
+ MacroAssembler::Address(structureGPR, Structure::typeInfoFlagsOffset()),
+ MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
+
+ m_jit.loadPtr(MacroAssembler::Address(op2GPR, JSCell::structureOffset()), structureGPR);
+ speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node.child2().index(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node.child2().index(),
+ m_jit.branchTest8(
+ MacroAssembler::NonZero,
+ MacroAssembler::Address(structureGPR, Structure::typeInfoFlagsOffset()),
+ MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
+ }
+
branchPtr(condition, op1GPR, op2GPR, taken);
jump(notTaken);
}
@@ -1144,37 +1187,17 @@ bool SpeculativeJIT::compilePeepHoleBranch(Node& node, MacroAssembler::Relationa
else if (Node::shouldSpeculateNumber(at(node.child1()), at(node.child2())))
compilePeepHoleDoubleBranch(node, branchNodeIndex, doubleCondition);
else if (node.op() == CompareEq) {
- if (Node::shouldSpeculateFinalObject(
- at(node.child1()), at(node.child2()))) {
- compilePeepHoleObjectEquality(
- node, branchNodeIndex, &JSFinalObject::s_info,
- isFinalObjectSpeculation);
- } else if (Node::shouldSpeculateArray(
- at(node.child1()), at(node.child2()))) {
- compilePeepHoleObjectEquality(
- node, branchNodeIndex, &JSArray::s_info,
- isArraySpeculation);
- } else if (at(node.child1()).shouldSpeculateFinalObject()
- && at(node.child2()).shouldSpeculateFinalObjectOrOther()) {
- compilePeepHoleObjectToObjectOrOtherEquality(
- node.child1(), node.child2(), branchNodeIndex,
- &JSFinalObject::s_info, isFinalObjectSpeculation);
- } else if (at(node.child1()).shouldSpeculateFinalObjectOrOther()
- && at(node.child2()).shouldSpeculateFinalObject()) {
- compilePeepHoleObjectToObjectOrOtherEquality(
- node.child2(), node.child1(), branchNodeIndex,
- &JSFinalObject::s_info, isFinalObjectSpeculation);
- } else if (at(node.child1()).shouldSpeculateArray()
- && at(node.child2()).shouldSpeculateArrayOrOther()) {
- compilePeepHoleObjectToObjectOrOtherEquality(
- node.child1(), node.child2(), branchNodeIndex,
- &JSArray::s_info, isArraySpeculation);
- } else if (at(node.child1()).shouldSpeculateArrayOrOther()
- && at(node.child2()).shouldSpeculateArray()) {
- compilePeepHoleObjectToObjectOrOtherEquality(
- node.child2(), node.child1(), branchNodeIndex,
- &JSArray::s_info, isArraySpeculation);
- } else {
+ if (at(node.child1()).shouldSpeculateString() || at(node.child2()).shouldSpeculateString()) {
+ nonSpeculativePeepholeBranch(node, branchNodeIndex, condition, operation);
+ return true;
+ }
+ if (at(node.child1()).shouldSpeculateNonStringCell() && at(node.child2()).shouldSpeculateNonStringCellOrOther())
+ compilePeepHoleObjectToObjectOrOtherEquality(node.child1(), node.child2(), branchNodeIndex);
+ else if (at(node.child1()).shouldSpeculateNonStringCellOrOther() && at(node.child2()).shouldSpeculateNonStringCell())
+ compilePeepHoleObjectToObjectOrOtherEquality(node.child2(), node.child1(), branchNodeIndex);
+ else if (at(node.child1()).shouldSpeculateNonStringCell() && at(node.child2()).shouldSpeculateNonStringCell())
+ compilePeepHoleObjectEquality(node, branchNodeIndex);
+ else {
nonSpeculativePeepholeBranch(node, branchNodeIndex, condition, operation);
return true;
}
@@ -1461,51 +1484,6 @@ void SpeculativeJIT::checkArgumentTypes()
m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), temp.gpr());
speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), TrustedImm32(static_cast<int32_t>(~1))));
- } else if (isInt8ArraySpeculation(predictedType)) {
- GPRTemporary temp(this);
- m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->int8ArrayDescriptor().m_classInfo)));
- } else if (isInt16ArraySpeculation(predictedType)) {
- GPRTemporary temp(this);
- m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->int16ArrayDescriptor().m_classInfo)));
- } else if (isInt32ArraySpeculation(predictedType)) {
- GPRTemporary temp(this);
- m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->int32ArrayDescriptor().m_classInfo)));
- } else if (isUint8ArraySpeculation(predictedType)) {
- GPRTemporary temp(this);
- m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint8ArrayDescriptor().m_classInfo)));
- } else if (isUint8ClampedArraySpeculation(predictedType)) {
- GPRTemporary temp(this);
- m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint8ClampedArrayDescriptor().m_classInfo)));
- } else if (isUint16ArraySpeculation(predictedType)) {
- GPRTemporary temp(this);
- m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint16ArrayDescriptor().m_classInfo)));
- } else if (isUint32ArraySpeculation(predictedType)) {
- GPRTemporary temp(this);
- m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint32ArrayDescriptor().m_classInfo)));
- } else if (isFloat32ArraySpeculation(predictedType)) {
- GPRTemporary temp(this);
- m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->float32ArrayDescriptor().m_classInfo)));
- } else if (isFloat64ArraySpeculation(predictedType)) {
- GPRTemporary temp(this);
- m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->float64ArrayDescriptor().m_classInfo)));
} else if (isCellSpeculation(predictedType))
speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, JITCompiler::addressFor(virtualRegister), GPRInfo::tagMaskRegister));
#else
@@ -1513,61 +1491,7 @@ void SpeculativeJIT::checkArgumentTypes()
speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag)));
else if (isBooleanSpeculation(predictedType))
speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag)));
- else if (isInt8ArraySpeculation(predictedType)) {
- GPRTemporary temp(this);
- m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
- m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->int8ArrayDescriptor().m_classInfo)));
- } else if (isInt16ArraySpeculation(predictedType)) {
- GPRTemporary temp(this);
- m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
- m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->int16ArrayDescriptor().m_classInfo)));
- } else if (isInt32ArraySpeculation(predictedType)) {
- GPRTemporary temp(this);
- m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
- m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->int32ArrayDescriptor().m_classInfo)));
- } else if (isUint8ArraySpeculation(predictedType)) {
- GPRTemporary temp(this);
- m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
- m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint8ArrayDescriptor().m_classInfo)));
- } else if (isUint8ClampedArraySpeculation(predictedType)) {
- GPRTemporary temp(this);
- m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
- m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint8ClampedArrayDescriptor().m_classInfo)));
- } else if (isUint16ArraySpeculation(predictedType)) {
- GPRTemporary temp(this);
- m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
- m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint16ArrayDescriptor().m_classInfo)));
- } else if (isUint32ArraySpeculation(predictedType)) {
- GPRTemporary temp(this);
- m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
- m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint32ArrayDescriptor().m_classInfo)));
- } else if (isFloat32ArraySpeculation(predictedType)) {
- GPRTemporary temp(this);
- m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
- m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->float32ArrayDescriptor().m_classInfo)));
- } else if (isFloat64ArraySpeculation(predictedType)) {
- GPRTemporary temp(this);
- m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
- m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
- speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->float64ArrayDescriptor().m_classInfo)));
- } else if (isCellSpeculation(predictedType))
+ else if (isCellSpeculation(predictedType))
speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::CellTag)));
#endif
}
@@ -2146,6 +2070,9 @@ void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor&
void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor& descriptor, GPRReg base, GPRReg property, Node& node, size_t elementSize, TypedArraySignedness signedness, TypedArrayRounding rounding)
{
+ StorageOperand storage(this, m_jit.graph().varArgChild(node, 3));
+ GPRReg storageReg = storage.gpr();
+
Edge valueUse = m_jit.graph().varArgChild(node, 2);
GPRTemporary value;
@@ -2213,10 +2140,7 @@ void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor&
}
ASSERT_UNUSED(valueGPR, valueGPR != property);
ASSERT(valueGPR != base);
- GPRTemporary storage(this);
- GPRReg storageReg = storage.gpr();
ASSERT(valueGPR != storageReg);
- m_jit.loadPtr(MacroAssembler::Address(base, descriptor.m_storageOffset), storageReg);
MacroAssembler::Jump outOfBounds;
if (node.op() == PutByVal)
outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, property, MacroAssembler::Address(base, descriptor.m_lengthOffset));
@@ -2278,6 +2202,9 @@ void SpeculativeJIT::compileGetByValOnFloatTypedArray(const TypedArrayDescriptor
void SpeculativeJIT::compilePutByValForFloatTypedArray(const TypedArrayDescriptor& descriptor, GPRReg base, GPRReg property, Node& node, size_t elementSize)
{
+ StorageOperand storage(this, m_jit.graph().varArgChild(node, 3));
+ GPRReg storageReg = storage.gpr();
+
Edge baseUse = m_jit.graph().varArgChild(node, 0);
Edge valueUse = m_jit.graph().varArgChild(node, 2);
@@ -2287,10 +2214,6 @@ void SpeculativeJIT::compilePutByValForFloatTypedArray(const TypedArrayDescripto
GPRTemporary result(this);
- GPRTemporary storage(this);
- GPRReg storageReg = storage.gpr();
-
- m_jit.loadPtr(MacroAssembler::Address(base, descriptor.m_storageOffset), storageReg);
MacroAssembler::Jump outOfBounds;
if (node.op() == PutByVal)
outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, property, MacroAssembler::Address(base, descriptor.m_lengthOffset));
@@ -2892,45 +2815,23 @@ bool SpeculativeJIT::compare(Node& node, MacroAssembler::RelationalCondition con
}
if (node.op() == CompareEq) {
- if (Node::shouldSpeculateFinalObject(at(node.child1()), at(node.child2()))) {
- compileObjectEquality(node, &JSFinalObject::s_info, isFinalObjectSpeculation);
- return false;
- }
-
- if (Node::shouldSpeculateArray(at(node.child1()), at(node.child2()))) {
- compileObjectEquality(node, &JSArray::s_info, isArraySpeculation);
- return false;
- }
-
- if (at(node.child1()).shouldSpeculateFinalObject()
- && at(node.child2()).shouldSpeculateFinalObjectOrOther()) {
- compileObjectToObjectOrOtherEquality(
- node.child1(), node.child2(), &JSFinalObject::s_info,
- isFinalObjectSpeculation);
+ if (at(node.child1()).shouldSpeculateString() || at(node.child2()).shouldSpeculateString()) {
+ nonSpeculativeNonPeepholeCompare(node, condition, operation);
return false;
}
- if (at(node.child1()).shouldSpeculateFinalObjectOrOther()
- && at(node.child2()).shouldSpeculateFinalObject()) {
- compileObjectToObjectOrOtherEquality(
- node.child2(), node.child1(), &JSFinalObject::s_info,
- isFinalObjectSpeculation);
+ if (at(node.child1()).shouldSpeculateNonStringCell() && at(node.child2()).shouldSpeculateNonStringCellOrOther()) {
+ compileObjectToObjectOrOtherEquality(node.child1(), node.child2());
return false;
}
- if (at(node.child1()).shouldSpeculateArray()
- && at(node.child2()).shouldSpeculateArrayOrOther()) {
- compileObjectToObjectOrOtherEquality(
- node.child1(), node.child2(), &JSArray::s_info,
- isArraySpeculation);
+ if (at(node.child1()).shouldSpeculateNonStringCellOrOther() && at(node.child2()).shouldSpeculateNonStringCell()) {
+ compileObjectToObjectOrOtherEquality(node.child2(), node.child1());
return false;
}
-
- if (at(node.child1()).shouldSpeculateArrayOrOther()
- && at(node.child2()).shouldSpeculateArray()) {
- compileObjectToObjectOrOtherEquality(
- node.child2(), node.child1(), &JSArray::s_info,
- isArraySpeculation);
+
+ if (at(node.child1()).shouldSpeculateNonStringCell() && at(node.child2()).shouldSpeculateNonStringCell()) {
+ compileObjectEquality(node);
return false;
}
}
@@ -3063,36 +2964,20 @@ bool SpeculativeJIT::compileStrictEq(Node& node)
return false;
}
- // 4) If the operands are predicted final object or array, then do a final object
- // or array comparison.
-
- if (Node::shouldSpeculateFinalObject(at(node.child1()), at(node.child2()))) {
+ if (at(node.child1()).shouldSpeculateString() || at(node.child2()).shouldSpeculateString())
+ return nonSpeculativeStrictEq(node);
+ if (at(node.child1()).shouldSpeculateNonStringCell() && at(node.child2()).shouldSpeculateNonStringCell()) {
unsigned branchIndexInBlock = detectPeepHoleBranch();
if (branchIndexInBlock != UINT_MAX) {
NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
- compilePeepHoleObjectEquality(node, branchNodeIndex, &JSFinalObject::s_info, isFinalObjectSpeculation);
+ compilePeepHoleObjectEquality(node, branchNodeIndex);
use(node.child1());
use(node.child2());
m_indexInBlock = branchIndexInBlock;
m_compileIndex = branchNodeIndex;
return true;
}
- compileObjectEquality(node, &JSFinalObject::s_info, isFinalObjectSpeculation);
- return false;
- }
-
- if (Node::shouldSpeculateArray(at(node.child1()), at(node.child2()))) {
- unsigned branchIndexInBlock = detectPeepHoleBranch();
- if (branchIndexInBlock != UINT_MAX) {
- NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
- compilePeepHoleObjectEquality(node, branchNodeIndex, &JSArray::s_info, isArraySpeculation);
- use(node.child1());
- use(node.child2());
- m_indexInBlock = branchIndexInBlock;
- m_compileIndex = branchNodeIndex;
- return true;
- }
- compileObjectEquality(node, &JSArray::s_info, isArraySpeculation);
+ compileObjectEquality(node);
return false;
}
@@ -3109,8 +2994,7 @@ void SpeculativeJIT::compileGetIndexedPropertyStorage(Node& node)
GPRTemporary storage(this);
GPRReg storageReg = storage.gpr();
- const TypedArrayDescriptor* descriptor =
- speculateArray(node.arrayMode(), node.child1(), baseReg);
+ const TypedArrayDescriptor* descriptor = typedArrayDescriptor(node.arrayMode());
switch (node.arrayMode()) {
case Array::String:
@@ -3156,15 +3040,8 @@ void SpeculativeJIT::compileGetByValOnArguments(Node& node)
if (!m_compileOkay)
return;
-
- if (!isArgumentsSpeculation(m_state.forNode(node.child1()).m_type)) {
- speculationCheck(
- BadType, JSValueSource::unboxedCell(baseReg), node.child1(),
- m_jit.branchPtr(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(baseReg, JSCell::classInfoOffset()),
- MacroAssembler::TrustedImmPtr(&Arguments::s_info)));
- }
+
+ ASSERT(modeAlreadyChecked(m_state.forNode(node.child1()), Array::Arguments));
m_jit.loadPtr(
MacroAssembler::Address(baseReg, Arguments::offsetOfData()),
@@ -3225,14 +3102,7 @@ void SpeculativeJIT::compileGetArgumentsLength(Node& node)
if (!m_compileOkay)
return;
- if (!isArgumentsSpeculation(m_state.forNode(node.child1()).m_type)) {
- speculationCheck(
- BadType, JSValueSource::unboxedCell(baseReg), node.child1(),
- m_jit.branchPtr(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(baseReg, JSCell::classInfoOffset()),
- MacroAssembler::TrustedImmPtr(&Arguments::s_info)));
- }
+ ASSERT(modeAlreadyChecked(m_state.forNode(node.child1()), Array::Arguments));
m_jit.loadPtr(
MacroAssembler::Address(baseReg, Arguments::offsetOfData()),
@@ -3252,33 +3122,40 @@ void SpeculativeJIT::compileGetArgumentsLength(Node& node)
void SpeculativeJIT::compileGetArrayLength(Node& node)
{
- SpeculateCellOperand base(this, node.child1());
- GPRTemporary result(this);
-
- GPRReg baseGPR = base.gpr();
- GPRReg resultGPR = result.gpr();
-
- const TypedArrayDescriptor* descriptor =
- speculateArray(node.arrayMode(), node.child1(), baseGPR);
+ const TypedArrayDescriptor* descriptor = typedArrayDescriptor(node.arrayMode());
switch (node.arrayMode()) {
case Array::JSArray:
- case Array::JSArrayOutOfBounds:
- m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), resultGPR);
- m_jit.load32(MacroAssembler::Address(resultGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), resultGPR);
+ case Array::JSArrayOutOfBounds: {
+ StorageOperand storage(this, node.child2());
+ GPRTemporary result(this, storage);
+ GPRReg storageReg = storage.gpr();
+ GPRReg resultReg = result.gpr();
+ m_jit.load32(MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)), resultReg);
- speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, resultGPR, MacroAssembler::TrustedImm32(0)));
+ speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, resultReg, MacroAssembler::TrustedImm32(0)));
- integerResult(resultGPR, m_compileIndex);
+ integerResult(resultReg, m_compileIndex);
break;
- case Array::String:
+ }
+ case Array::String: {
+ SpeculateCellOperand base(this, node.child1());
+ GPRTemporary result(this, base);
+ GPRReg baseGPR = base.gpr();
+ GPRReg resultGPR = result.gpr();
m_jit.load32(MacroAssembler::Address(baseGPR, JSString::offsetOfLength()), resultGPR);
integerResult(resultGPR, m_compileIndex);
break;
- case Array::Arguments:
+ }
+ case Array::Arguments: {
compileGetArgumentsLength(node);
break;
+ }
default:
+ SpeculateCellOperand base(this, node.child1());
+ GPRTemporary result(this, base);
+ GPRReg baseGPR = base.gpr();
+ GPRReg resultGPR = result.gpr();
ASSERT(descriptor);
m_jit.load32(MacroAssembler::Address(baseGPR, descriptor->m_lengthOffset), resultGPR);
integerResult(resultGPR, m_compileIndex);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 69a30a974..f7b125e1b 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -1198,6 +1198,11 @@ public:
m_jit.setupArgumentsWithExecState(arg1);
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(J_DFGOperation_EAZ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(J_DFGOperation_ESt operation, GPRReg result, Structure* structure)
{
m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure));
@@ -1481,6 +1486,11 @@ public:
m_jit.setupArgumentsWithExecState(arg1);
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
+ JITCompiler::Call callOperation(J_DFGOperation_EAZ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2);
+ return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+ }
JITCompiler::Call callOperation(J_DFGOperation_ESt operation, GPRReg resultTag, GPRReg resultPayload, Structure* structure)
{
m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure));
@@ -1825,9 +1835,23 @@ public:
return call;
}
#elif CPU(ARM)
+#if CPU(ARM_HARDFP)
JITCompiler::Call appendCallWithExceptionCheckSetResult(const FunctionPtr& function, FPRReg result)
{
JITCompiler::Call call = appendCallWithExceptionCheck(function);
+ m_jit.moveDouble(result, FPRInfo::argumentFPR0);
+ return call;
+ }
+ JITCompiler::Call appendCallSetResult(const FunctionPtr& function, FPRReg result)
+ {
+ JITCompiler::Call call = m_jit.appendCall(function);
+ m_jit.moveDouble(result, FPRInfo::argumentFPR0);
+ return call;
+ }
+#else
+ JITCompiler::Call appendCallWithExceptionCheckSetResult(const FunctionPtr& function, FPRReg result)
+ {
+ JITCompiler::Call call = appendCallWithExceptionCheck(function);
m_jit.assembler().vmov(result, GPRInfo::returnValueGPR, GPRInfo::returnValueGPR2);
return call;
}
@@ -1837,6 +1861,7 @@ public:
m_jit.assembler().vmov(result, GPRInfo::returnValueGPR, GPRInfo::returnValueGPR2);
return call;
}
+#endif // CPU(ARM_HARDFP)
#else
JITCompiler::Call appendCallWithExceptionCheckSetResult(const FunctionPtr& function, FPRReg result)
{
@@ -2054,16 +2079,14 @@ public:
bool compilePeepHoleBranch(Node&, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, S_DFGOperation_EJJ);
void compilePeepHoleIntegerBranch(Node&, NodeIndex branchNodeIndex, JITCompiler::RelationalCondition);
void compilePeepHoleDoubleBranch(Node&, NodeIndex branchNodeIndex, JITCompiler::DoubleCondition);
- void compilePeepHoleObjectEquality(Node&, NodeIndex branchNodeIndex, const ClassInfo*, SpeculatedTypeChecker);
- void compilePeepHoleObjectToObjectOrOtherEquality(
- Edge leftChild, Edge rightChild, NodeIndex branchNodeIndex, const ClassInfo*, SpeculatedTypeChecker);
- void compileObjectEquality(Node&, const ClassInfo*, SpeculatedTypeChecker);
- void compileObjectToObjectOrOtherEquality(
- Edge leftChild, Edge rightChild, const ClassInfo*, SpeculatedTypeChecker);
+ void compilePeepHoleObjectEquality(Node&, NodeIndex branchNodeIndex);
+ void compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild, NodeIndex branchNodeIndex);
+ void compileObjectEquality(Node&);
+ void compileObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild);
void compileValueAdd(Node&);
- void compileObjectOrOtherLogicalNot(Edge value, const ClassInfo*, bool needSpeculationCheck);
+ void compileNonStringCellOrOtherLogicalNot(Edge value, bool needSpeculationCheck);
void compileLogicalNot(Node&);
- void emitObjectOrOtherBranch(Edge value, BlockIndex taken, BlockIndex notTaken, const ClassInfo*, bool needSpeculationCheck);
+ void emitNonStringCellOrOtherBranch(Edge value, BlockIndex taken, BlockIndex notTaken, bool needSpeculationCheck);
void emitBranch(Node&);
void compileIntegerCompare(Node&, MacroAssembler::RelationalCondition);
@@ -2197,7 +2220,7 @@ public:
const TypedArrayDescriptor* typedArrayDescriptor(Array::Mode);
- const TypedArrayDescriptor* speculateArray(Array::Mode, Edge baseEdge, GPRReg baseReg);
+ void checkArray(Node&);
template<bool strict>
GPRReg fillSpeculateIntInternal(NodeIndex, DataFormat& returnFormat);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 846d078ba..34b8dae46 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -1048,7 +1048,7 @@ void SpeculativeJIT::emitCall(Node& node)
slowPath.append(m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleePayloadGPR, targetToCheck));
slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, calleeTagGPR, TrustedImm32(JSValue::CellTag)));
- m_jit.loadPtr(MacroAssembler::Address(calleePayloadGPR, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), resultPayloadGPR);
+ m_jit.loadPtr(MacroAssembler::Address(calleePayloadGPR, OBJECT_OFFSETOF(JSFunction, m_scope)), resultPayloadGPR);
m_jit.storePtr(resultPayloadGPR, MacroAssembler::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ScopeChain + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
m_jit.store32(MacroAssembler::TrustedImm32(JSValue::CellTag), MacroAssembler::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ScopeChain + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
@@ -1489,17 +1489,53 @@ JITCompiler::Jump SpeculativeJIT::convertToDouble(JSValueOperand& op, FPRReg res
return notNumber;
}
-void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInfo, SpeculatedTypeChecker speculatedTypeChecker)
+void SpeculativeJIT::compileObjectEquality(Node& node)
{
SpeculateCellOperand op1(this, node.child1());
SpeculateCellOperand op2(this, node.child2());
GPRReg op1GPR = op1.gpr();
GPRReg op2GPR = op2.gpr();
- if (!speculatedTypeChecker(m_state.forNode(node.child1()).m_type))
- speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo)));
- if (!speculatedTypeChecker(m_state.forNode(node.child2()).m_type))
- speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node.child2(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op2GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo)));
+ if (m_jit.graph().globalObjectFor(node.codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
+ m_jit.graph().globalObjectFor(node.codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+ speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node.child1(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op1GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node.child2(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op2GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ } else {
+ GPRTemporary structure(this);
+ GPRReg structureGPR = structure.gpr();
+
+ m_jit.loadPtr(MacroAssembler::Address(op1GPR, JSCell::structureOffset()), structureGPR);
+ speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node.child1(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node.child1(),
+ m_jit.branchTest8(
+ MacroAssembler::NonZero,
+ MacroAssembler::Address(structureGPR, Structure::typeInfoFlagsOffset()),
+ MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
+
+ m_jit.loadPtr(MacroAssembler::Address(op2GPR, JSCell::structureOffset()), structureGPR);
+ speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node.child2(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node.child2(),
+ m_jit.branchTest8(
+ MacroAssembler::NonZero,
+ MacroAssembler::Address(structureGPR, Structure::typeInfoFlagsOffset()),
+ MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
+ }
GPRTemporary resultPayload(this, op2);
GPRReg resultPayloadGPR = resultPayload.gpr();
@@ -1514,10 +1550,9 @@ void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInf
booleanResult(resultPayloadGPR, m_compileIndex);
}
-void SpeculativeJIT::compileObjectToObjectOrOtherEquality(
- Edge leftChild, Edge rightChild,
- const ClassInfo* classInfo, SpeculatedTypeChecker speculatedTypeChecker)
+void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild)
{
+ Node& leftNode = m_jit.graph()[leftChild.index()];
SpeculateCellOperand op1(this, leftChild);
JSValueOperand op2(this, rightChild);
GPRTemporary result(this);
@@ -1527,31 +1562,59 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality(
GPRReg op2PayloadGPR = op2.payloadGPR();
GPRReg resultGPR = result.gpr();
- if (!speculatedTypeChecker(m_state.forNode(leftChild).m_type)) {
- speculationCheck(
- BadType, JSValueSource::unboxedCell(op1GPR), leftChild.index(),
+ if (m_jit.graph().globalObjectFor(leftNode.codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
+ m_jit.graph().globalObjectFor(leftNode.codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+ speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild.index(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op1GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ } else {
+ GPRTemporary structure(this);
+ GPRReg structureGPR = structure.gpr();
+
+ m_jit.loadPtr(MacroAssembler::Address(op1GPR, JSCell::structureOffset()), structureGPR);
+ speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild.index(),
m_jit.branchPtr(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(op1GPR, JSCell::classInfoOffset()),
- MacroAssembler::TrustedImmPtr(classInfo)));
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild.index(),
+ m_jit.branchTest8(
+ MacroAssembler::NonZero,
+ MacroAssembler::Address(structureGPR, Structure::typeInfoFlagsOffset()),
+ MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
}
+
// It seems that most of the time when programs do a == b where b may be either null/undefined
// or an object, b is usually an object. Balance the branches to make that case fast.
MacroAssembler::Jump rightNotCell =
m_jit.branch32(MacroAssembler::NotEqual, op2TagGPR, TrustedImm32(JSValue::CellTag));
- // We know that within this branch, rightChild must be a cell. If the CFA can tell us that the
- // proof, when filtered on cell, demonstrates that we have an object of the desired type
- // (speculationCheck() will test for FinalObject or Array, currently), then we can skip the
- // speculation.
- if (!speculatedTypeChecker(m_state.forNode(rightChild).m_type & SpecCell)) {
- speculationCheck(
- BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild.index(),
+ // We know that within this branch, rightChild must be a cell.
+ if (m_jit.graph().globalObjectFor(leftNode.codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
+ m_jit.graph().globalObjectFor(leftNode.codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+ speculationCheck(BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild.index(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op2PayloadGPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ } else {
+ GPRTemporary structure(this);
+ GPRReg structureGPR = structure.gpr();
+
+ m_jit.loadPtr(MacroAssembler::Address(op2PayloadGPR, JSCell::structureOffset()), structureGPR);
+ speculationCheck(BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild.index(),
m_jit.branchPtr(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(op2PayloadGPR, JSCell::classInfoOffset()),
- MacroAssembler::TrustedImmPtr(classInfo)));
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ speculationCheck(BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild.index(),
+ m_jit.branchTest8(
+ MacroAssembler::NonZero,
+ MacroAssembler::Address(structureGPR, Structure::typeInfoFlagsOffset()),
+ MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
}
// At this point we know that we can perform a straight-forward equality comparison on pointer
@@ -1585,9 +1648,7 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality(
booleanResult(resultGPR, m_compileIndex);
}
-void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(
- Edge leftChild, Edge rightChild, NodeIndex branchNodeIndex,
- const ClassInfo* classInfo, SpeculatedTypeChecker speculatedTypeChecker)
+void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild, NodeIndex branchNodeIndex)
{
Node& branchNode = at(branchNodeIndex);
BlockIndex taken = branchNode.takenBlockIndex();
@@ -1602,13 +1663,28 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(
GPRReg op2PayloadGPR = op2.payloadGPR();
GPRReg resultGPR = result.gpr();
- if (!speculatedTypeChecker(m_state.forNode(leftChild).m_type)) {
- speculationCheck(
- BadType, JSValueSource::unboxedCell(op1GPR), leftChild.index(),
+ if (m_jit.graph().globalObjectFor(branchNode.codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
+ m_jit.graph().globalObjectFor(branchNode.codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+ speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild.index(),
m_jit.branchPtr(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(op1GPR, JSCell::classInfoOffset()),
- MacroAssembler::TrustedImmPtr(classInfo)));
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op1GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ } else {
+ GPRTemporary structure(this);
+ GPRReg structureGPR = structure.gpr();
+
+ m_jit.loadPtr(MacroAssembler::Address(op1GPR, JSCell::structureOffset()), structureGPR);
+ speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild.index(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild.index(),
+ m_jit.branchTest8(
+ MacroAssembler::NonZero,
+ MacroAssembler::Address(structureGPR, Structure::typeInfoFlagsOffset()),
+ MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
}
// It seems that most of the time when programs do a == b where b may be either null/undefined
@@ -1616,17 +1692,29 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(
MacroAssembler::Jump rightNotCell =
m_jit.branch32(MacroAssembler::NotEqual, op2TagGPR, TrustedImm32(JSValue::CellTag));
- // We know that within this branch, rightChild must be a cell. If the CFA can tell us that the
- // proof, when filtered on cell, demonstrates that we have an object of the desired type
- // (speculationCheck() will test for FinalObject or Array, currently), then we can skip the
- // speculation.
- if (!speculatedTypeChecker(m_state.forNode(rightChild).m_type & SpecCell)) {
- speculationCheck(
- BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild.index(),
+ // We know that within this branch, rightChild must be a cell.
+ if (m_jit.graph().globalObjectFor(branchNode.codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
+ m_jit.graph().globalObjectFor(branchNode.codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+ speculationCheck(BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild.index(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op2PayloadGPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ } else {
+ GPRTemporary structure(this);
+ GPRReg structureGPR = structure.gpr();
+
+ m_jit.loadPtr(MacroAssembler::Address(op2PayloadGPR, JSCell::structureOffset()), structureGPR);
+ speculationCheck(BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild.index(),
m_jit.branchPtr(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(op2PayloadGPR, JSCell::classInfoOffset()),
- MacroAssembler::TrustedImmPtr(classInfo)));
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ speculationCheck(BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild.index(),
+ m_jit.branchTest8(
+ MacroAssembler::NonZero,
+ MacroAssembler::Address(structureGPR, Structure::typeInfoFlagsOffset()),
+ MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
}
// At this point we know that we can perform a straight-forward equality comparison on pointer
@@ -1703,7 +1791,7 @@ void SpeculativeJIT::compileValueAdd(Node& node)
jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
}
-void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse, const ClassInfo* classInfo, bool needSpeculationCheck)
+void SpeculativeJIT::compileNonStringCellOrOtherLogicalNot(Edge nodeUse, bool needSpeculationCheck)
{
JSValueOperand value(this, nodeUse);
GPRTemporary resultPayload(this);
@@ -1712,8 +1800,44 @@ void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse, const ClassInf
GPRReg resultPayloadGPR = resultPayload.gpr();
MacroAssembler::Jump notCell = m_jit.branch32(MacroAssembler::NotEqual, valueTagGPR, TrustedImm32(JSValue::CellTag));
- if (needSpeculationCheck)
- speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(valuePayloadGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo)));
+ if (m_jit.graph().globalObjectFor(m_jit.graph()[nodeUse.index()].codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
+ m_jit.graph().globalObjectFor(m_jit.graph()[nodeUse.index()].codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+
+ if (needSpeculationCheck) {
+ speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse,
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(valuePayloadGPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ }
+ } else {
+ GPRTemporary structure(this);
+ GPRReg structureGPR = structure.gpr();
+
+ m_jit.loadPtr(MacroAssembler::Address(valuePayloadGPR, JSCell::structureOffset()), structureGPR);
+
+ if (needSpeculationCheck) {
+ speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse,
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ }
+
+ MacroAssembler::Jump isNotMasqueradesAsUndefined =
+ m_jit.branchTest8(
+ MacroAssembler::Zero,
+ MacroAssembler::Address(structureGPR, Structure::typeInfoFlagsOffset()),
+ MacroAssembler::TrustedImm32(MasqueradesAsUndefined));
+
+ speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse,
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(structureGPR, Structure::globalObjectOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.graph().globalObjectFor(m_jit.graph()[nodeUse.index()].codeOrigin))));
+
+ isNotMasqueradesAsUndefined.link(&m_jit);
+ }
m_jit.move(TrustedImm32(0), resultPayloadGPR);
MacroAssembler::Jump done = m_jit.jump();
@@ -1723,7 +1847,11 @@ void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse, const ClassInf
if (needSpeculationCheck) {
m_jit.move(valueTagGPR, resultPayloadGPR);
m_jit.or32(TrustedImm32(1), resultPayloadGPR);
- speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, m_jit.branch32(MacroAssembler::NotEqual, resultPayloadGPR, TrustedImm32(JSValue::NullTag)));
+ speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse,
+ m_jit.branch32(
+ MacroAssembler::NotEqual,
+ resultPayloadGPR,
+ TrustedImm32(JSValue::NullTag)));
}
m_jit.move(TrustedImm32(1), resultPayloadGPR);
@@ -1741,12 +1869,9 @@ void SpeculativeJIT::compileLogicalNot(Node& node)
booleanResult(result.gpr(), m_compileIndex);
return;
}
- if (at(node.child1()).shouldSpeculateFinalObjectOrOther()) {
- compileObjectOrOtherLogicalNot(node.child1(), &JSFinalObject::s_info, !isFinalObjectOrOtherSpeculation(m_state.forNode(node.child1()).m_type));
- return;
- }
- if (at(node.child1()).shouldSpeculateArrayOrOther()) {
- compileObjectOrOtherLogicalNot(node.child1(), &JSArray::s_info, !isArrayOrOtherSpeculation(m_state.forNode(node.child1()).m_type));
+ if (at(node.child1()).shouldSpeculateNonStringCellOrOther()) {
+ compileNonStringCellOrOtherLogicalNot(node.child1(),
+ !isNonStringCellOrOtherSpeculation(m_state.forNode(node.child1()).m_type));
return;
}
if (at(node.child1()).shouldSpeculateInteger()) {
@@ -1789,7 +1914,7 @@ void SpeculativeJIT::compileLogicalNot(Node& node)
booleanResult(resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly);
}
-void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse, BlockIndex taken, BlockIndex notTaken, const ClassInfo* classInfo, bool needSpeculationCheck)
+void SpeculativeJIT::emitNonStringCellOrOtherBranch(Edge nodeUse, BlockIndex taken, BlockIndex notTaken, bool needSpeculationCheck)
{
JSValueOperand value(this, nodeUse);
GPRTemporary scratch(this);
@@ -1798,8 +1923,37 @@ void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse, BlockIndex taken, Blo
GPRReg scratchGPR = scratch.gpr();
MacroAssembler::Jump notCell = m_jit.branch32(MacroAssembler::NotEqual, valueTagGPR, TrustedImm32(JSValue::CellTag));
- if (needSpeculationCheck)
- speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(valuePayloadGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo)));
+ if (m_jit.graph().globalObjectFor(m_jit.graph()[nodeUse.index()].codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
+ m_jit.graph().globalObjectFor(m_jit.graph()[nodeUse.index()].codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+
+ if (needSpeculationCheck) {
+ speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse,
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(valuePayloadGPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ }
+ } else {
+ m_jit.loadPtr(MacroAssembler::Address(valuePayloadGPR, JSCell::structureOffset()), scratchGPR);
+
+ if (needSpeculationCheck) {
+ speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse.index(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ scratchGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ }
+
+ JITCompiler::Jump isNotMasqueradesAsUndefined = m_jit.branchTest8(JITCompiler::Zero, MacroAssembler::Address(scratchGPR, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined));
+
+ speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse.index(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(scratchGPR, Structure::globalObjectOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.graph().globalObjectFor(m_jit.graph()[nodeUse.index()].codeOrigin))));
+
+ isNotMasqueradesAsUndefined.link(&m_jit);
+ }
jump(taken, ForceJump);
notCell.link(&m_jit);
@@ -1836,10 +1990,9 @@ void SpeculativeJIT::emitBranch(Node& node)
jump(notTaken);
noResult(m_compileIndex);
- } else if (at(node.child1()).shouldSpeculateFinalObjectOrOther()) {
- emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSFinalObject::s_info, !isFinalObjectOrOtherSpeculation(m_state.forNode(node.child1()).m_type));
- } else if (at(node.child1()).shouldSpeculateArrayOrOther()) {
- emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSArray::s_info, !isArrayOrOtherSpeculation(m_state.forNode(node.child1()).m_type));
+ } else if (at(node.child1()).shouldSpeculateNonStringCellOrOther()) {
+ emitNonStringCellOrOtherBranch(node.child1(), taken, notTaken,
+ !isNonStringCellOrOtherSpeculation(m_state.forNode(node.child1()).m_type));
} else if (at(node.child1()).shouldSpeculateNumber()) {
if (at(node.child1()).shouldSpeculateInteger()) {
bool invert = false;
@@ -2373,6 +2526,11 @@ void SpeculativeJIT::compile(Node& node)
compileGetByValOnString(node);
break;
}
+
+ case CheckArray: {
+ checkArray(node);
+ break;
+ }
case GetByVal: {
switch (node.arrayMode()) {
@@ -2396,8 +2554,7 @@ void SpeculativeJIT::compile(Node& node)
jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
break;
}
- case Array::JSArray:
- case Array::JSArrayOutOfBounds: {
+ case Array::JSArray: {
SpeculateStrictInt32Operand property(this, node.child2());
StorageOperand storage(this, node.child3());
GPRReg propertyReg = property.gpr();
@@ -2412,19 +2569,59 @@ void SpeculativeJIT::compile(Node& node)
SpeculateCellOperand base(this, node.child1());
GPRReg baseReg = base.gpr();
// We've already speculated that it's some kind of array, at this point.
- speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())));
+ speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())));
}
GPRTemporary resultTag(this);
GPRTemporary resultPayload(this);
m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag.gpr());
- speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag)));
+ speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag)));
m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr());
-
+
jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
break;
}
+ case Array::JSArrayOutOfBounds: {
+ SpeculateCellOperand base(this, node.child1());
+ SpeculateStrictInt32Operand property(this, node.child2());
+ StorageOperand storage(this, node.child3());
+ GPRReg propertyReg = property.gpr();
+ GPRReg storageReg = storage.gpr();
+
+ if (!m_compileOkay)
+ return;
+
+ GPRTemporary resultTag(this);
+ GPRTemporary resultPayload(this);
+ GPRReg resultTagReg = resultTag.gpr();
+ GPRReg resultPayloadReg = resultPayload.gpr();
+
+ // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
+ // If we have predicted the base to be type array, we can skip the check.
+ GPRReg baseReg = base.gpr();
+ // We've already speculated that it's some kind of array, at this point.
+ JITCompiler::Jump outOfBounds = m_jit.branch32(
+ MacroAssembler::AboveOrEqual, propertyReg,
+ MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()));
+
+ m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTagReg);
+ JITCompiler::Jump hole = m_jit.branch32(
+ MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag));
+ m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayloadReg);
+
+ JITCompiler::JumpList slowCases;
+ slowCases.append(outOfBounds);
+ slowCases.append(hole);
+ addSlowPathGenerator(
+ slowPathCall(
+ slowCases, this, operationGetByValArrayInt,
+ JSValueRegs(resultTagReg, resultPayloadReg),
+ baseReg, propertyReg));
+
+ jsValueResult(resultTagReg, resultPayloadReg, m_compileIndex);
+ break;
+ }
case Array::String:
compileGetByValOnString(node);
break;
@@ -2470,6 +2667,7 @@ void SpeculativeJIT::compile(Node& node)
Edge child1 = m_jit.graph().varArgChild(node, 0);
Edge child2 = m_jit.graph().varArgChild(node, 1);
Edge child3 = m_jit.graph().varArgChild(node, 2);
+ Edge child4 = m_jit.graph().varArgChild(node, 3);
Array::Mode arrayMode = modeForPut(node.arrayMode());
bool alreadyHandled = false;
@@ -2513,8 +2711,6 @@ void SpeculativeJIT::compile(Node& node)
GPRReg baseReg = base.gpr();
GPRReg propertyReg = property.gpr();
- speculateArray(arrayMode, child1, baseReg);
-
switch (arrayMode) {
case Array::JSArray:
case Array::JSArrayOutOfBounds: {
@@ -2531,13 +2727,11 @@ void SpeculativeJIT::compile(Node& node)
GPRReg scratchReg = scratch.gpr();
writeBarrier(baseReg, valueTagReg, child3, WriteBarrierForPropertyAccess, scratchReg);
}
+
+ StorageOperand storage(this, child4);
+ GPRReg storageReg = storage.gpr();
if (node.op() == PutByValAlias) {
- // Get the array storage.
- GPRTemporary storage(this);
- GPRReg storageReg = storage.gpr();
- m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
-
// Store the value to the array.
GPRReg propertyReg = property.gpr();
m_jit.store32(value.tagGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
@@ -2554,12 +2748,8 @@ void SpeculativeJIT::compile(Node& node)
base.use();
property.use();
value.use();
+ storage.use();
- // Get the array storage.
- GPRTemporary storage(this);
- GPRReg storageReg = storage.gpr();
- m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
-
// Check if we're writing to a hole; if so increment m_numValuesInVector.
MacroAssembler::Jump notHoleValue = m_jit.branch32(MacroAssembler::NotEqual, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag));
m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
@@ -2688,6 +2878,8 @@ void SpeculativeJIT::compile(Node& node)
}
case ArrayPush: {
+ ASSERT(modeIsJSArray(node.arrayMode()));
+
SpeculateCellOperand base(this, node.child1());
JSValueOperand value(this, node.child2());
GPRTemporary storageLength(this);
@@ -2697,17 +2889,14 @@ void SpeculativeJIT::compile(Node& node)
GPRReg valuePayloadGPR = value.payloadGPR();
GPRReg storageLengthGPR = storageLength.gpr();
- {
+ if (Heap::isWriteBarrierEnabled()) {
GPRTemporary scratch(this);
writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR);
}
- speculateArray(Array::JSArray, node.child1(), baseGPR);
-
- GPRTemporary storage(this);
+ StorageOperand storage(this, node.child3());
GPRReg storageGPR = storage.gpr();
- m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR);
m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
// Refuse to handle bizarre lengths.
@@ -2730,10 +2919,12 @@ void SpeculativeJIT::compile(Node& node)
}
case ArrayPop: {
+ ASSERT(modeIsJSArray(node.arrayMode()));
+
SpeculateCellOperand base(this, node.child1());
+ StorageOperand storage(this, node.child2());
GPRTemporary valueTag(this);
GPRTemporary valuePayload(this);
- GPRTemporary storage(this);
GPRTemporary storageLength(this);
GPRReg baseGPR = base.gpr();
@@ -2742,9 +2933,6 @@ void SpeculativeJIT::compile(Node& node)
GPRReg storageGPR = storage.gpr();
GPRReg storageLengthGPR = storageLength.gpr();
- speculateArray(Array::JSArray, node.child1(), baseGPR);
-
- m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR);
m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
JITCompiler::JumpList setUndefinedCases;
@@ -3163,38 +3351,36 @@ void SpeculativeJIT::compile(Node& node)
JITCompiler::Jump activationNotCreated;
if (checkTopLevel)
activationNotCreated = m_jit.branchTestPtr(JITCompiler::Zero, JITCompiler::addressFor(static_cast<VirtualRegister>(m_jit.codeBlock()->activationRegister())));
- m_jit.loadPtr(JITCompiler::Address(resultGPR, OBJECT_OFFSETOF(ScopeChainNode, next)), resultGPR);
+ m_jit.loadPtr(JITCompiler::Address(resultGPR, JSScope::offsetOfNext()), resultGPR);
activationNotCreated.link(&m_jit);
}
while (skip--)
- m_jit.loadPtr(JITCompiler::Address(resultGPR, OBJECT_OFFSETOF(ScopeChainNode, next)), resultGPR);
+ m_jit.loadPtr(JITCompiler::Address(resultGPR, JSScope::offsetOfNext()), resultGPR);
- m_jit.loadPtr(JITCompiler::Address(resultGPR, OBJECT_OFFSETOF(ScopeChainNode, object)), resultGPR);
-
cellResult(resultGPR, m_compileIndex);
break;
}
case GetScopedVar: {
- SpeculateCellOperand scopeChain(this, node.child1());
+ SpeculateCellOperand scope(this, node.child1());
GPRTemporary resultTag(this);
GPRTemporary resultPayload(this);
GPRReg resultTagGPR = resultTag.gpr();
GPRReg resultPayloadGPR = resultPayload.gpr();
- m_jit.loadPtr(JITCompiler::Address(scopeChain.gpr(), JSVariableObject::offsetOfRegisters()), resultPayloadGPR);
+ m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSVariableObject::offsetOfRegisters()), resultPayloadGPR);
m_jit.load32(JITCompiler::Address(resultPayloadGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
m_jit.load32(JITCompiler::Address(resultPayloadGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR);
jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex);
break;
}
case PutScopedVar: {
- SpeculateCellOperand scopeChain(this, node.child1());
+ SpeculateCellOperand scope(this, node.child1());
GPRTemporary scratchRegister(this);
GPRReg scratchGPR = scratchRegister.gpr();
- m_jit.loadPtr(JITCompiler::Address(scopeChain.gpr(), JSVariableObject::offsetOfRegisters()), scratchGPR);
+ m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSVariableObject::offsetOfRegisters()), scratchGPR);
JSValueOperand value(this, node.child2());
m_jit.store32(value.tagGPR(), JITCompiler::Address(scratchGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
m_jit.store32(value.payloadGPR(), JITCompiler::Address(scratchGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
- writeBarrier(scopeChain.gpr(), value.tagGPR(), node.child2(), WriteBarrierForVariableAccess, scratchGPR);
+ writeBarrier(scope.gpr(), value.tagGPR(), node.child2(), WriteBarrierForVariableAccess, scratchGPR);
noResult(m_compileIndex);
break;
}
@@ -3535,7 +3721,7 @@ void SpeculativeJIT::compile(Node& node)
JSValueOperand value(this, node.child1());
WatchpointSet* watchpointSet =
- m_jit.globalObjectFor(node.codeOrigin)->symbolTable().get(
+ m_jit.globalObjectFor(node.codeOrigin)->symbolTable()->get(
identifier(node.identifierNumberForCheck())->impl()).watchpointSet();
addSlowPathGenerator(
slowPathCall(
@@ -3563,7 +3749,7 @@ void SpeculativeJIT::compile(Node& node)
}
case GlobalVarWatchpoint: {
- m_jit.globalObjectFor(node.codeOrigin)->symbolTable().get(
+ m_jit.globalObjectFor(node.codeOrigin)->symbolTable()->get(
identifier(node.identifierNumberForCheck())->impl()).addWatchpoint(
speculationWatchpoint());
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index b69d53600..a1ac899a2 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -1032,7 +1032,7 @@ void SpeculativeJIT::emitCall(Node& node)
m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister);
slowPath = m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleeGPR, targetToCheck, MacroAssembler::TrustedImmPtr(JSValue::encode(JSValue())));
- m_jit.loadPtr(MacroAssembler::Address(calleeGPR, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), resultGPR);
+ m_jit.loadPtr(MacroAssembler::Address(calleeGPR, OBJECT_OFFSETOF(JSFunction, m_scope)), resultGPR);
m_jit.storePtr(resultGPR, MacroAssembler::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ScopeChain));
CodeOrigin codeOrigin = at(m_compileIndex).codeOrigin;
@@ -1538,7 +1538,7 @@ JITCompiler::Jump SpeculativeJIT::convertToDouble(GPRReg value, FPRReg result, G
return notNumber;
}
-void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInfo, SpeculatedTypeChecker speculatedTypeChecker)
+void SpeculativeJIT::compileObjectEquality(Node& node)
{
SpeculateCellOperand op1(this, node.child1());
SpeculateCellOperand op2(this, node.child2());
@@ -1547,11 +1547,47 @@ void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInf
GPRReg op1GPR = op1.gpr();
GPRReg op2GPR = op2.gpr();
GPRReg resultGPR = result.gpr();
-
- if (!speculatedTypeChecker(m_state.forNode(node.child1()).m_type))
- speculationCheck(BadType, JSValueRegs(op1GPR), node.child1().index(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo)));
- if (!speculatedTypeChecker(m_state.forNode(node.child2()).m_type))
- speculationCheck(BadType, JSValueRegs(op2GPR), node.child2().index(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op2GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo)));
+
+ if (m_jit.graph().globalObjectFor(node.codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
+ m_jit.graph().globalObjectFor(node.codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+ speculationCheck(BadType, JSValueRegs(op1GPR), node.child1().index(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op1GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ speculationCheck(BadType, JSValueRegs(op2GPR), node.child2().index(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op2GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ } else {
+ GPRTemporary structure(this);
+ GPRReg structureGPR = structure.gpr();
+
+ m_jit.loadPtr(MacroAssembler::Address(op1GPR, JSCell::structureOffset()), structureGPR);
+ speculationCheck(BadType, JSValueRegs(op1GPR), node.child1().index(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ speculationCheck(BadType, JSValueRegs(op1GPR), node.child1().index(),
+ m_jit.branchTest8(
+ MacroAssembler::NonZero,
+ MacroAssembler::Address(structureGPR, Structure::typeInfoFlagsOffset()),
+ MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
+
+ m_jit.loadPtr(MacroAssembler::Address(op2GPR, JSCell::structureOffset()), structureGPR);
+ speculationCheck(BadType, JSValueRegs(op2GPR), node.child2().index(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ speculationCheck(BadType, JSValueRegs(op2GPR), node.child2().index(),
+ m_jit.branchTest8(
+ MacroAssembler::NonZero,
+ MacroAssembler::Address(structureGPR, Structure::typeInfoFlagsOffset()),
+ MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
+ }
MacroAssembler::Jump falseCase = m_jit.branchPtr(MacroAssembler::NotEqual, op1GPR, op2GPR);
m_jit.move(TrustedImm32(ValueTrue), resultGPR);
@@ -1563,10 +1599,9 @@ void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInf
jsValueResult(resultGPR, m_compileIndex, DataFormatJSBoolean);
}
-void SpeculativeJIT::compileObjectToObjectOrOtherEquality(
- Edge leftChild, Edge rightChild,
- const ClassInfo* classInfo, SpeculatedTypeChecker speculatedTypeChecker)
+void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild)
{
+ Node& leftNode = m_jit.graph()[leftChild.index()];
SpeculateCellOperand op1(this, leftChild);
JSValueOperand op2(this, rightChild);
GPRTemporary result(this);
@@ -1574,14 +1609,29 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality(
GPRReg op1GPR = op1.gpr();
GPRReg op2GPR = op2.gpr();
GPRReg resultGPR = result.gpr();
-
- if (!speculatedTypeChecker(m_state.forNode(leftChild).m_type)) {
- speculationCheck(
- BadType, JSValueRegs(op1GPR), leftChild.index(),
+
+ if (m_jit.graph().globalObjectFor(leftNode.codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
+ m_jit.graph().globalObjectFor(leftNode.codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+ speculationCheck(BadType, JSValueRegs(op1GPR), leftChild.index(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op1GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ } else {
+ GPRTemporary structure(this);
+ GPRReg structureGPR = structure.gpr();
+
+ m_jit.loadPtr(MacroAssembler::Address(op1GPR, JSCell::structureOffset()), structureGPR);
+ speculationCheck(BadType, JSValueRegs(op1GPR), leftChild.index(),
m_jit.branchPtr(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(op1GPR, JSCell::classInfoOffset()),
- MacroAssembler::TrustedImmPtr(classInfo)));
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ speculationCheck(BadType, JSValueRegs(op1GPR), leftChild.index(),
+ m_jit.branchTest8(
+ MacroAssembler::NonZero,
+ MacroAssembler::Address(structureGPR, Structure::typeInfoFlagsOffset()),
+ MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
}
// It seems that most of the time when programs do a == b where b may be either null/undefined
@@ -1589,17 +1639,29 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality(
MacroAssembler::Jump rightNotCell =
m_jit.branchTestPtr(MacroAssembler::NonZero, op2GPR, GPRInfo::tagMaskRegister);
- // We know that within this branch, rightChild must be a cell. If the CFA can tell us that the
- // proof, when filtered on cell, demonstrates that we have an object of the desired type
- // (speculationCheck() will test for FinalObject or Array, currently), then we can skip the
- // speculation.
- if (!speculatedTypeChecker(m_state.forNode(rightChild).m_type & SpecCell)) {
- speculationCheck(
- BadType, JSValueRegs(op2GPR), rightChild.index(),
+ // We know that within this branch, rightChild must be a cell.
+ if (m_jit.graph().globalObjectFor(leftNode.codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
+ m_jit.graph().globalObjectFor(leftNode.codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+ speculationCheck(BadType, JSValueRegs(op2GPR), rightChild.index(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op2GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ } else {
+ GPRTemporary structure(this);
+ GPRReg structureGPR = structure.gpr();
+
+ m_jit.loadPtr(MacroAssembler::Address(op2GPR, JSCell::structureOffset()), structureGPR);
+ speculationCheck(BadType, JSValueRegs(op2GPR), rightChild.index(),
m_jit.branchPtr(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(op2GPR, JSCell::classInfoOffset()),
- MacroAssembler::TrustedImmPtr(classInfo)));
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ speculationCheck(BadType, JSValueRegs(op2GPR), rightChild.index(),
+ m_jit.branchTest8(
+ MacroAssembler::NonZero,
+ MacroAssembler::Address(structureGPR, Structure::typeInfoFlagsOffset()),
+ MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
}
// At this point we know that we can perform a straight-forward equality comparison on pointer
@@ -1633,9 +1695,7 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality(
jsValueResult(resultGPR, m_compileIndex, DataFormatJSBoolean);
}
-void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(
- Edge leftChild, Edge rightChild, NodeIndex branchNodeIndex,
- const ClassInfo* classInfo, SpeculatedTypeChecker speculatedTypeChecker)
+void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild, NodeIndex branchNodeIndex)
{
Node& branchNode = at(branchNodeIndex);
BlockIndex taken = branchNode.takenBlockIndex();
@@ -1649,13 +1709,28 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(
GPRReg op2GPR = op2.gpr();
GPRReg resultGPR = result.gpr();
- if (!speculatedTypeChecker(m_state.forNode(leftChild).m_type)) {
- speculationCheck(
- BadType, JSValueRegs(op1GPR), leftChild.index(),
+ if (m_jit.graph().globalObjectFor(branchNode.codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
+ m_jit.graph().globalObjectFor(branchNode.codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+ speculationCheck(BadType, JSValueRegs(op1GPR), leftChild.index(),
m_jit.branchPtr(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(op1GPR, JSCell::classInfoOffset()),
- MacroAssembler::TrustedImmPtr(classInfo)));
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op1GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ } else {
+ GPRTemporary structure(this);
+ GPRReg structureGPR = structure.gpr();
+
+ m_jit.loadPtr(MacroAssembler::Address(op1GPR, JSCell::structureOffset()), structureGPR);
+ speculationCheck(BadType, JSValueRegs(op1GPR), leftChild.index(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ speculationCheck(BadType, JSValueRegs(op1GPR), leftChild.index(),
+ m_jit.branchTest8(
+ MacroAssembler::NonZero,
+ MacroAssembler::Address(structureGPR, Structure::typeInfoFlagsOffset()),
+ MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
}
// It seems that most of the time when programs do a == b where b may be either null/undefined
@@ -1663,17 +1738,29 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(
MacroAssembler::Jump rightNotCell =
m_jit.branchTestPtr(MacroAssembler::NonZero, op2GPR, GPRInfo::tagMaskRegister);
- // We know that within this branch, rightChild must be a cell. If the CFA can tell us that the
- // proof, when filtered on cell, demonstrates that we have an object of the desired type
- // (speculationCheck() will test for FinalObject or Array, currently), then we can skip the
- // speculation.
- if (!speculatedTypeChecker(m_state.forNode(rightChild).m_type & SpecCell)) {
- speculationCheck(
- BadType, JSValueRegs(op2GPR), rightChild.index(),
+ // We know that within this branch, rightChild must be a cell.
+ if (m_jit.graph().globalObjectFor(branchNode.codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
+ m_jit.graph().globalObjectFor(branchNode.codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+ speculationCheck(BadType, JSValueRegs(op2GPR), rightChild.index(),
m_jit.branchPtr(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(op2GPR, JSCell::classInfoOffset()),
- MacroAssembler::TrustedImmPtr(classInfo)));
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op2GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ } else {
+ GPRTemporary structure(this);
+ GPRReg structureGPR = structure.gpr();
+
+ m_jit.loadPtr(MacroAssembler::Address(op2GPR, JSCell::structureOffset()), structureGPR);
+ speculationCheck(BadType, JSValueRegs(op2GPR), rightChild.index(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ speculationCheck(BadType, JSValueRegs(op2GPR), rightChild.index(),
+ m_jit.branchTest8(
+ MacroAssembler::NonZero,
+ MacroAssembler::Address(structureGPR, Structure::typeInfoFlagsOffset()),
+ MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
}
// At this point we know that we can perform a straight-forward equality comparison on pointer
@@ -1748,7 +1835,7 @@ void SpeculativeJIT::compileValueAdd(Node& node)
jsValueResult(result.gpr(), m_compileIndex);
}
-void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse, const ClassInfo* classInfo, bool needSpeculationCheck)
+void SpeculativeJIT::compileNonStringCellOrOtherLogicalNot(Edge nodeUse, bool needSpeculationCheck)
{
JSValueOperand value(this, nodeUse);
GPRTemporary result(this);
@@ -1756,19 +1843,59 @@ void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse, const ClassInf
GPRReg resultGPR = result.gpr();
MacroAssembler::Jump notCell = m_jit.branchTestPtr(MacroAssembler::NonZero, valueGPR, GPRInfo::tagMaskRegister);
- if (needSpeculationCheck)
- speculationCheck(BadType, JSValueRegs(valueGPR), nodeUse, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(valueGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo)));
- m_jit.move(TrustedImm32(static_cast<int32_t>(ValueFalse)), resultGPR);
+ if (m_jit.graph().globalObjectFor(m_jit.graph()[nodeUse.index()].codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
+ m_jit.graph().globalObjectFor(m_jit.graph()[nodeUse.index()].codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+
+ if (needSpeculationCheck) {
+ speculationCheck(BadType, JSValueRegs(valueGPR), nodeUse,
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(valueGPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ }
+ } else {
+ GPRTemporary structure(this);
+ GPRReg structureGPR = structure.gpr();
+
+ m_jit.loadPtr(MacroAssembler::Address(valueGPR, JSCell::structureOffset()), structureGPR);
+
+ if (needSpeculationCheck) {
+ speculationCheck(BadType, JSValueRegs(valueGPR), nodeUse,
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ }
+
+ MacroAssembler::Jump isNotMasqueradesAsUndefined =
+ m_jit.branchTest8(
+ MacroAssembler::Zero,
+ MacroAssembler::Address(structureGPR, Structure::typeInfoFlagsOffset()),
+ MacroAssembler::TrustedImm32(MasqueradesAsUndefined));
+
+ speculationCheck(BadType, JSValueRegs(valueGPR), nodeUse,
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(structureGPR, Structure::globalObjectOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.graph().globalObjectFor(m_jit.graph()[nodeUse.index()].codeOrigin))));
+
+ isNotMasqueradesAsUndefined.link(&m_jit);
+ }
+ m_jit.move(TrustedImm32(ValueFalse), resultGPR);
MacroAssembler::Jump done = m_jit.jump();
notCell.link(&m_jit);
-
+
if (needSpeculationCheck) {
m_jit.move(valueGPR, resultGPR);
m_jit.andPtr(MacroAssembler::TrustedImm32(~TagBitUndefined), resultGPR);
- speculationCheck(BadType, JSValueRegs(valueGPR), nodeUse, m_jit.branchPtr(MacroAssembler::NotEqual, resultGPR, MacroAssembler::TrustedImmPtr(reinterpret_cast<void*>(ValueNull))));
+ speculationCheck(BadType, JSValueRegs(valueGPR), nodeUse,
+ m_jit.branchPtr(
+ MacroAssembler::NotEqual,
+ resultGPR,
+ MacroAssembler::TrustedImmPtr(reinterpret_cast<void*>(ValueNull))));
}
- m_jit.move(TrustedImm32(static_cast<int32_t>(ValueTrue)), resultGPR);
+ m_jit.move(TrustedImm32(ValueTrue), resultGPR);
done.link(&m_jit);
@@ -1777,12 +1904,9 @@ void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse, const ClassInf
void SpeculativeJIT::compileLogicalNot(Node& node)
{
- if (at(node.child1()).shouldSpeculateFinalObjectOrOther()) {
- compileObjectOrOtherLogicalNot(node.child1(), &JSFinalObject::s_info, !isFinalObjectOrOtherSpeculation(m_state.forNode(node.child1()).m_type));
- return;
- }
- if (at(node.child1()).shouldSpeculateArrayOrOther()) {
- compileObjectOrOtherLogicalNot(node.child1(), &JSArray::s_info, !isArrayOrOtherSpeculation(m_state.forNode(node.child1()).m_type));
+ if (at(node.child1()).shouldSpeculateNonStringCellOrOther()) {
+ compileNonStringCellOrOtherLogicalNot(node.child1(),
+ !isNonStringCellOrOtherSpeculation(m_state.forNode(node.child1()).m_type));
return;
}
if (at(node.child1()).shouldSpeculateInteger()) {
@@ -1850,7 +1974,7 @@ void SpeculativeJIT::compileLogicalNot(Node& node)
jsValueResult(resultGPR, m_compileIndex, DataFormatJSBoolean, UseChildrenCalledExplicitly);
}
-void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse, BlockIndex taken, BlockIndex notTaken, const ClassInfo* classInfo, bool needSpeculationCheck)
+void SpeculativeJIT::emitNonStringCellOrOtherBranch(Edge nodeUse, BlockIndex taken, BlockIndex notTaken, bool needSpeculationCheck)
{
JSValueOperand value(this, nodeUse);
GPRTemporary scratch(this);
@@ -1858,8 +1982,37 @@ void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse, BlockIndex taken, Blo
GPRReg scratchGPR = scratch.gpr();
MacroAssembler::Jump notCell = m_jit.branchTestPtr(MacroAssembler::NonZero, valueGPR, GPRInfo::tagMaskRegister);
- if (needSpeculationCheck)
- speculationCheck(BadType, JSValueRegs(valueGPR), nodeUse.index(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(valueGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo)));
+ if (m_jit.graph().globalObjectFor(m_jit.graph()[nodeUse.index()].codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
+ m_jit.graph().globalObjectFor(m_jit.graph()[nodeUse.index()].codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+
+ if (needSpeculationCheck) {
+ speculationCheck(BadType, JSValueRegs(valueGPR), nodeUse.index(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(valueGPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ }
+ } else {
+ m_jit.loadPtr(MacroAssembler::Address(valueGPR, JSCell::structureOffset()), scratchGPR);
+
+ if (needSpeculationCheck) {
+ speculationCheck(BadType, JSValueRegs(valueGPR), nodeUse.index(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ scratchGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ }
+
+ JITCompiler::Jump isNotMasqueradesAsUndefined = m_jit.branchTest8(JITCompiler::Zero, MacroAssembler::Address(scratchGPR, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined));
+
+ speculationCheck(BadType, JSValueRegs(valueGPR), nodeUse.index(),
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(scratchGPR, Structure::globalObjectOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.graph().globalObjectFor(m_jit.graph()[nodeUse.index()].codeOrigin))));
+
+ isNotMasqueradesAsUndefined.link(&m_jit);
+ }
jump(taken, ForceJump);
notCell.link(&m_jit);
@@ -1879,10 +2032,9 @@ void SpeculativeJIT::emitBranch(Node& node)
BlockIndex taken = node.takenBlockIndex();
BlockIndex notTaken = node.notTakenBlockIndex();
- if (at(node.child1()).shouldSpeculateFinalObjectOrOther()) {
- emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSFinalObject::s_info, !isFinalObjectOrOtherSpeculation(m_state.forNode(node.child1()).m_type));
- } else if (at(node.child1()).shouldSpeculateArrayOrOther()) {
- emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSArray::s_info, !isArrayOrOtherSpeculation(m_state.forNode(node.child1()).m_type));
+ if (at(node.child1()).shouldSpeculateNonStringCellOrOther()) {
+ emitNonStringCellOrOtherBranch(node.child1(), taken, notTaken,
+ !isNonStringCellOrOtherSpeculation(m_state.forNode(node.child1()).m_type));
} else if (at(node.child1()).shouldSpeculateNumber()) {
if (at(node.child1()).shouldSpeculateInteger()) {
bool invert = false;
@@ -2406,6 +2558,11 @@ void SpeculativeJIT::compile(Node& node)
compileGetByValOnString(node);
break;
}
+
+ case CheckArray: {
+ checkArray(node);
+ break;
+ }
case GetByVal: {
switch (node.arrayMode()) {
@@ -2443,11 +2600,24 @@ void SpeculativeJIT::compile(Node& node)
// We will have already speculated that the base is some kind of array,
// at this point.
- speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())));
+ MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()));
+ if (node.arrayMode() == Array::JSArray)
+ speculationCheck(OutOfBounds, JSValueRegs(), NoNode, outOfBounds);
GPRTemporary result(this);
m_jit.loadPtr(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), result.gpr());
- speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branchTestPtr(MacroAssembler::Zero, result.gpr()));
+ MacroAssembler::Jump hole = m_jit.branchTestPtr(MacroAssembler::Zero, result.gpr());
+ if (node.arrayMode() == Array::JSArray)
+ speculationCheck(OutOfBounds, JSValueRegs(), NoNode, hole);
+ else {
+ MacroAssembler::JumpList slowCases;
+ slowCases.append(outOfBounds);
+ slowCases.append(hole);
+ addSlowPathGenerator(
+ slowPathCall(
+ slowCases, this, operationGetByValArrayInt,
+ result.gpr(), baseReg, propertyReg));
+ }
jsValueResult(result.gpr(), m_compileIndex);
break;
@@ -2497,6 +2667,7 @@ void SpeculativeJIT::compile(Node& node)
Edge child1 = m_jit.graph().varArgChild(node, 0);
Edge child2 = m_jit.graph().varArgChild(node, 1);
Edge child3 = m_jit.graph().varArgChild(node, 2);
+ Edge child4 = m_jit.graph().varArgChild(node, 3);
Array::Mode arrayMode = modeForPut(node.arrayMode());
bool alreadyHandled = false;
@@ -2538,27 +2709,26 @@ void SpeculativeJIT::compile(Node& node)
GPRReg baseReg = base.gpr();
GPRReg propertyReg = property.gpr();
- speculateArray(arrayMode, child1, baseReg);
-
switch (arrayMode) {
case Array::JSArray:
case Array::JSArrayOutOfBounds: {
JSValueOperand value(this, child3);
- GPRTemporary scratch(this);
// Map base, property & value into registers, allocate a scratch register.
GPRReg valueReg = value.gpr();
- GPRReg scratchReg = scratch.gpr();
if (!m_compileOkay)
return;
- writeBarrier(baseReg, value.gpr(), child3, WriteBarrierForPropertyAccess, scratchReg);
+ if (Heap::isWriteBarrierEnabled()) {
+ GPRTemporary scratch(this);
+ writeBarrier(baseReg, value.gpr(), child3, WriteBarrierForPropertyAccess, scratch.gpr());
+ }
+
+ StorageOperand storage(this, child4);
+ GPRReg storageReg = storage.gpr();
if (node.op() == PutByValAlias) {
- GPRReg storageReg = scratchReg;
- m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
-
// Store the value to the array.
GPRReg propertyReg = property.gpr();
GPRReg valueReg = value.gpr();
@@ -2575,11 +2745,8 @@ void SpeculativeJIT::compile(Node& node)
base.use();
property.use();
value.use();
+ storage.use();
- // Get the array storage.
- GPRReg storageReg = scratchReg;
- m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
-
// Check if we're writing to a hole; if so increment m_numValuesInVector.
MacroAssembler::Jump notHoleValue = m_jit.branchTestPtr(MacroAssembler::NonZero, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
@@ -2747,21 +2914,24 @@ void SpeculativeJIT::compile(Node& node)
}
case ArrayPush: {
+ ASSERT(modeIsJSArray(node.arrayMode()));
+
SpeculateCellOperand base(this, node.child1());
JSValueOperand value(this, node.child2());
- GPRTemporary storage(this);
GPRTemporary storageLength(this);
GPRReg baseGPR = base.gpr();
GPRReg valueGPR = value.gpr();
- GPRReg storageGPR = storage.gpr();
GPRReg storageLengthGPR = storageLength.gpr();
- writeBarrier(baseGPR, valueGPR, node.child2(), WriteBarrierForPropertyAccess, storageGPR, storageLengthGPR);
+ if (Heap::isWriteBarrierEnabled()) {
+ GPRTemporary scratch(this);
+ writeBarrier(baseGPR, valueGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR);
+ }
- speculateArray(Array::JSArray, node.child1(), baseGPR);
+ StorageOperand storage(this, node.child3());
+ GPRReg storageGPR = storage.gpr();
- m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR);
m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
// Refuse to handle bizarre lengths.
@@ -2786,19 +2956,18 @@ void SpeculativeJIT::compile(Node& node)
}
case ArrayPop: {
+ ASSERT(modeIsJSArray(node.arrayMode()));
+
SpeculateCellOperand base(this, node.child1());
+ StorageOperand storage(this, node.child2());
GPRTemporary value(this);
- GPRTemporary storage(this);
GPRTemporary storageLength(this);
GPRReg baseGPR = base.gpr();
- GPRReg valueGPR = value.gpr();
GPRReg storageGPR = storage.gpr();
+ GPRReg valueGPR = value.gpr();
GPRReg storageLengthGPR = storageLength.gpr();
- speculateArray(Array::JSArray, node.child1(), baseGPR);
-
- m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR);
m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
JITCompiler::JumpList setUndefinedCases;
@@ -3175,34 +3344,32 @@ void SpeculativeJIT::compile(Node& node)
JITCompiler::Jump activationNotCreated;
if (checkTopLevel)
activationNotCreated = m_jit.branchTestPtr(JITCompiler::Zero, JITCompiler::addressFor(static_cast<VirtualRegister>(m_jit.codeBlock()->activationRegister())));
- m_jit.loadPtr(JITCompiler::Address(resultGPR, OBJECT_OFFSETOF(ScopeChainNode, next)), resultGPR);
+ m_jit.loadPtr(JITCompiler::Address(resultGPR, JSScope::offsetOfNext()), resultGPR);
activationNotCreated.link(&m_jit);
}
while (skip--)
- m_jit.loadPtr(JITCompiler::Address(resultGPR, OBJECT_OFFSETOF(ScopeChainNode, next)), resultGPR);
+ m_jit.loadPtr(JITCompiler::Address(resultGPR, JSScope::offsetOfNext()), resultGPR);
- m_jit.loadPtr(JITCompiler::Address(resultGPR, OBJECT_OFFSETOF(ScopeChainNode, object)), resultGPR);
-
cellResult(resultGPR, m_compileIndex);
break;
}
case GetScopedVar: {
- SpeculateCellOperand scopeChain(this, node.child1());
+ SpeculateCellOperand scope(this, node.child1());
GPRTemporary result(this);
GPRReg resultGPR = result.gpr();
- m_jit.loadPtr(JITCompiler::Address(scopeChain.gpr(), JSVariableObject::offsetOfRegisters()), resultGPR);
+ m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSVariableObject::offsetOfRegisters()), resultGPR);
m_jit.loadPtr(JITCompiler::Address(resultGPR, node.varNumber() * sizeof(Register)), resultGPR);
jsValueResult(resultGPR, m_compileIndex);
break;
}
case PutScopedVar: {
- SpeculateCellOperand scopeChain(this, node.child1());
+ SpeculateCellOperand scope(this, node.child1());
GPRTemporary scratchRegister(this);
GPRReg scratchGPR = scratchRegister.gpr();
- m_jit.loadPtr(JITCompiler::Address(scopeChain.gpr(), JSVariableObject::offsetOfRegisters()), scratchGPR);
+ m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSVariableObject::offsetOfRegisters()), scratchGPR);
JSValueOperand value(this, node.child2());
m_jit.storePtr(value.gpr(), JITCompiler::Address(scratchGPR, node.varNumber() * sizeof(Register)));
- writeBarrier(scopeChain.gpr(), value.gpr(), node.child2(), WriteBarrierForVariableAccess, scratchGPR);
+ writeBarrier(scope.gpr(), value.gpr(), node.child2(), WriteBarrierForVariableAccess, scratchGPR);
noResult(m_compileIndex);
break;
}
@@ -3518,7 +3685,7 @@ void SpeculativeJIT::compile(Node& node)
JSValueOperand value(this, node.child1());
WatchpointSet* watchpointSet =
- m_jit.globalObjectFor(node.codeOrigin)->symbolTable().get(
+ m_jit.globalObjectFor(node.codeOrigin)->symbolTable()->get(
identifier(node.identifierNumberForCheck())->impl()).watchpointSet();
addSlowPathGenerator(
slowPathCall(
@@ -3541,7 +3708,7 @@ void SpeculativeJIT::compile(Node& node)
}
case GlobalVarWatchpoint: {
- m_jit.globalObjectFor(node.codeOrigin)->symbolTable().get(
+ m_jit.globalObjectFor(node.codeOrigin)->symbolTable()->get(
identifier(node.identifierNumberForCheck())->impl()).addWatchpoint(
speculationWatchpoint());
diff --git a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
index eb04a6747..dec2e49f7 100644
--- a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
@@ -99,6 +99,8 @@ public:
case PutByVal:
case PutByValAlias:
case GetArrayLength:
+ case CheckArray:
+ case GetIndexedPropertyStorage:
case Phantom:
// Don't count these uses.
break;
@@ -128,6 +130,50 @@ public:
#endif
iter->second.m_structure = 0;
}
+
+ // Disable structure check hoisting for variables that cross the OSR entry that
+ // we're currently taking, and where the value currently does not have the
+ // structure we want.
+
+ for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
+ BasicBlock* block = m_graph.m_blocks[blockIndex].get();
+ if (!block)
+ continue;
+ ASSERT(block->isReachable);
+ if (!block->isOSRTarget)
+ continue;
+ if (block->bytecodeBegin != m_graph.m_osrEntryBytecodeIndex)
+ continue;
+ for (size_t i = 0; i < m_graph.m_mustHandleValues.size(); ++i) {
+ int operand = m_graph.m_mustHandleValues.operandForIndex(i);
+ NodeIndex nodeIndex = block->variablesAtHead.operand(operand);
+ if (nodeIndex == NoNode)
+ continue;
+ VariableAccessData* variable = m_graph[nodeIndex].variableAccessData();
+ HashMap<VariableAccessData*, CheckData>::iterator iter = m_map.find(variable);
+ if (iter == m_map.end())
+ continue;
+ if (!iter->second.m_structure)
+ continue;
+ JSValue value = m_graph.m_mustHandleValues[i];
+ if (!value || !value.isCell()) {
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ dataLog("Zeroing the structure to hoist for %s because the OSR entry value is not a cell: %s.\n",
+ m_graph.nameOfVariableAccessData(variable), value.description());
+#endif
+ iter->second.m_structure = 0;
+ continue;
+ }
+ if (value.asCell()->structure() != iter->second.m_structure) {
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ dataLog("Zeroing the structure to hoist for %s because the OSR entry value has structure %p and we wanted %p.\n",
+ m_graph.nameOfVariableAccessData(variable), value.asCell()->structure(), iter->second.m_structure);
+#endif
+ iter->second.m_structure = 0;
+ continue;
+ }
+ }
+ }
// Identify the set of variables that are live across a structure clobber.
diff --git a/Source/JavaScriptCore/dfg/DFGThunks.cpp b/Source/JavaScriptCore/dfg/DFGThunks.cpp
index b056de79c..546aec256 100644
--- a/Source/JavaScriptCore/dfg/DFGThunks.cpp
+++ b/Source/JavaScriptCore/dfg/DFGThunks.cpp
@@ -219,10 +219,11 @@ static MacroAssemblerCodeRef virtualForThunkGenerator(
CCallHelpers::NotEqual, GPRInfo::nonArgGPR1,
CCallHelpers::TrustedImm32(JSValue::CellTag)));
#endif
+ jit.loadPtr(CCallHelpers::Address(GPRInfo::nonArgGPR0, JSCell::structureOffset()), GPRInfo::nonArgGPR2);
slowCase.append(
jit.branchPtr(
CCallHelpers::NotEqual,
- CCallHelpers::Address(GPRInfo::nonArgGPR0, JSCell::classInfoOffset()),
+ CCallHelpers::Address(GPRInfo::nonArgGPR2, Structure::classInfoOffset()),
CCallHelpers::TrustedImmPtr(&JSFunction::s_info)));
// Now we know we have a JSFunction.