summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-08-23 17:03:15 +0200
committerSimon Hausmann <simon.hausmann@nokia.com>2012-08-23 17:03:15 +0200
commita73d1c176f2f3e0458861de8590dc20321a501ae (patch)
treed897fc5974797c3cb300d7f5916f258df765401f /Source/JavaScriptCore/dfg
parentc311cf639cc1d6570d67b0a80a8ba04dc992a658 (diff)
downloadqtwebkit-a73d1c176f2f3e0458861de8590dc20321a501ae.tar.gz
Imported WebKit commit a5ae8a56a48e44ebfb9b81aaa5488affaffdb175 (http://svn.webkit.org/repository/webkit/trunk@126420)
New snapshot with OS X 10.6 build fix
Diffstat (limited to 'Source/JavaScriptCore/dfg')
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractState.cpp314
-rw-r--r--Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp79
-rw-r--r--Source/JavaScriptCore/dfg/DFGArrayMode.cpp217
-rw-r--r--Source/JavaScriptCore/dfg/DFGArrayMode.h135
-rw-r--r--Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp63
-rw-r--r--Source/JavaScriptCore/dfg/DFGCSEPhase.cpp21
-rw-r--r--Source/JavaScriptCore/dfg/DFGFixupPhase.cpp176
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.cpp4
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.h55
-rw-r--r--Source/JavaScriptCore/dfg/DFGNode.h29
-rw-r--r--Source/JavaScriptCore/dfg/DFGNodeType.h12
-rw-r--r--Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp12
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp254
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h20
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp585
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp595
-rw-r--r--Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp44
17 files changed, 1251 insertions, 1364 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index 5c53f6d78..cfe915947 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -868,65 +868,66 @@ bool AbstractState::execute(unsigned indexInBlock)
case GetByVal: {
node.setCanExit(true);
- if (!node.prediction() || !m_graph[node.child1()].prediction() || !m_graph[node.child2()].prediction()) {
+ switch (node.arrayMode()) {
+ case Array::Undecided:
+ ASSERT_NOT_REACHED();
+ break;
+ case Array::ForceExit:
m_isValid = false;
break;
- }
- if (!m_graph[node.child2()].shouldSpeculateInteger() || (!node.child3() && !m_graph[node.child1()].shouldSpeculateArguments())) {
+ case Array::Generic:
clobberWorld(node.codeOrigin, indexInBlock);
forNode(nodeIndex).makeTop();
break;
- }
- if (m_graph[node.child1()].shouldSpeculateArguments()) {
+ 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;
- }
- if (m_graph[node.child1()].prediction() == SpecString) {
- forNode(node.child1()).filter(SpecString);
+ case Array::JSArray:
+ 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);
- forNode(nodeIndex).set(SpecString);
+ forNode(nodeIndex).makeTop();
break;
- }
-
- if (m_graph[node.child1()].shouldSpeculateInt8Array()) {
+ case Array::Int8Array:
forNode(node.child1()).filter(SpecInt8Array);
forNode(node.child2()).filter(SpecInt32);
forNode(nodeIndex).set(SpecInt32);
break;
- }
- if (m_graph[node.child1()].shouldSpeculateInt16Array()) {
+ case Array::Int16Array:
forNode(node.child1()).filter(SpecInt16Array);
forNode(node.child2()).filter(SpecInt32);
forNode(nodeIndex).set(SpecInt32);
break;
- }
- if (m_graph[node.child1()].shouldSpeculateInt32Array()) {
+ case Array::Int32Array:
forNode(node.child1()).filter(SpecInt32Array);
forNode(node.child2()).filter(SpecInt32);
forNode(nodeIndex).set(SpecInt32);
break;
- }
- if (m_graph[node.child1()].shouldSpeculateUint8Array()) {
+ case Array::Uint8Array:
forNode(node.child1()).filter(SpecUint8Array);
forNode(node.child2()).filter(SpecInt32);
forNode(nodeIndex).set(SpecInt32);
break;
- }
- if (m_graph[node.child1()].shouldSpeculateUint8ClampedArray()) {
+ case Array::Uint8ClampedArray:
forNode(node.child1()).filter(SpecUint8ClampedArray);
forNode(node.child2()).filter(SpecInt32);
forNode(nodeIndex).set(SpecInt32);
break;
- }
- if (m_graph[node.child1()].shouldSpeculateUint16Array()) {
+ case Array::Uint16Array:
forNode(node.child1()).filter(SpecUint16Array);
forNode(node.child2()).filter(SpecInt32);
forNode(nodeIndex).set(SpecInt32);
break;
- }
- if (m_graph[node.child1()].shouldSpeculateUint32Array()) {
+ case Array::Uint32Array:
forNode(node.child1()).filter(SpecUint32Array);
forNode(node.child2()).filter(SpecInt32);
if (node.shouldSpeculateInteger())
@@ -934,55 +935,47 @@ bool AbstractState::execute(unsigned indexInBlock)
else
forNode(nodeIndex).set(SpecDouble);
break;
- }
- if (m_graph[node.child1()].shouldSpeculateFloat32Array()) {
+ case Array::Float32Array:
forNode(node.child1()).filter(SpecFloat32Array);
forNode(node.child2()).filter(SpecInt32);
forNode(nodeIndex).set(SpecDouble);
break;
- }
- if (m_graph[node.child1()].shouldSpeculateFloat64Array()) {
+ case Array::Float64Array:
forNode(node.child1()).filter(SpecFloat64Array);
forNode(node.child2()).filter(SpecInt32);
forNode(nodeIndex).set(SpecDouble);
break;
}
- forNode(node.child1()).filter(SpecCell);
- forNode(node.child2()).filter(SpecInt32);
- forNode(nodeIndex).makeTop();
break;
}
case PutByVal:
- case PutByValAlias:
- case PutByValSafe: {
+ 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);
-
- if (!m_graph[child1].prediction() || !m_graph[child2].prediction()) {
+ switch (modeForPut(node.arrayMode())) {
+ case Array::ForceExit:
m_isValid = false;
break;
- }
- if (!m_graph[child2].shouldSpeculateInteger()
-#if USE(JSVALUE32_64)
- || m_graph[child1].shouldSpeculateArguments()
-#endif
- ) {
- ASSERT(node.op() == PutByVal || node.op() == PutByValSafe);
+ case Array::Generic:
clobberWorld(node.codeOrigin, indexInBlock);
- forNode(nodeIndex).makeTop();
break;
- }
-
- if (m_graph[child1].shouldSpeculateArguments()) {
+ 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;
- }
- if (m_graph[child1].shouldSpeculateInt8Array()) {
+ case Array::Int8Array:
forNode(child1).filter(SpecInt8Array);
forNode(child2).filter(SpecInt32);
if (m_graph[child3].shouldSpeculateInteger())
@@ -990,8 +983,7 @@ bool AbstractState::execute(unsigned indexInBlock)
else
forNode(child3).filter(SpecNumber);
break;
- }
- if (m_graph[child1].shouldSpeculateInt16Array()) {
+ case Array::Int16Array:
forNode(child1).filter(SpecInt16Array);
forNode(child2).filter(SpecInt32);
if (m_graph[child3].shouldSpeculateInteger())
@@ -999,8 +991,7 @@ bool AbstractState::execute(unsigned indexInBlock)
else
forNode(child3).filter(SpecNumber);
break;
- }
- if (m_graph[child1].shouldSpeculateInt32Array()) {
+ case Array::Int32Array:
forNode(child1).filter(SpecInt32Array);
forNode(child2).filter(SpecInt32);
if (m_graph[child3].shouldSpeculateInteger())
@@ -1008,8 +999,7 @@ bool AbstractState::execute(unsigned indexInBlock)
else
forNode(child3).filter(SpecNumber);
break;
- }
- if (m_graph[child1].shouldSpeculateUint8Array()) {
+ case Array::Uint8Array:
forNode(child1).filter(SpecUint8Array);
forNode(child2).filter(SpecInt32);
if (m_graph[child3].shouldSpeculateInteger())
@@ -1017,8 +1007,7 @@ bool AbstractState::execute(unsigned indexInBlock)
else
forNode(child3).filter(SpecNumber);
break;
- }
- if (m_graph[child1].shouldSpeculateUint8ClampedArray()) {
+ case Array::Uint8ClampedArray:
forNode(child1).filter(SpecUint8ClampedArray);
forNode(child2).filter(SpecInt32);
if (m_graph[child3].shouldSpeculateInteger())
@@ -1026,8 +1015,7 @@ bool AbstractState::execute(unsigned indexInBlock)
else
forNode(child3).filter(SpecNumber);
break;
- }
- if (m_graph[child1].shouldSpeculateUint16Array()) {
+ case Array::Uint16Array:
forNode(child1).filter(SpecUint16Array);
forNode(child2).filter(SpecInt32);
if (m_graph[child3].shouldSpeculateInteger())
@@ -1035,8 +1023,7 @@ bool AbstractState::execute(unsigned indexInBlock)
else
forNode(child3).filter(SpecNumber);
break;
- }
- if (m_graph[child1].shouldSpeculateUint32Array()) {
+ case Array::Uint32Array:
forNode(child1).filter(SpecUint32Array);
forNode(child2).filter(SpecInt32);
if (m_graph[child3].shouldSpeculateInteger())
@@ -1044,23 +1031,20 @@ bool AbstractState::execute(unsigned indexInBlock)
else
forNode(child3).filter(SpecNumber);
break;
- }
- if (m_graph[child1].shouldSpeculateFloat32Array()) {
+ case Array::Float32Array:
forNode(child1).filter(SpecFloat32Array);
forNode(child2).filter(SpecInt32);
forNode(child3).filter(SpecNumber);
break;
- }
- if (m_graph[child1].shouldSpeculateFloat64Array()) {
+ case Array::Float64Array:
forNode(child1).filter(SpecFloat64Array);
forNode(child2).filter(SpecInt32);
forNode(child3).filter(SpecNumber);
break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
}
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- if (node.op() == PutByValSafe)
- clobberWorld(node.codeOrigin, indexInBlock);
break;
}
@@ -1356,69 +1340,82 @@ bool AbstractState::execute(unsigned indexInBlock)
break;
case GetArrayLength:
- node.setCanExit(true);
- forNode(node.child1()).filter(SpecCell);
- forNode(nodeIndex).set(SpecInt32);
- break;
-
- case GetArgumentsLength:
- node.setCanExit(true);
- forNode(node.child1()).filter(SpecArguments);
- forNode(nodeIndex).set(SpecInt32);
+ 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;
+ }
break;
- case GetStringLength:
- node.setCanExit(!isStringSpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecString);
- forNode(nodeIndex).set(SpecInt32);
- break;
-
- case GetInt8ArrayLength:
- node.setCanExit(!isInt8ArraySpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecInt8Array);
- forNode(nodeIndex).set(SpecInt32);
- break;
- case GetInt16ArrayLength:
- node.setCanExit(!isInt16ArraySpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecInt16Array);
- forNode(nodeIndex).set(SpecInt32);
- break;
- case GetInt32ArrayLength:
- node.setCanExit(!isInt32ArraySpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecInt32Array);
- forNode(nodeIndex).set(SpecInt32);
- break;
- case GetUint8ArrayLength:
- node.setCanExit(!isUint8ArraySpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecUint8Array);
- forNode(nodeIndex).set(SpecInt32);
- break;
- case GetUint8ClampedArrayLength:
- node.setCanExit(!isUint8ClampedArraySpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecUint8ClampedArray);
- forNode(nodeIndex).set(SpecInt32);
- break;
- case GetUint16ArrayLength:
- node.setCanExit(!isUint16ArraySpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecUint16Array);
- forNode(nodeIndex).set(SpecInt32);
- break;
- case GetUint32ArrayLength:
- node.setCanExit(!isUint32ArraySpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecUint32Array);
- forNode(nodeIndex).set(SpecInt32);
- break;
- case GetFloat32ArrayLength:
- node.setCanExit(!isFloat32ArraySpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecFloat32Array);
- forNode(nodeIndex).set(SpecInt32);
- break;
- case GetFloat64ArrayLength:
- node.setCanExit(!isFloat64ArraySpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecFloat64Array);
- forNode(nodeIndex).set(SpecInt32);
- break;
-
case CheckStructure:
case ForwardCheckStructure: {
// FIXME: We should be able to propagate the structure sets of constants (i.e. prototypes).
@@ -1489,65 +1486,48 @@ bool AbstractState::execute(unsigned indexInBlock)
forNode(nodeIndex).clear(); // The result is not a JS value.
break;
case GetIndexedPropertyStorage: {
- ASSERT(m_graph[node.child1()].prediction());
- ASSERT(m_graph[node.child2()].shouldSpeculateInteger());
node.setCanExit(true); // Lies, but this is (almost) always followed by GetByVal, which does exit. So no point in trying to be more precise.
- if (m_graph[node.child1()].shouldSpeculateArguments()) {
- ASSERT_NOT_REACHED();
- break;
- }
- if (m_graph[node.child1()].prediction() == SpecString) {
+ switch (node.arrayMode()) {
+ case Array::String:
forNode(node.child1()).filter(SpecString);
- forNode(nodeIndex).clear();
break;
- }
-
- if (m_graph[node.child1()].shouldSpeculateInt8Array()) {
+ case Array::JSArray:
+ case Array::JSArrayOutOfBounds:
+ // This doesn't filter anything meaningful right now. We may want to add
+ // CFA tracking of array mode speculations, but we don't have that, yet.
+ forNode(node.child1()).filter(SpecCell);
+ break;
+ case Array::Int8Array:
forNode(node.child1()).filter(SpecInt8Array);
- forNode(nodeIndex).clear();
break;
- }
- if (m_graph[node.child1()].shouldSpeculateInt16Array()) {
+ case Array::Int16Array:
forNode(node.child1()).filter(SpecInt16Array);
- forNode(nodeIndex).clear();
break;
- }
- if (m_graph[node.child1()].shouldSpeculateInt32Array()) {
+ case Array::Int32Array:
forNode(node.child1()).filter(SpecInt32Array);
- forNode(nodeIndex).clear();
break;
- }
- if (m_graph[node.child1()].shouldSpeculateUint8Array()) {
+ case Array::Uint8Array:
forNode(node.child1()).filter(SpecUint8Array);
- forNode(nodeIndex).clear();
break;
- }
- if (m_graph[node.child1()].shouldSpeculateUint8ClampedArray()) {
+ case Array::Uint8ClampedArray:
forNode(node.child1()).filter(SpecUint8ClampedArray);
- forNode(nodeIndex).clear();
break;
- }
- if (m_graph[node.child1()].shouldSpeculateUint16Array()) {
+ case Array::Uint16Array:
forNode(node.child1()).filter(SpecUint16Array);
- forNode(nodeIndex).set(SpecOther);
break;
- }
- if (m_graph[node.child1()].shouldSpeculateUint32Array()) {
+ case Array::Uint32Array:
forNode(node.child1()).filter(SpecUint32Array);
- forNode(nodeIndex).clear();
break;
- }
- if (m_graph[node.child1()].shouldSpeculateFloat32Array()) {
+ case Array::Float32Array:
forNode(node.child1()).filter(SpecFloat32Array);
- forNode(nodeIndex).clear();
break;
- }
- if (m_graph[node.child1()].shouldSpeculateFloat64Array()) {
+ case Array::Float64Array:
forNode(node.child1()).filter(SpecFloat64Array);
- forNode(nodeIndex).clear();
+ break;
+ default:
+ ASSERT_NOT_REACHED();
break;
}
- forNode(node.child1()).filter(SpecCell);
forNode(nodeIndex).clear();
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
index 000e1a938..2f535ba22 100644
--- a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
@@ -145,7 +145,7 @@ public:
}
// Figure out which variables alias the arguments and nothing else, and are
- // used only for GetByVal and GetArgumentsLength accesses. At the same time,
+ // used only for GetByVal and GetArrayLength accesses. At the same time,
// identify uses of CreateArguments that are not consistent with the arguments
// being aliased only to variables that satisfy these constraints.
for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
@@ -277,34 +277,25 @@ public:
}
case GetByVal: {
- if (!node.prediction()
- || !m_graph[node.child1()].prediction()
- || !m_graph[node.child2()].prediction()) {
+ if (node.arrayMode() != Array::Arguments) {
observeBadArgumentsUses(node);
break;
}
+
+ // That's so awful and pretty much impossible since it would
+ // imply that the arguments were predicted integer, but it's
+ // good to be defensive and thorough.
+ observeBadArgumentsUse(node.child2());
+ observeProperArgumentsUse(node, node.child1());
+ break;
+ }
- if (!isActionableArraySpeculation(m_graph[node.child1()].prediction())
- || !m_graph[node.child2()].shouldSpeculateInteger()) {
+ case GetArrayLength: {
+ if (node.arrayMode() != Array::Arguments) {
observeBadArgumentsUses(node);
break;
}
-
- if (m_graph[node.child1()].shouldSpeculateArguments()) {
- // If arguments is used as an index, then it's an escaping use.
- // That's so awful and pretty much impossible since it would
- // imply that the arguments were predicted integer, but it's
- // good to be defensive and thorough.
- observeBadArgumentsUse(node.child2());
- observeProperArgumentsUse(node, node.child1());
- break;
- }
-
- observeBadArgumentsUses(node);
- break;
- }
-
- case GetArgumentsLength: {
+
observeProperArgumentsUse(node, node.child1());
break;
}
@@ -496,38 +487,32 @@ public:
}
case GetByVal: {
- if (!node.prediction()
- || !m_graph[node.child1()].prediction()
- || !m_graph[node.child2()].prediction())
+ if (node.arrayMode() != Array::Arguments)
break;
+
+ // This can be simplified to GetMyArgumentByVal if we know that
+ // it satisfies either condition (1) or (2):
+ // 1) Its first child is a valid ArgumentsAliasingData and the
+ // InlineCallFrame* is not marked as creating arguments.
+ // 2) Its first child is CreateArguments and its InlineCallFrame*
+ // is not marked as creating arguments.
- if (!isActionableArraySpeculation(m_graph[node.child1()].prediction())
- || !m_graph[node.child2()].shouldSpeculateInteger())
+ if (!isOKToOptimize(m_graph[node.child1()]))
break;
- if (m_graph[node.child1()].shouldSpeculateArguments()) {
- // This can be simplified to GetMyArgumentByVal if we know that
- // it satisfies either condition (1) or (2):
- // 1) Its first child is a valid ArgumentsAliasingData and the
- // InlineCallFrame* is not marked as creating arguments.
- // 2) Its first child is CreateArguments and its InlineCallFrame*
- // is not marked as creating arguments.
-
- if (!isOKToOptimize(m_graph[node.child1()]))
- break;
-
- m_graph.deref(node.child1());
- node.children.child1() = node.children.child2();
- node.children.child2() = Edge();
- node.setOpAndDefaultFlags(GetMyArgumentByVal);
- changed = true;
- --indexInBlock; // Force reconsideration of this op now that it's a GetMyArgumentByVal.
- break;
- }
+ m_graph.deref(node.child1());
+ node.children.child1() = node.children.child2();
+ node.children.child2() = Edge();
+ node.setOpAndDefaultFlags(GetMyArgumentByVal);
+ changed = true;
+ --indexInBlock; // Force reconsideration of this op now that it's a GetMyArgumentByVal.
break;
}
- case GetArgumentsLength: {
+ case GetArrayLength: {
+ if (node.arrayMode() != Array::Arguments)
+ break;
+
if (!isOKToOptimize(m_graph[node.child1()]))
break;
diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
new file mode 100644
index 000000000..ec4edc2e8
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DFGArrayMode.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGAbstractValue.h"
+
+namespace JSC { namespace DFG {
+
+Array::Mode fromObserved(ArrayModes modes, bool makeSafe)
+{
+ // FIXME: we may want to add some polymorphic support in the future. That's why this
+ // is a switch statement right now.
+
+ switch (modes) {
+ case 0:
+ return Array::Undecided;
+ case IsJSArray:
+ return makeSafe ? Array::JSArrayOutOfBounds : Array::JSArray;
+ default:
+ // We know that this is possibly a kind of array for which, though there is no
+ // useful data in the array profile, we may be able to extract useful data from
+ // the value profiles of the inputs. Hence, we leave it as undecided, and let
+ // the predictions propagator decide later.
+ return Array::Undecided;
+ }
+}
+
+Array::Mode refineArrayMode(Array::Mode arrayMode, SpeculatedType base, SpeculatedType index)
+{
+ if (!base || !index) {
+ // It can be that we had a legitimate arrayMode but no incoming predictions. That'll
+ // happen if we inlined code based on, say, a global variable watchpoint, but later
+ // realized that the callsite could not have possibly executed. It may be worthwhile
+ // to fix that, but for now I'm leaving it as-is.
+ return Array::ForceExit;
+ }
+
+ 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:
+ return arrayMode;
+ default:
+ break;
+ }
+
+ if (isStringSpeculation(base))
+ return Array::String;
+
+ if (isArgumentsSpeculation(base))
+ return Array::Arguments;
+
+ if (isInt8ArraySpeculation(base))
+ return Array::Int8Array;
+
+ if (isInt16ArraySpeculation(base))
+ return Array::Int16Array;
+
+ if (isInt32ArraySpeculation(base))
+ return Array::Int32Array;
+
+ if (isUint8ArraySpeculation(base))
+ return Array::Uint8Array;
+
+ if (isUint8ClampedArraySpeculation(base))
+ return Array::Uint8ClampedArray;
+
+ if (isUint16ArraySpeculation(base))
+ return Array::Uint16Array;
+
+ if (isUint32ArraySpeculation(base))
+ return Array::Uint32Array;
+
+ if (isFloat32ArraySpeculation(base))
+ return Array::Float32Array;
+
+ if (isFloat64ArraySpeculation(base))
+ return Array::Float64Array;
+
+ return Array::Generic;
+}
+
+bool modeAlreadyChecked(AbstractValue& value, Array::Mode arrayMode)
+{
+ switch (arrayMode) {
+ case Array::Generic:
+ return true;
+
+ case Array::ForceExit:
+ return false;
+
+ case Array::String:
+ return isStringSpeculation(value.m_type);
+
+ case Array::JSArray:
+ case Array::JSArrayOutOfBounds:
+ return value.m_currentKnownStructure.hasSingleton()
+ && value.m_currentKnownStructure.singleton()->classInfo() == &JSArray::s_info;
+
+ case Array::Arguments:
+ return isArgumentsSpeculation(value.m_type);
+
+ case Array::Int8Array:
+ return isInt8ArraySpeculation(value.m_type);
+
+ case Array::Int16Array:
+ return isInt16ArraySpeculation(value.m_type);
+
+ case Array::Int32Array:
+ return isInt32ArraySpeculation(value.m_type);
+
+ case Array::Uint8Array:
+ return isUint8ArraySpeculation(value.m_type);
+
+ case Array::Uint8ClampedArray:
+ return isUint8ClampedArraySpeculation(value.m_type);
+
+ case Array::Uint16Array:
+ return isUint16ArraySpeculation(value.m_type);
+
+ case Array::Uint32Array:
+ return isUint32ArraySpeculation(value.m_type);
+
+ case Array::Float32Array:
+ return isFloat32ArraySpeculation(value.m_type);
+
+ case Array::Float64Array:
+ return isFloat64ArraySpeculation(value.m_type);
+
+ case Array::Undecided:
+ break;
+ }
+
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+const char* modeToString(Array::Mode mode)
+{
+ switch (mode) {
+ case Array::Undecided:
+ return "Undecided";
+ case Array::Generic:
+ return "Generic";
+ case Array::ForceExit:
+ return "ForceExit";
+ case Array::String:
+ return "String";
+ case Array::JSArray:
+ return "JSArray";
+ case Array::JSArrayOutOfBounds:
+ return "JSArrayOutOfBounds";
+ case Array::Arguments:
+ return "Arguments";
+ case Array::Int8Array:
+ return "Int8Array";
+ case Array::Int16Array:
+ return "Int16Array";
+ case Array::Int32Array:
+ return "Int32Array";
+ case Array::Uint8Array:
+ return "Uint8Array";
+ case Array::Uint8ClampedArray:
+ return "Uint8ClampedArray";
+ case Array::Uint16Array:
+ return "Uint16Array";
+ case Array::Uint32Array:
+ return "Uint32Array";
+ case Array::Float32Array:
+ return "Float32Array";
+ case Array::Float64Array:
+ return "Float64Array";
+ default:
+ // Better to return something then it is to crash. Remember, this method
+ // is being called from our main diagnostic tool, the IR dumper. It's like
+ // a stack trace. So if we get here then probably something has already
+ // gone wrong.
+ return "Unknown!";
+ }
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.h b/Source/JavaScriptCore/dfg/DFGArrayMode.h
new file mode 100644
index 000000000..6ce62ae72
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGArrayMode.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGArrayMode_h
+#define DFGArrayMode_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(DFG_JIT)
+
+#include "ArrayProfile.h"
+#include "SpeculatedType.h"
+
+namespace JSC { namespace DFG {
+
+struct AbstractValue;
+
+// Use a namespace + enum instead of enum alone to avoid the namespace collision
+// that would otherwise occur, since we say things like "Int8Array" and "JSArray"
+// in lots of other places, to mean subtly different things.
+namespace Array {
+enum Mode {
+ Undecided, // Implies that we need predictions to decide. We will never get to the backend in this mode.
+ ForceExit, // Implies that we have no idea how to execute this operation, so we should just give up.
+ Generic,
+ String,
+ JSArray,
+ JSArrayOutOfBounds,
+ Arguments,
+ Int8Array,
+ Int16Array,
+ Int32Array,
+ Uint8Array,
+ Uint8ClampedArray,
+ Uint16Array,
+ Uint32Array,
+ Float32Array,
+ Float64Array
+};
+} // namespace Array
+
+Array::Mode fromObserved(ArrayModes modes, bool makeSafe);
+
+Array::Mode refineArrayMode(Array::Mode, SpeculatedType base, SpeculatedType index);
+
+bool modeAlreadyChecked(AbstractValue&, Array::Mode);
+
+const char* modeToString(Array::Mode);
+
+inline bool canCSEStorage(Array::Mode arrayMode)
+{
+ switch (arrayMode) {
+ case Array::Undecided:
+ case Array::ForceExit:
+ case Array::Generic:
+ case Array::Arguments:
+ return false;
+ default:
+ return true;
+ }
+}
+
+inline Array::Mode modeForPut(Array::Mode arrayMode)
+{
+ switch (arrayMode) {
+ case Array::String:
+ return Array::Generic;
+#if USE(JSVALUE32_64)
+ case Array::Arguments:
+ return Array::Generic;
+#endif
+ default:
+ return arrayMode;
+ }
+}
+
+inline bool modesCompatibleForStorageLoad(Array::Mode left, Array::Mode right)
+{
+ if (left == right)
+ return true;
+
+ bool leftIsJSArray =
+ left == Array::JSArray
+ || left == Array::JSArrayOutOfBounds;
+
+ bool rightIsJSArray =
+ right == Array::JSArray
+ || right == Array::JSArrayOutOfBounds;
+
+ if (leftIsJSArray && rightIsJSArray)
+ return true;
+
+ return false;
+}
+
+inline bool modeSupportsLength(Array::Mode mode)
+{
+ switch (mode) {
+ case Array::Undecided:
+ case Array::ForceExit:
+ case Array::Generic:
+ return false;
+ default:
+ return true;
+ }
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGArrayMode_h
+
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index f7536f87f..f9b1db9ab 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -31,6 +31,7 @@
#include "ArrayConstructor.h"
#include "CallLinkStatus.h"
#include "CodeBlock.h"
+#include "DFGArrayMode.h"
#include "DFGByteCodeCache.h"
#include "DFGCapabilities.h"
#include "GetByIdStatus.h"
@@ -816,6 +817,36 @@ private:
{
return getPrediction(m_graph.size(), m_currentProfilingIndex);
}
+
+ Array::Mode getArrayModeWithoutOSRExit(Instruction* currentInstruction, NodeIndex base)
+ {
+ ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
+ profile->computeUpdatedPrediction();
+ if (profile->hasDefiniteStructure())
+ addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(profile->expectedStructure())), base);
+
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ if (m_inlineStackTop->m_profiledBlock->numberOfRareCaseProfiles())
+ dataLog("Slow case profile for bc#%u: %u\n", m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter);
+ dataLog("Array profile for bc#%u: %p%s, %u\n", m_currentIndex, profile->expectedStructure(), profile->structureIsPolymorphic() ? " (polymorphic)" : "", profile->observedArrayModes());
+#endif
+
+ bool makeSafe =
+ m_inlineStackTop->m_profiledBlock->couldTakeSlowCase(m_currentIndex)
+ || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, OutOfBounds);
+
+ 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)
{
@@ -1548,8 +1579,7 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins
return false;
int indexOperand = registerOffset + argumentToOperand(1);
- NodeIndex storage = addToGraph(GetIndexedPropertyStorage, get(thisOperand), getToInt32(indexOperand));
- NodeIndex charCode = addToGraph(StringCharCodeAt, get(thisOperand), getToInt32(indexOperand), storage);
+ NodeIndex charCode = addToGraph(StringCharCodeAt, OpInfo(Array::String), get(thisOperand), getToInt32(indexOperand));
if (usesResult)
set(resultOperand, charCode);
@@ -1565,8 +1595,7 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins
return false;
int indexOperand = registerOffset + argumentToOperand(1);
- NodeIndex storage = addToGraph(GetIndexedPropertyStorage, get(thisOperand), getToInt32(indexOperand));
- NodeIndex charCode = addToGraph(StringCharAt, get(thisOperand), getToInt32(indexOperand), storage);
+ NodeIndex charCode = addToGraph(StringCharAt, OpInfo(Array::String), get(thisOperand), getToInt32(indexOperand));
if (usesResult)
set(resultOperand, charCode);
@@ -2148,13 +2177,9 @@ bool ByteCodeParser::parseBlock(unsigned limit)
SpeculatedType prediction = getPrediction();
NodeIndex base = get(currentInstruction[2].u.operand);
+ Array::Mode arrayMode = getArrayMode(currentInstruction, base);
NodeIndex property = get(currentInstruction[3].u.operand);
- ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
- profile->computeUpdatedPrediction();
- if (profile->hasDefiniteStructure())
- addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(profile->expectedStructure())), base);
- NodeIndex propertyStorage = addToGraph(GetIndexedPropertyStorage, base, property);
- NodeIndex getByVal = addToGraph(GetByVal, OpInfo(0), OpInfo(prediction), base, property, propertyStorage);
+ NodeIndex getByVal = addToGraph(GetByVal, OpInfo(arrayMode), OpInfo(prediction), base, property);
set(currentInstruction[1].u.operand, getByVal);
NEXT_OPCODE(op_get_by_val);
@@ -2162,26 +2187,16 @@ bool ByteCodeParser::parseBlock(unsigned limit)
case op_put_by_val: {
NodeIndex base = get(currentInstruction[1].u.operand);
+
+ Array::Mode arrayMode = getArrayMode(currentInstruction, base);
+
NodeIndex property = get(currentInstruction[2].u.operand);
NodeIndex value = get(currentInstruction[3].u.operand);
- ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
- profile->computeUpdatedPrediction();
- if (profile->hasDefiniteStructure())
- addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(profile->expectedStructure())), base);
-
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("Slow case profile for bc#%u: %u\n", m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter);
-#endif
-
- bool makeSafe =
- m_inlineStackTop->m_profiledBlock->couldTakeSlowCase(m_currentIndex)
- || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, OutOfBounds);
-
addVarArgChild(base);
addVarArgChild(property);
addVarArgChild(value);
- addToGraph(Node::VarArg, makeSafe ? PutByValSafe : PutByVal, OpInfo(0), OpInfo(0));
+ addToGraph(Node::VarArg, PutByVal, OpInfo(arrayMode), OpInfo(0));
NEXT_OPCODE(op_put_by_val);
}
diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
index b78ddc89d..dce57d520 100644
--- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
@@ -284,8 +284,7 @@ private:
return index;
break;
case PutByVal:
- case PutByValAlias:
- case PutByValSafe: {
+ case PutByValAlias: {
if (!m_graph.byValIsPure(node))
return NoNode;
if (m_graph.varArgChild(node, 0) == child1 && canonicalize(m_graph.varArgChild(node, 1)) == canonicalize(child2))
@@ -365,7 +364,6 @@ private:
case PutByVal:
case PutByValAlias:
- case PutByValSafe:
if (m_graph.byValIsPure(node)) {
// If PutByVal speculates that it's accessing an array with an
// integer index, then it's impossible for it to cause a structure
@@ -409,7 +407,6 @@ private:
case PutByVal:
case PutByValAlias:
- case PutByValSafe:
if (m_graph.byValIsPure(node)) {
// If PutByVal speculates that it's accessing an array with an
// integer index, then it's impossible for it to cause a structure
@@ -515,7 +512,6 @@ private:
case PutByVal:
case PutByValAlias:
- case PutByValSafe:
if (m_graph.byValIsPure(node)) {
// If PutByVal speculates that it's accessing an array with an
// integer index, then it's impossible for it to cause a structure
@@ -560,7 +556,6 @@ private:
case PutByVal:
case PutByValAlias:
case GetByVal:
- case PutByValSafe:
if (m_graph.byValIsPure(node)) {
// If PutByVal speculates that it's accessing an array with an
// integer index, then it's impossible for it to cause a structure
@@ -613,7 +608,6 @@ private:
case PutByVal:
case PutByValAlias:
- case PutByValSafe:
if (m_graph.byValIsPure(node)) {
// If PutByVal speculates that it's accessing an array with an
// integer index, then it's impossible for it to cause a structure
@@ -925,17 +919,7 @@ private:
case ArithMin:
case ArithMax:
case ArithSqrt:
- case GetInt8ArrayLength:
- case GetInt16ArrayLength:
- case GetInt32ArrayLength:
- case GetUint8ArrayLength:
- case GetUint8ClampedArrayLength:
- case GetUint16ArrayLength:
- case GetUint32ArrayLength:
- case GetFloat32ArrayLength:
- case GetFloat64ArrayLength:
case GetCallee:
- case GetStringLength:
case StringCharAt:
case StringCharCodeAt:
case Int32ToDouble:
@@ -1103,8 +1087,7 @@ private:
setReplacement(getByValLoadElimination(node.child1().index(), node.child2().index()));
break;
- case PutByVal:
- case PutByValSafe: {
+ case PutByVal: {
Edge child1 = m_graph.varArgChild(node, 0);
Edge child2 = m_graph.varArgChild(node, 1);
if (isActionableMutableArraySpeculation(m_graph[child1].prediction())
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index f7b10fc43..fe7cae8a9 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -74,97 +74,89 @@ private:
switch (op) {
case GetById: {
+ Node* nodePtr = &node;
+
if (!isInt32Speculation(m_graph[m_compileIndex].prediction()))
break;
- if (codeBlock()->identifier(node.identifierNumber()) != globalData().propertyNames->length)
- break;
- bool isArray = isArraySpeculation(m_graph[node.child1()].prediction());
- bool isArguments = isArgumentsSpeculation(m_graph[node.child1()].prediction());
- bool isString = isStringSpeculation(m_graph[node.child1()].prediction());
- bool isInt8Array = m_graph[node.child1()].shouldSpeculateInt8Array();
- bool isInt16Array = m_graph[node.child1()].shouldSpeculateInt16Array();
- bool isInt32Array = m_graph[node.child1()].shouldSpeculateInt32Array();
- bool isUint8Array = m_graph[node.child1()].shouldSpeculateUint8Array();
- bool isUint8ClampedArray = m_graph[node.child1()].shouldSpeculateUint8ClampedArray();
- bool isUint16Array = m_graph[node.child1()].shouldSpeculateUint16Array();
- bool isUint32Array = m_graph[node.child1()].shouldSpeculateUint32Array();
- bool isFloat32Array = m_graph[node.child1()].shouldSpeculateFloat32Array();
- bool isFloat64Array = m_graph[node.child1()].shouldSpeculateFloat64Array();
- if (!isArray && !isArguments && !isString && !isInt8Array && !isInt16Array && !isInt32Array && !isUint8Array && !isUint8ClampedArray && !isUint16Array && !isUint32Array && !isFloat32Array && !isFloat64Array)
+ if (codeBlock()->identifier(nodePtr->identifierNumber()) != globalData().propertyNames->length)
break;
-
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" @%u -> %s", m_compileIndex, isArray ? "GetArrayLength" : "GetStringLength");
-#endif
- if (isArray) {
- node.setOp(GetArrayLength);
- ASSERT(node.flags() & NodeMustGenerate);
- node.clearFlags(NodeMustGenerate);
- m_graph.deref(m_compileIndex);
-
- ArrayProfile* arrayProfile =
- m_graph.baselineCodeBlockFor(node.codeOrigin)->getArrayProfile(
- node.codeOrigin.bytecodeIndex);
- if (!arrayProfile)
- break;
+ ArrayProfile* arrayProfile =
+ m_graph.baselineCodeBlockFor(nodePtr->codeOrigin)->getArrayProfile(
+ nodePtr->codeOrigin.bytecodeIndex);
+ Array::Mode arrayMode = Array::Undecided;
+ if (arrayProfile) {
arrayProfile->computeUpdatedPrediction();
- if (!arrayProfile->hasDefiniteStructure())
- break;
- m_graph.ref(node.child1());
- Node checkStructure(CheckStructure, node.codeOrigin, OpInfo(m_graph.addStructureSet(arrayProfile->expectedStructure())), node.child1().index());
- checkStructure.ref();
- NodeIndex checkStructureIndex = m_graph.size();
- m_graph.append(checkStructure);
- m_insertionSet.append(m_indexInBlock, checkStructureIndex);
- break;
+ arrayMode = refineArrayMode(
+ fromObserved(arrayProfile->observedArrayModes(), false),
+ m_graph[node.child1()].prediction(),
+ m_graph[m_compileIndex].prediction());
+ 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();
+ NodeIndex checkStructureIndex = m_graph.size();
+ m_graph.append(checkStructure);
+ m_insertionSet.append(m_indexInBlock, checkStructureIndex);
+ nodePtr = &m_graph[m_compileIndex];
+ }
+ } else {
+ arrayMode = refineArrayMode(
+ arrayMode,
+ m_graph[node.child1()].prediction(),
+ m_graph[m_compileIndex].prediction());
}
- if (isArguments)
- node.setOp(GetArgumentsLength);
- else if (isString)
- node.setOp(GetStringLength);
- else if (isInt8Array)
- node.setOp(GetInt8ArrayLength);
- else if (isInt16Array)
- node.setOp(GetInt16ArrayLength);
- else if (isInt32Array)
- node.setOp(GetInt32ArrayLength);
- else if (isUint8Array)
- node.setOp(GetUint8ArrayLength);
- else if (isUint8ClampedArray)
- node.setOp(GetUint8ClampedArrayLength);
- else if (isUint16Array)
- node.setOp(GetUint16ArrayLength);
- else if (isUint32Array)
- node.setOp(GetUint32ArrayLength);
- else if (isFloat32Array)
- node.setOp(GetFloat32ArrayLength);
- else if (isFloat64Array)
- node.setOp(GetFloat64ArrayLength);
- else
- ASSERT_NOT_REACHED();
- // No longer MustGenerate
- ASSERT(node.flags() & NodeMustGenerate);
- node.clearFlags(NodeMustGenerate);
+ if (!modeSupportsLength(arrayMode))
+ break;
+ nodePtr->setOp(GetArrayLength);
+ ASSERT(nodePtr->flags() & NodeMustGenerate);
+ nodePtr->clearFlags(NodeMustGenerate);
m_graph.deref(m_compileIndex);
+ nodePtr->setArrayMode(arrayMode);
break;
}
case GetIndexedPropertyStorage: {
- if (!m_graph[node.child1()].prediction()
- || !m_graph[node.child2()].shouldSpeculateInteger()
- || m_graph[node.child1()].shouldSpeculateArguments()) {
- node.setOpAndDefaultFlags(Nop);
- m_graph.clearAndDerefChild1(node);
- m_graph.clearAndDerefChild2(node);
- m_graph.clearAndDerefChild3(node);
- node.setRefCount(0);
- }
+ 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;
}
case GetByVal:
case StringCharAt:
case StringCharCodeAt: {
- if (!!node.child3() && m_graph[node.child3()].op() == Nop)
- node.children.child3() = Edge();
+ node.setArrayMode(
+ refineArrayMode(
+ node.arrayMode(),
+ 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());
+ }
break;
}
@@ -334,24 +326,30 @@ private:
}
case PutByVal:
- case PutByValSafe: {
+ case PutByValAlias: {
Edge child1 = m_graph.varArgChild(node, 0);
Edge child2 = m_graph.varArgChild(node, 1);
Edge child3 = m_graph.varArgChild(node, 2);
- if (!m_graph[child1].prediction() || !m_graph[child2].prediction())
- break;
- if (!m_graph[child2].shouldSpeculateInteger())
+ node.setArrayMode(
+ refineArrayMode(
+ node.arrayMode(), m_graph[child1].prediction(), m_graph[child2].prediction()));
+
+ switch (modeForPut(node.arrayMode())) {
+ case Array::Int8Array:
+ case Array::Int16Array:
+ case Array::Int32Array:
+ case Array::Uint8Array:
+ case Array::Uint8ClampedArray:
+ case Array::Uint16Array:
+ case Array::Uint32Array:
+ if (!m_graph[child3].shouldSpeculateInteger())
+ fixDoubleEdge(2);
break;
- if (isActionableIntMutableArraySpeculation(m_graph[child1].prediction())) {
- if (m_graph[child3].isConstant())
- break;
- if (m_graph[child3].shouldSpeculateInteger())
- break;
+ case Array::Float32Array:
+ case Array::Float64Array:
fixDoubleEdge(2);
break;
- }
- if (isActionableFloatMutableArraySpeculation(m_graph[child1].prediction())) {
- fixDoubleEdge(2);
+ default:
break;
}
break;
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp
index 9ae0648b8..8e80ff2fc 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.cpp
+++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp
@@ -211,6 +211,10 @@ void Graph::dump(const char* prefix, NodeIndex nodeIndex)
dataLog("%s%s", hasPrinted ? ", " : "", nodeFlagsAsString(node.flags()));
hasPrinted = true;
}
+ if (node.hasArrayMode()) {
+ dataLog("%s%s", hasPrinted ? ", " : "", modeToString(node.arrayMode()));
+ hasPrinted = true;
+ }
if (node.hasVarNumber()) {
dataLog("%svar%u", hasPrinted ? ", " : "", node.varNumber());
hasPrinted = true;
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index 8d164a299..ba5d86f81 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -488,48 +488,20 @@ public:
bool byValIsPure(Node& node)
{
- switch (node.op()) {
- case PutByVal: {
- if (!at(varArgChild(node, 1)).shouldSpeculateInteger())
- return false;
- SpeculatedType prediction = at(varArgChild(node, 0)).prediction();
- if (!isActionableMutableArraySpeculation(prediction))
- return false;
- return true;
- }
-
- case PutByValSafe: {
- if (!at(varArgChild(node, 1)).shouldSpeculateInteger())
- return false;
- SpeculatedType prediction = at(varArgChild(node, 0)).prediction();
- if (!isActionableMutableArraySpeculation(prediction))
- return false;
- if (isArraySpeculation(prediction))
- return false;
- return true;
- }
-
- case PutByValAlias: {
- if (!at(varArgChild(node, 1)).shouldSpeculateInteger())
- return false;
- SpeculatedType prediction = at(varArgChild(node, 0)).prediction();
- if (!isActionableMutableArraySpeculation(prediction))
- return false;
- return true;
- }
-
- case GetByVal: {
- if (!at(node.child2()).shouldSpeculateInteger())
- return false;
- SpeculatedType prediction = at(node.child1()).prediction();
- if (!isActionableArraySpeculation(prediction))
- return false;
- return true;
- }
-
- default:
- ASSERT_NOT_REACHED();
+ switch (node.arrayMode()) {
+ case Array::Generic:
+ case Array::JSArrayOutOfBounds:
return false;
+ case Array::String:
+ return node.op() == GetByVal;
+#if USE(JSVALUE32_64)
+ case Array::Arguments:
+ if (node.op() == GetByVal)
+ return true;
+ return false;
+#endif // USE(JSVALUE32_64)
+ default:
+ return true;
}
}
@@ -549,7 +521,6 @@ public:
return !isPredictedNumerical(node);
case GetByVal:
case PutByVal:
- case PutByValSafe:
case PutByValAlias:
return !byValIsPure(node);
default:
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index dac855be0..7ca4d8d48 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -33,6 +33,7 @@
#include "CodeBlock.h"
#include "CodeOrigin.h"
#include "DFGAdjacencyList.h"
+#include "DFGArrayMode.h"
#include "DFGCommon.h"
#include "DFGNodeFlags.h"
#include "DFGNodeType.h"
@@ -732,6 +733,34 @@ struct Node {
return m_opInfo;
}
+ bool hasArrayMode()
+ {
+ switch (op()) {
+ case GetIndexedPropertyStorage:
+ case GetArrayLength:
+ case PutByVal:
+ case PutByValAlias:
+ case GetByVal:
+ case StringCharAt:
+ case StringCharCodeAt:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ Array::Mode arrayMode()
+ {
+ ASSERT(hasArrayMode());
+ return static_cast<Array::Mode>(m_opInfo);
+ }
+
+ void setArrayMode(Array::Mode arrayMode)
+ {
+ ASSERT(hasArrayMode());
+ m_opInfo = arrayMode;
+ }
+
bool hasVirtualRegister()
{
return m_virtualRegister != InvalidVirtualRegister;
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index f0f8cb1d0..ee5ad9013 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -113,7 +113,6 @@ namespace JSC { namespace DFG {
/* opcodes use VarArgs beause they may have up to 4 children. */\
macro(GetByVal, NodeResultJS | NodeMustGenerate | NodeMightClobber) \
macro(PutByVal, NodeMustGenerate | NodeHasVarArgs | NodeMightClobber) \
- macro(PutByValSafe, NodeMustGenerate | NodeHasVarArgs | NodeMightClobber) \
macro(PutByValAlias, NodeMustGenerate | NodeHasVarArgs | NodeMightClobber) \
macro(GetById, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
macro(GetByIdFlush, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
@@ -143,17 +142,6 @@ namespace JSC { namespace DFG {
macro(GetByOffset, NodeResultJS) \
macro(PutByOffset, NodeMustGenerate) \
macro(GetArrayLength, NodeResultInt32) \
- macro(GetArgumentsLength, NodeResultInt32) \
- macro(GetStringLength, NodeResultInt32) \
- macro(GetInt8ArrayLength, NodeResultInt32) \
- macro(GetInt16ArrayLength, NodeResultInt32) \
- macro(GetInt32ArrayLength, NodeResultInt32) \
- macro(GetUint8ArrayLength, NodeResultInt32) \
- macro(GetUint8ClampedArrayLength, NodeResultInt32) \
- macro(GetUint16ArrayLength, NodeResultInt32) \
- macro(GetUint32ArrayLength, NodeResultInt32) \
- macro(GetFloat32ArrayLength, NodeResultInt32) \
- macro(GetFloat64ArrayLength, NodeResultInt32) \
macro(GetScopeChain, NodeResultJS) \
macro(GetScopedVar, NodeResultJS | NodeMustGenerate) \
macro(PutScopedVar, NodeMustGenerate | NodeClobbersWorld) \
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index 1247528e8..258d1199a 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -612,17 +612,6 @@ private:
case PutByValAlias:
case GetArrayLength:
- case GetArgumentsLength:
- case GetInt8ArrayLength:
- case GetInt16ArrayLength:
- case GetInt32ArrayLength:
- case GetUint8ArrayLength:
- case GetUint8ClampedArrayLength:
- case GetUint16ArrayLength:
- case GetUint32ArrayLength:
- case GetFloat32ArrayLength:
- case GetFloat64ArrayLength:
- case GetStringLength:
case Int32ToDouble:
case DoubleAsInt32:
case GetLocalUnlinked:
@@ -637,7 +626,6 @@ private:
}
case PutByVal:
- case PutByValSafe:
changed |= m_graph[m_graph.varArgChild(node, 0)].mergeFlags(NodeUsedAsValue);
changed |= m_graph[m_graph.varArgChild(node, 1)].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
changed |= m_graph[m_graph.varArgChild(node, 2)].mergeFlags(NodeUsedAsValue);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 6c6615716..d74207420 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -269,12 +269,82 @@ void SpeculativeJIT::clearGenerationInfo()
m_fprs = RegisterBank<FPRInfo>();
}
-void SpeculativeJIT::speculateArray(Edge edge, GPRReg baseReg)
+const TypedArrayDescriptor* SpeculativeJIT::typedArrayDescriptor(Array::Mode arrayMode)
+{
+ switch (arrayMode) {
+ case Array::Int8Array:
+ return &m_jit.globalData()->int8ArrayDescriptor();
+ case Array::Int16Array:
+ return &m_jit.globalData()->int16ArrayDescriptor();
+ case Array::Int32Array:
+ return &m_jit.globalData()->int32ArrayDescriptor();
+ case Array::Uint8Array:
+ return &m_jit.globalData()->uint8ArrayDescriptor();
+ case Array::Uint8ClampedArray:
+ return &m_jit.globalData()->uint8ClampedArrayDescriptor();
+ case Array::Uint16Array:
+ return &m_jit.globalData()->uint16ArrayDescriptor();
+ case Array::Uint32Array:
+ return &m_jit.globalData()->uint32ArrayDescriptor();
+ case Array::Float32Array:
+ return &m_jit.globalData()->float32ArrayDescriptor();
+ case Array::Float64Array:
+ return &m_jit.globalData()->float32ArrayDescriptor();
+ default:
+ return 0;
+ }
+}
+
+const TypedArrayDescriptor* SpeculativeJIT::speculateArray(Array::Mode arrayMode, Edge edge, GPRReg baseReg)
{
- AbstractValue& arrayValue = m_state.forNode(edge);
- if (arrayValue.m_currentKnownStructure.hasSingleton()
- && arrayValue.m_currentKnownStructure.singleton()->classInfo() == &JSArray::s_info)
- return;
+ const TypedArrayDescriptor* result = typedArrayDescriptor(arrayMode);
+
+ if (modeAlreadyChecked(m_state.forNode(edge), arrayMode))
+ return result;
+
+ const ClassInfo* expectedClassInfo = 0;
+
+ switch (arrayMode) {
+ case Array::ForceExit:
+ ASSERT_NOT_REACHED();
+ terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode);
+ return result;
+ case Array::String:
+ expectedClassInfo = &JSString::s_info;
+ break;
+ case Array::JSArray:
+ case Array::JSArrayOutOfBounds: {
+ // This code duplicates the code below in anticipation of this code being
+ // substantially changed in the future.
+ GPRTemporary temp(this);
+ m_jit.loadPtr(
+ MacroAssembler::Address(baseReg, JSCell::structureOffset()), temp.gpr());
+ speculationCheck(
+ Uncountable, JSValueRegs(), NoNode,
+ m_jit.branchPtr(
+ MacroAssembler::NotEqual,
+ MacroAssembler::Address(temp.gpr(), Structure::classInfoOffset()),
+ MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
+ return result;
+ }
+ case Array::Arguments:
+ expectedClassInfo = &Arguments::s_info;
+ break;
+ case Array::Int8Array:
+ case Array::Int16Array:
+ case Array::Int32Array:
+ case Array::Uint8Array:
+ case Array::Uint8ClampedArray:
+ case Array::Uint16Array:
+ case Array::Uint32Array:
+ case Array::Float32Array:
+ case Array::Float64Array:
+ expectedClassInfo = result->m_classInfo;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
GPRTemporary temp(this);
m_jit.loadPtr(
@@ -284,7 +354,9 @@ void SpeculativeJIT::speculateArray(Edge edge, GPRReg baseReg)
m_jit.branchPtr(
MacroAssembler::NotEqual,
MacroAssembler::Address(temp.gpr(), Structure::classInfoOffset()),
- MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
+ MacroAssembler::TrustedImmPtr(expectedClassInfo)));
+
+ return result;
}
GPRReg SpeculativeJIT::fillStorage(NodeIndex nodeIndex)
@@ -1620,11 +1692,7 @@ void SpeculativeJIT::compileGetByValOnString(Node& node)
GPRReg propertyReg = property.gpr();
GPRReg storageReg = storage.gpr();
- if (!isStringSpeculation(m_state.forNode(node.child1()).m_type)) {
- terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
- noResult(m_compileIndex);
- return;
- }
+ ASSERT(modeAlreadyChecked(m_state.forNode(node.child1()), Array::String));
// unsigned comparison so we can filter out negative indices and indices that are too large
speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSString::offsetOfLength())));
@@ -2018,23 +2086,7 @@ static void compileClampDoubleToByte(JITCompiler& jit, GPRReg result, FPRReg sou
}
-void SpeculativeJIT::compileGetTypedArrayLength(const TypedArrayDescriptor& descriptor, Node& node, bool needsSpeculationCheck)
-{
- SpeculateCellOperand base(this, node.child1());
- GPRTemporary result(this);
-
- GPRReg baseGPR = base.gpr();
- GPRReg resultGPR = result.gpr();
-
- if (needsSpeculationCheck)
- speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo)));
-
- m_jit.load32(MacroAssembler::Address(baseGPR, descriptor.m_lengthOffset), resultGPR);
-
- integerResult(resultGPR, m_compileIndex);
-}
-
-void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor& descriptor, Node& node, size_t elementSize, TypedArraySpeculationRequirements speculationRequirements, TypedArraySignedness signedness)
+void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor& descriptor, Node& node, size_t elementSize, TypedArraySignedness signedness)
{
SpeculateCellOperand base(this, node.child1());
SpeculateStrictInt32Operand property(this, node.child2());
@@ -2047,12 +2099,7 @@ void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor&
GPRTemporary result(this);
GPRReg resultReg = result.gpr();
- if (speculationRequirements != NoTypedArrayTypeSpecCheck) {
- ASSERT_NOT_REACHED();
- terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
- noResult(m_compileIndex);
- return;
- }
+ ASSERT(modeAlreadyChecked(m_state.forNode(node.child1()), node.arrayMode()));
speculationCheck(
Uncountable, JSValueRegs(), NoNode,
@@ -2097,13 +2144,10 @@ void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor&
doubleResult(fresult.fpr(), m_compileIndex);
}
-void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor& descriptor, GPRReg base, GPRReg property, Node& node, size_t elementSize, TypedArraySpeculationRequirements speculationRequirements, TypedArraySignedness signedness, TypedArrayRounding rounding)
+void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor& descriptor, GPRReg base, GPRReg property, Node& node, size_t elementSize, TypedArraySignedness signedness, TypedArrayRounding rounding)
{
- Edge baseUse = m_jit.graph().varArgChild(node, 0);
Edge valueUse = m_jit.graph().varArgChild(node, 2);
- if (speculationRequirements != NoTypedArrayTypeSpecCheck)
- speculationCheck(BadType, JSValueSource::unboxedCell(base), baseUse, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(base, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo)));
GPRTemporary value;
GPRReg valueGPR;
@@ -2174,7 +2218,7 @@ void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor&
ASSERT(valueGPR != storageReg);
m_jit.loadPtr(MacroAssembler::Address(base, descriptor.m_storageOffset), storageReg);
MacroAssembler::Jump outOfBounds;
- if (speculationRequirements != NoTypedArraySpecCheck)
+ if (node.op() == PutByVal)
outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, property, MacroAssembler::Address(base, descriptor.m_lengthOffset));
switch (elementSize) {
@@ -2190,12 +2234,12 @@ void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor&
default:
ASSERT_NOT_REACHED();
}
- if (speculationRequirements != NoTypedArraySpecCheck)
+ if (node.op() == PutByVal)
outOfBounds.link(&m_jit);
noResult(m_compileIndex);
}
-void SpeculativeJIT::compileGetByValOnFloatTypedArray(const TypedArrayDescriptor& descriptor, Node& node, size_t elementSize, TypedArraySpeculationRequirements speculationRequirements)
+void SpeculativeJIT::compileGetByValOnFloatTypedArray(const TypedArrayDescriptor& descriptor, Node& node, size_t elementSize)
{
SpeculateCellOperand base(this, node.child1());
SpeculateStrictInt32Operand property(this, node.child2());
@@ -2204,17 +2248,11 @@ void SpeculativeJIT::compileGetByValOnFloatTypedArray(const TypedArrayDescriptor
GPRReg baseReg = base.gpr();
GPRReg propertyReg = property.gpr();
GPRReg storageReg = storage.gpr();
-
- if (speculationRequirements != NoTypedArrayTypeSpecCheck) {
- ASSERT_NOT_REACHED();
- terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
- noResult(m_compileIndex);
- return;
- }
+
+ ASSERT(modeAlreadyChecked(m_state.forNode(node.child1()), node.arrayMode()));
FPRTemporary result(this);
FPRReg resultReg = result.fpr();
- ASSERT(speculationRequirements != NoTypedArraySpecCheck);
speculationCheck(
Uncountable, JSValueRegs(), NoNode,
m_jit.branch32(
@@ -2238,15 +2276,14 @@ void SpeculativeJIT::compileGetByValOnFloatTypedArray(const TypedArrayDescriptor
doubleResult(resultReg, m_compileIndex);
}
-void SpeculativeJIT::compilePutByValForFloatTypedArray(const TypedArrayDescriptor& descriptor, GPRReg base, GPRReg property, Node& node, size_t elementSize, TypedArraySpeculationRequirements speculationRequirements)
+void SpeculativeJIT::compilePutByValForFloatTypedArray(const TypedArrayDescriptor& descriptor, GPRReg base, GPRReg property, Node& node, size_t elementSize)
{
Edge baseUse = m_jit.graph().varArgChild(node, 0);
Edge valueUse = m_jit.graph().varArgChild(node, 2);
SpeculateDoubleOperand valueOp(this, valueUse);
- if (speculationRequirements != NoTypedArrayTypeSpecCheck)
- speculationCheck(BadType, JSValueSource::unboxedCell(base), baseUse.index(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(base, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo)));
+ ASSERT_UNUSED(baseUse, modeAlreadyChecked(m_state.forNode(baseUse), node.arrayMode()));
GPRTemporary result(this);
@@ -2255,7 +2292,7 @@ void SpeculativeJIT::compilePutByValForFloatTypedArray(const TypedArrayDescripto
m_jit.loadPtr(MacroAssembler::Address(base, descriptor.m_storageOffset), storageReg);
MacroAssembler::Jump outOfBounds;
- if (speculationRequirements != NoTypedArraySpecCheck)
+ if (node.op() == PutByVal)
outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, property, MacroAssembler::Address(base, descriptor.m_lengthOffset));
switch (elementSize) {
@@ -2272,7 +2309,7 @@ void SpeculativeJIT::compilePutByValForFloatTypedArray(const TypedArrayDescripto
default:
ASSERT_NOT_REACHED();
}
- if (speculationRequirements != NoTypedArraySpecCheck)
+ if (node.op() == PutByVal)
outOfBounds.link(&m_jit);
noResult(m_compileIndex);
}
@@ -3066,75 +3103,36 @@ bool SpeculativeJIT::compileStrictEq(Node& node)
void SpeculativeJIT::compileGetIndexedPropertyStorage(Node& node)
{
- ASSERT(at(node.child1()).prediction());
- ASSERT(at(node.child2()).shouldSpeculateInteger());
-
SpeculateCellOperand base(this, node.child1());
GPRReg baseReg = base.gpr();
GPRTemporary storage(this);
GPRReg storageReg = storage.gpr();
- if (at(node.child1()).shouldSpeculateArguments()) {
- ASSERT_NOT_REACHED();
- } else if (at(node.child1()).prediction() == SpecString) {
- if (!isStringSpeculation(m_state.forNode(node.child1()).m_type))
- speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
-
+
+ const TypedArrayDescriptor* descriptor =
+ speculateArray(node.arrayMode(), node.child1(), baseReg);
+
+ switch (node.arrayMode()) {
+ case Array::String:
m_jit.loadPtr(MacroAssembler::Address(baseReg, JSString::offsetOfValue()), storageReg);
// Speculate that we're not accessing a rope
speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branchTest32(MacroAssembler::Zero, storageReg));
m_jit.loadPtr(MacroAssembler::Address(storageReg, StringImpl::dataOffset()), storageReg);
- } else if (at(node.child1()).shouldSpeculateInt8Array()) {
- const TypedArrayDescriptor& descriptor = m_jit.globalData()->int8ArrayDescriptor();
- if (!isInt8ArraySpeculation(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(descriptor.m_classInfo)));
- m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg);
- } else if (at(node.child1()).shouldSpeculateInt16Array()) {
- const TypedArrayDescriptor& descriptor = m_jit.globalData()->int16ArrayDescriptor();
- if (!isInt16ArraySpeculation(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(descriptor.m_classInfo)));
- m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg);
- } else if (at(node.child1()).shouldSpeculateInt32Array()) {
- const TypedArrayDescriptor& descriptor = m_jit.globalData()->int32ArrayDescriptor();
- if (!isInt32ArraySpeculation(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(descriptor.m_classInfo)));
- m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg);
- } else if (at(node.child1()).shouldSpeculateUint8Array()) {
- const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint8ArrayDescriptor();
- if (!isUint8ArraySpeculation(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(descriptor.m_classInfo)));
- m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg);
- } else if (at(node.child1()).shouldSpeculateUint8ClampedArray()) {
- const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint8ClampedArrayDescriptor();
- if (!isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type))
- speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo)));
- m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg);
- } else if (at(node.child1()).shouldSpeculateUint16Array()) {
- const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint16ArrayDescriptor();
- if (!isUint16ArraySpeculation(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(descriptor.m_classInfo)));
- m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg);
- } else if (at(node.child1()).shouldSpeculateUint32Array()) {
- const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint32ArrayDescriptor();
- if (!isUint32ArraySpeculation(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(descriptor.m_classInfo)));
- m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg);
- } else if (at(node.child1()).shouldSpeculateFloat32Array()) {
- const TypedArrayDescriptor& descriptor = m_jit.globalData()->float32ArrayDescriptor();
- if (!isFloat32ArraySpeculation(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(descriptor.m_classInfo)));
- m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg);
- } else if (at(node.child1()).shouldSpeculateFloat64Array()) {
- const TypedArrayDescriptor& descriptor = m_jit.globalData()->float64ArrayDescriptor();
- if (!isFloat64ArraySpeculation(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(descriptor.m_classInfo)));
- m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg);
- } else {
- speculateArray(node.child1(), baseReg);
+ break;
+
+ case Array::JSArray:
+ case Array::JSArrayOutOfBounds:
m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
+ break;
+
+ default:
+ ASSERT(descriptor);
+ m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor->m_storageOffset), storageReg);
+ break;
}
+
storageResult(storageReg, m_compileIndex);
}
@@ -3252,6 +3250,42 @@ void SpeculativeJIT::compileGetArgumentsLength(Node& node)
integerResult(resultReg, m_compileIndex);
}
+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);
+
+ 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);
+
+ speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, resultGPR, MacroAssembler::TrustedImm32(0)));
+
+ integerResult(resultGPR, m_compileIndex);
+ break;
+ case Array::String:
+ m_jit.load32(MacroAssembler::Address(baseGPR, JSString::offsetOfLength()), resultGPR);
+ integerResult(resultGPR, m_compileIndex);
+ break;
+ case Array::Arguments:
+ compileGetArgumentsLength(node);
+ break;
+ default:
+ ASSERT(descriptor);
+ m_jit.load32(MacroAssembler::Address(baseGPR, descriptor->m_lengthOffset), resultGPR);
+ integerResult(resultGPR, m_compileIndex);
+ break;
+ }
+}
+
void SpeculativeJIT::compileNewFunctionNoCheck(Node& node)
{
GPRResult result(this);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 073dbb42c..69a30a974 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -2082,6 +2082,8 @@ public:
void compileGetByValOnArguments(Node&);
void compileGetArgumentsLength(Node&);
+ void compileGetArrayLength(Node&);
+
void compileValueToInt32(Node&);
void compileUInt32ToNumber(Node&);
void compileDoubleAsInt32(Node&);
@@ -2095,12 +2097,6 @@ public:
#endif
void compileArithMod(Node&);
void compileSoftModulo(Node&);
- void compileGetTypedArrayLength(const TypedArrayDescriptor&, Node&, bool needsSpeculationCheck);
- enum TypedArraySpeculationRequirements {
- NoTypedArraySpecCheck,
- NoTypedArrayTypeSpecCheck,
- AllTypedArraySpecChecks
- };
enum TypedArraySignedness {
SignedTypedArray,
UnsignedTypedArray
@@ -2110,10 +2106,10 @@ public:
ClampRounding
};
void compileGetIndexedPropertyStorage(Node&);
- void compileGetByValOnIntTypedArray(const TypedArrayDescriptor&, Node&, size_t elementSize, TypedArraySpeculationRequirements, TypedArraySignedness);
- void compilePutByValForIntTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize, TypedArraySpeculationRequirements, TypedArraySignedness, TypedArrayRounding = TruncateRounding);
- void compileGetByValOnFloatTypedArray(const TypedArrayDescriptor&, Node&, size_t elementSize, TypedArraySpeculationRequirements);
- void compilePutByValForFloatTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize, TypedArraySpeculationRequirements);
+ void compileGetByValOnIntTypedArray(const TypedArrayDescriptor&, Node&, size_t elementSize, TypedArraySignedness);
+ void compilePutByValForIntTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize, TypedArraySignedness, TypedArrayRounding = TruncateRounding);
+ void compileGetByValOnFloatTypedArray(const TypedArrayDescriptor&, Node&, size_t elementSize);
+ void compilePutByValForFloatTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize);
void compileNewFunctionNoCheck(Node&);
void compileNewFunctionExpression(Node&);
bool compileRegExpExec(Node&);
@@ -2199,7 +2195,9 @@ public:
JumpReplacementWatchpoint* forwardSpeculationWatchpoint(ExitKind = UncountableWatchpoint);
JumpReplacementWatchpoint* speculationWatchpointWithConditionalDirection(ExitKind, bool isForward);
- void speculateArray(Edge baseEdge, GPRReg baseReg);
+ const TypedArrayDescriptor* typedArrayDescriptor(Array::Mode);
+
+ const TypedArrayDescriptor* speculateArray(Array::Mode, Edge baseEdge, GPRReg baseReg);
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 7a9ba1e41..26a48dcec 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -2341,12 +2341,13 @@ void SpeculativeJIT::compile(Node& node)
}
case GetByVal: {
- if (!node.prediction() || !at(node.child1()).prediction() || !at(node.child2()).prediction()) {
+ switch (node.arrayMode()) {
+ case Array::Undecided:
+ case Array::ForceExit:
+ ASSERT_NOT_REACHED();
terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode);
break;
- }
-
- if (!at(node.child2()).shouldSpeculateInteger() || (!node.child3() && !at(node.child1()).shouldSpeculateArguments())) {
+ case Array::Generic: {
SpeculateCellOperand base(this, node.child1()); // Save a register, speculate cell. We'll probably be right.
JSValueOperand property(this, node.child2());
GPRReg baseGPR = base.gpr();
@@ -2361,125 +2362,94 @@ void SpeculativeJIT::compile(Node& node)
jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
break;
}
+ case Array::JSArray:
+ case Array::JSArrayOutOfBounds: {
+ SpeculateStrictInt32Operand property(this, node.child2());
+ StorageOperand storage(this, node.child3());
+ GPRReg propertyReg = property.gpr();
+ GPRReg storageReg = storage.gpr();
- if (at(node.child1()).shouldSpeculateArguments()) {
- compileGetByValOnArguments(node);
if (!m_compileOkay)
return;
+
+ // 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.
+ {
+ 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())));
+ }
+
+ 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)));
+ 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;
}
-
- if (at(node.child1()).prediction() == SpecString) {
+ case Array::String:
compileGetByValOnString(node);
- if (!m_compileOkay)
- return;
break;
- }
-
- if (at(node.child1()).shouldSpeculateInt8Array()) {
- compileGetByValOnIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), node, sizeof(int8_t), isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(node.child1()).shouldSpeculateInt16Array()) {
- compileGetByValOnIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), node, sizeof(int16_t), isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(node.child1()).shouldSpeculateInt32Array()) {
- compileGetByValOnIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), node, sizeof(int32_t), isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(node.child1()).shouldSpeculateUint8Array()) {
- compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), node, sizeof(uint8_t), isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(node.child1()).shouldSpeculateUint8ClampedArray()) {
- compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray);
- if (!m_compileOkay)
- return;
+ case Array::Arguments:
+ compileGetByValOnArguments(node);
+ break;
+ case Array::Int8Array:
+ compileGetByValOnIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), node, sizeof(int8_t), SignedTypedArray);
+ break;
+ case Array::Int16Array:
+ compileGetByValOnIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), node, sizeof(int16_t), SignedTypedArray);
+ break;
+ case Array::Int32Array:
+ compileGetByValOnIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), node, sizeof(int32_t), SignedTypedArray);
+ break;
+ case Array::Uint8Array:
+ compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), node, sizeof(uint8_t), UnsignedTypedArray);
+ break;
+ case Array::Uint8ClampedArray:
+ compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), UnsignedTypedArray);
+ break;
+ case Array::Uint16Array:
+ compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), UnsignedTypedArray);
+ break;
+ case Array::Uint32Array:
+ compileGetByValOnIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), node, sizeof(uint32_t), UnsignedTypedArray);
+ break;
+ case Array::Float32Array:
+ compileGetByValOnFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), node, sizeof(float));
+ break;
+ case Array::Float64Array:
+ compileGetByValOnFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), node, sizeof(double));
+ break;
+ default:
+ ASSERT_NOT_REACHED();
break;
}
-
- if (at(node.child1()).shouldSpeculateUint16Array()) {
- compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(node.child1()).shouldSpeculateUint32Array()) {
- compileGetByValOnIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), node, sizeof(uint32_t), isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(node.child1()).shouldSpeculateFloat32Array()) {
- compileGetByValOnFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), node, sizeof(float), isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(node.child1()).shouldSpeculateFloat64Array()) {
- compileGetByValOnFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), node, sizeof(double), isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks);
- if (!m_compileOkay)
- return;
- break;
- }
-
- SpeculateStrictInt32Operand property(this, node.child2());
- StorageOperand storage(this, node.child3());
- GPRReg propertyReg = property.gpr();
- GPRReg storageReg = storage.gpr();
-
- if (!m_compileOkay)
- return;
-
- // 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.
- {
- 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())));
- }
-
- 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)));
- 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 PutByVal:
- case PutByValSafe: {
+ case PutByValAlias: {
Edge child1 = m_jit.graph().varArgChild(node, 0);
Edge child2 = m_jit.graph().varArgChild(node, 1);
Edge child3 = m_jit.graph().varArgChild(node, 2);
- if (!at(child1).prediction() || !at(child2).prediction()) {
+ Array::Mode arrayMode = modeForPut(node.arrayMode());
+ bool alreadyHandled = false;
+
+ switch (arrayMode) {
+ case Array::Undecided:
+ case Array::ForceExit:
+ ASSERT_NOT_REACHED();
terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode);
+ alreadyHandled = true;
break;
- }
-
- if (!at(child2).shouldSpeculateInteger()
- || at(child1).shouldSpeculateArguments()) {
+ case Array::Generic: {
+ ASSERT(node.op() == PutByVal);
+
SpeculateCellOperand base(this, child1); // Save a register, speculate cell. We'll probably be right.
JSValueOperand property(this, child2);
JSValueOperand value(this, child3);
@@ -2493,233 +2463,144 @@ void SpeculativeJIT::compile(Node& node)
callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValCellStrict : operationPutByValCellNonStrict, baseGPR, propertyTagGPR, propertyPayloadGPR, valueTagGPR, valuePayloadGPR);
noResult(m_compileIndex);
+ alreadyHandled = true;
break;
}
-
- SpeculateCellOperand base(this, child1);
- SpeculateStrictInt32Operand property(this, child2);
- if (at(child1).shouldSpeculateInt8Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), isInt8ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateInt16Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), isInt16ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateInt32Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), isInt32ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateUint8Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateUint8ClampedArray()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ClampedArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray, ClampRounding);
- if (!m_compileOkay)
- return;
+ default:
break;
}
-
- if (at(child1).shouldSpeculateUint16Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), isUint16ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
- if (at(child1).shouldSpeculateUint32Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), isUint32ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateFloat32Array()) {
- compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), isFloat32ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks);
- if (!m_compileOkay)
- return;
- break;
- }
+ if (alreadyHandled)
+ break;
- if (at(child1).shouldSpeculateFloat64Array()) {
- compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), isFloat64ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks);
- if (!m_compileOkay)
- return;
- break;
- }
+ SpeculateCellOperand base(this, child1);
+ SpeculateStrictInt32Operand property(this, child2);
- JSValueOperand value(this, child3);
- // Map base, property & value into registers, allocate a scratch register.
GPRReg baseReg = base.gpr();
GPRReg propertyReg = property.gpr();
- GPRReg valueTagReg = value.tagGPR();
- GPRReg valuePayloadReg = value.payloadGPR();
-
- if (!m_compileOkay)
- return;
- {
- GPRTemporary scratch(this);
- GPRReg scratchReg = scratch.gpr();
- writeBarrier(baseReg, valueTagReg, child3, WriteBarrierForPropertyAccess, scratchReg);
- }
+ speculateArray(arrayMode, child1, baseReg);
- speculateArray(child1, baseReg);
-
- MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()));
- if (node.op() == PutByVal)
- speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds);
-
- base.use();
- property.use();
- value.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)));
-
- // If we're writing to a hole we might be growing the array;
- MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
- m_jit.add32(TrustedImm32(1), propertyReg);
- m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
- m_jit.sub32(TrustedImm32(1), propertyReg);
-
- lengthDoesNotNeedUpdate.link(&m_jit);
- notHoleValue.link(&m_jit);
+ switch (arrayMode) {
+ case Array::JSArray:
+ case Array::JSArrayOutOfBounds: {
+ JSValueOperand value(this, child3);
- // Store the value to the array.
- m_jit.store32(valueTagReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
- m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
-
- if (node.op() == PutByValSafe) {
- addSlowPathGenerator(
- slowPathCall(
- beyondArrayBounds, this,
- m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
- NoResult, baseReg, propertyReg, valueTagReg, valuePayloadReg));
- }
+ GPRReg valueTagReg = value.tagGPR();
+ GPRReg valuePayloadReg = value.payloadGPR();
- noResult(m_compileIndex, UseChildrenCalledExplicitly);
- break;
- }
-
- case PutByValAlias: {
- Edge child1 = m_jit.graph().varArgChild(node, 0);
- Edge child2 = m_jit.graph().varArgChild(node, 1);
- Edge child3 = m_jit.graph().varArgChild(node, 2);
-
- if (!at(child1).prediction() || !at(child2).prediction()) {
- terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode);
- break;
- }
-
- ASSERT(isActionableMutableArraySpeculation(at(child1).prediction()));
- ASSERT(at(child2).shouldSpeculateInteger());
-
- SpeculateCellOperand base(this, child1);
- SpeculateStrictInt32Operand property(this, child2);
-
- if (at(child1).shouldSpeculateInt8Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), NoTypedArraySpecCheck, SignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateInt16Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), NoTypedArraySpecCheck, SignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateInt32Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), NoTypedArraySpecCheck, SignedTypedArray);
if (!m_compileOkay)
return;
- break;
- }
-
- if (at(child1).shouldSpeculateUint8Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), NoTypedArraySpecCheck, UnsignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
+
+ {
+ GPRTemporary scratch(this);
+ GPRReg scratchReg = scratch.gpr();
+ writeBarrier(baseReg, valueTagReg, child3, WriteBarrierForPropertyAccess, scratchReg);
+ }
- if (at(child1).shouldSpeculateUint8ClampedArray()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), NoTypedArraySpecCheck, UnsignedTypedArray, ClampRounding);
- if (!m_compileOkay)
- return;
- break;
- }
+ 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)));
+ m_jit.store32(value.payloadGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+
+ noResult(m_compileIndex);
+ break;
+ }
- if (at(child1).shouldSpeculateUint16Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), NoTypedArraySpecCheck, UnsignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateUint32Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), NoTypedArraySpecCheck, UnsignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateFloat32Array()) {
- compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), NoTypedArraySpecCheck);
- if (!m_compileOkay)
- return;
- break;
+ MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()));
+ if (arrayMode == Array::JSArray)
+ speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds);
+
+ base.use();
+ property.use();
+ value.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)));
+
+ // If we're writing to a hole we might be growing the array;
+ MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
+ m_jit.add32(TrustedImm32(1), propertyReg);
+ m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
+ m_jit.sub32(TrustedImm32(1), propertyReg);
+
+ lengthDoesNotNeedUpdate.link(&m_jit);
+ notHoleValue.link(&m_jit);
+
+ // Store the value to the array.
+ m_jit.store32(valueTagReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+ m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+
+ if (arrayMode == Array::JSArrayOutOfBounds) {
+ addSlowPathGenerator(
+ slowPathCall(
+ beyondArrayBounds, this,
+ m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
+ NoResult, baseReg, propertyReg, valueTagReg, valuePayloadReg));
+ }
+
+ noResult(m_compileIndex, UseChildrenCalledExplicitly);
+ break;
}
-
- if (at(child1).shouldSpeculateFloat64Array()) {
- compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), NoTypedArraySpecCheck);
- if (!m_compileOkay)
- return;
- break;
+
+ case Array::Arguments:
+ // FIXME: we could at some point make this work. Right now we're assuming that the register
+ // pressure would be too great.
+ ASSERT_NOT_REACHED();
+ break;
+
+ case Array::Int8Array:
+ compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), SignedTypedArray);
+ break;
+
+ case Array::Int16Array:
+ compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), SignedTypedArray);
+ break;
+
+ case Array::Int32Array:
+ compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), SignedTypedArray);
+ break;
+
+ case Array::Uint8Array:
+ compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), UnsignedTypedArray);
+ break;
+
+ case Array::Uint8ClampedArray:
+ compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), UnsignedTypedArray, ClampRounding);
+ break;
+
+ case Array::Uint16Array:
+ compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), UnsignedTypedArray);
+ break;
+
+ case Array::Uint32Array:
+ compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), UnsignedTypedArray);
+ break;
+
+ case Array::Float32Array:
+ compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float));
+ break;
+
+ case Array::Float64Array:
+ compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double));
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
}
-
- ASSERT(at(child1).shouldSpeculateArray());
-
- JSValueOperand value(this, child3);
- GPRTemporary scratch(this, base);
-
- GPRReg baseReg = base.gpr();
- GPRReg scratchReg = scratch.gpr();
-
- writeBarrier(baseReg, value.tagGPR(), child3, WriteBarrierForPropertyAccess, scratchReg);
-
- // Get the array storage.
- GPRReg storageReg = scratchReg;
- 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)));
- m_jit.store32(value.payloadGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
-
- noResult(m_compileIndex);
break;
}
@@ -2787,7 +2668,7 @@ void SpeculativeJIT::compile(Node& node)
writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR);
}
- speculateArray(node.child1(), baseGPR);
+ speculateArray(Array::JSArray, node.child1(), baseGPR);
GPRTemporary storage(this);
GPRReg storageGPR = storage.gpr();
@@ -2827,7 +2708,7 @@ void SpeculativeJIT::compile(Node& node)
GPRReg storageGPR = storage.gpr();
GPRReg storageLengthGPR = storageLength.gpr();
- speculateArray(node.child1(), baseGPR);
+ 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);
@@ -3373,82 +3254,10 @@ void SpeculativeJIT::compile(Node& node)
break;
}
- case GetArrayLength: {
- SpeculateCellOperand base(this, node.child1());
- GPRReg baseGPR = base.gpr();
-
- speculateArray(node.child1(), baseGPR);
-
- GPRTemporary result(this);
- GPRReg resultGPR = result.gpr();
-
- m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), resultGPR);
- m_jit.load32(MacroAssembler::Address(resultGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), resultGPR);
-
- speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, resultGPR, MacroAssembler::TrustedImm32(0)));
-
- integerResult(resultGPR, m_compileIndex);
+ case GetArrayLength:
+ compileGetArrayLength(node);
break;
- }
-
- case GetArgumentsLength: {
- compileGetArgumentsLength(node);
- break;
- }
-
- case GetStringLength: {
- SpeculateCellOperand base(this, node.child1());
- GPRTemporary result(this);
-
- GPRReg baseGPR = base.gpr();
- GPRReg resultGPR = result.gpr();
-
- if (!isStringSpeculation(m_state.forNode(node.child1()).m_type))
- speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- m_jit.load32(MacroAssembler::Address(baseGPR, JSString::offsetOfLength()), resultGPR);
-
- integerResult(resultGPR, m_compileIndex);
- break;
- }
-
- case GetInt8ArrayLength: {
- compileGetTypedArrayLength(m_jit.globalData()->int8ArrayDescriptor(), node, !isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type));
- break;
- }
- case GetInt16ArrayLength: {
- compileGetTypedArrayLength(m_jit.globalData()->int16ArrayDescriptor(), node, !isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type));
- break;
- }
- case GetInt32ArrayLength: {
- compileGetTypedArrayLength(m_jit.globalData()->int32ArrayDescriptor(), node, !isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type));
- break;
- }
- case GetUint8ArrayLength: {
- compileGetTypedArrayLength(m_jit.globalData()->uint8ArrayDescriptor(), node, !isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type));
- break;
- }
- case GetUint8ClampedArrayLength: {
- compileGetTypedArrayLength(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, !isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type));
- break;
- }
- case GetUint16ArrayLength: {
- compileGetTypedArrayLength(m_jit.globalData()->uint16ArrayDescriptor(), node, !isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type));
- break;
- }
- case GetUint32ArrayLength: {
- compileGetTypedArrayLength(m_jit.globalData()->uint32ArrayDescriptor(), node, !isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type));
- break;
- }
- case GetFloat32ArrayLength: {
- compileGetTypedArrayLength(m_jit.globalData()->float32ArrayDescriptor(), node, !isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type));
- break;
- }
- case GetFloat64ArrayLength: {
- compileGetTypedArrayLength(m_jit.globalData()->float64ArrayDescriptor(), node, !isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type));
- break;
- }
-
case CheckFunction: {
SpeculateCellOperand function(this, node.child1());
speculationCheck(BadCache, JSValueRegs(), NoNode, m_jit.branchWeakPtr(JITCompiler::NotEqual, function.gpr(), node.function()));
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index c2151088c..c2e207264 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -2374,12 +2374,13 @@ void SpeculativeJIT::compile(Node& node)
}
case GetByVal: {
- if (!node.prediction() || !at(node.child1()).prediction() || !at(node.child2()).prediction()) {
+ switch (node.arrayMode()) {
+ case Array::Undecided:
+ case Array::ForceExit:
+ ASSERT_NOT_REACHED();
terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode);
break;
- }
-
- if (!at(node.child2()).shouldSpeculateInteger() || (!node.child3() && !at(node.child1()).shouldSpeculateArguments())) {
+ case Array::Generic: {
JSValueOperand base(this, node.child1());
JSValueOperand property(this, node.child2());
GPRReg baseGPR = base.gpr();
@@ -2392,120 +2393,90 @@ void SpeculativeJIT::compile(Node& node)
jsValueResult(result.gpr(), m_compileIndex);
break;
}
-
- if (at(node.child1()).shouldSpeculateArguments()) {
- compileGetByValOnArguments(node);
+ case Array::JSArray:
+ case Array::JSArrayOutOfBounds: {
+ SpeculateCellOperand base(this, node.child1());
+ SpeculateStrictInt32Operand property(this, node.child2());
+ StorageOperand storage(this, node.child3());
+
+ GPRReg baseReg = base.gpr();
+ GPRReg propertyReg = property.gpr();
+ GPRReg storageReg = storage.gpr();
+
if (!m_compileOkay)
return;
+
+ // 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())));
+
+ 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()));
+
+ jsValueResult(result.gpr(), m_compileIndex);
break;
}
-
- if (at(node.child1()).prediction() == SpecString) {
+ case Array::String:
compileGetByValOnString(node);
- if (!m_compileOkay)
- return;
break;
- }
-
- if (at(node.child1()).shouldSpeculateInt8Array()) {
- compileGetByValOnIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), node, sizeof(int8_t), isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(node.child1()).shouldSpeculateInt16Array()) {
- compileGetByValOnIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), node, sizeof(int16_t), isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(node.child1()).shouldSpeculateInt32Array()) {
- compileGetByValOnIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), node, sizeof(int32_t), isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(node.child1()).shouldSpeculateUint8Array()) {
- compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), node, sizeof(uint8_t), isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(node.child1()).shouldSpeculateUint8ClampedArray()) {
- compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray);
- if (!m_compileOkay)
- return;
+ case Array::Arguments:
+ compileGetByValOnArguments(node);
+ break;
+ case Array::Int8Array:
+ compileGetByValOnIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), node, sizeof(int8_t), SignedTypedArray);
+ break;
+ case Array::Int16Array:
+ compileGetByValOnIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), node, sizeof(int16_t), SignedTypedArray);
+ break;
+ case Array::Int32Array:
+ compileGetByValOnIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), node, sizeof(int32_t), SignedTypedArray);
+ break;
+ case Array::Uint8Array:
+ compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), node, sizeof(uint8_t), UnsignedTypedArray);
+ break;
+ case Array::Uint8ClampedArray:
+ compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), UnsignedTypedArray);
+ break;
+ case Array::Uint16Array:
+ compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), UnsignedTypedArray);
+ break;
+ case Array::Uint32Array:
+ compileGetByValOnIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), node, sizeof(uint32_t), UnsignedTypedArray);
+ break;
+ case Array::Float32Array:
+ compileGetByValOnFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), node, sizeof(float));
+ break;
+ case Array::Float64Array:
+ compileGetByValOnFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), node, sizeof(double));
+ break;
+ default:
+ ASSERT_NOT_REACHED();
break;
}
-
- if (at(node.child1()).shouldSpeculateUint16Array()) {
- compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(node.child1()).shouldSpeculateUint32Array()) {
- compileGetByValOnIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), node, sizeof(uint32_t), isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(node.child1()).shouldSpeculateFloat32Array()) {
- compileGetByValOnFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), node, sizeof(float), isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(node.child1()).shouldSpeculateFloat64Array()) {
- compileGetByValOnFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), node, sizeof(double), isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks);
- if (!m_compileOkay)
- return;
- break;
- }
-
- SpeculateCellOperand base(this, node.child1());
- SpeculateStrictInt32Operand property(this, node.child2());
- StorageOperand storage(this, node.child3());
-
- GPRReg baseReg = base.gpr();
- GPRReg propertyReg = property.gpr();
- GPRReg storageReg = storage.gpr();
-
- if (!m_compileOkay)
- return;
-
- // 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())));
-
- 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()));
-
- jsValueResult(result.gpr(), m_compileIndex);
break;
}
case PutByVal:
- case PutByValSafe: {
+ case PutByValAlias: {
Edge child1 = m_jit.graph().varArgChild(node, 0);
Edge child2 = m_jit.graph().varArgChild(node, 1);
Edge child3 = m_jit.graph().varArgChild(node, 2);
- if (!at(child1).prediction() || !at(child2).prediction()) {
+ Array::Mode arrayMode = modeForPut(node.arrayMode());
+ bool alreadyHandled = false;
+
+ switch (arrayMode) {
+ case Array::Undecided:
+ case Array::ForceExit:
+ ASSERT_NOT_REACHED();
terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode);
+ alreadyHandled = true;
break;
- }
-
- if (!at(child2).shouldSpeculateInteger()) {
+ case Array::Generic: {
+ ASSERT(node.op() == PutByVal);
+
JSValueOperand arg1(this, child1);
JSValueOperand arg2(this, child2);
JSValueOperand arg3(this, child3);
@@ -2517,19 +2488,97 @@ void SpeculativeJIT::compile(Node& node)
callOperation(m_jit.strictModeFor(node.codeOrigin) ? operationPutByValStrict : operationPutByValNonStrict, arg1GPR, arg2GPR, arg3GPR);
noResult(m_compileIndex);
+ alreadyHandled = true;
break;
}
-
+ default:
+ break;
+ }
+
+ if (alreadyHandled)
+ break;
+
SpeculateCellOperand base(this, child1);
SpeculateStrictInt32Operand property(this, child2);
- if (at(child1).shouldSpeculateArguments()) {
- dataLog(" in here ");
+
+ 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 (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();
+ m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
+
+ noResult(m_compileIndex);
+ break;
+ }
+
+ MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()));
+ if (arrayMode == Array::JSArray)
+ speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds);
+
+ base.use();
+ property.use();
+ value.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)));
+
+ // If we're writing to a hole we might be growing the array;
+ MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
+ m_jit.add32(TrustedImm32(1), propertyReg);
+ m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
+ m_jit.sub32(TrustedImm32(1), propertyReg);
+
+ lengthDoesNotNeedUpdate.link(&m_jit);
+ notHoleValue.link(&m_jit);
+
+ // Store the value to the array.
+ m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
+
+ if (arrayMode == Array::JSArrayOutOfBounds) {
+ addSlowPathGenerator(
+ slowPathCall(
+ beyondArrayBounds, this,
+ m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
+ NoResult, baseReg, propertyReg, valueReg));
+ }
+
+ noResult(m_compileIndex, UseChildrenCalledExplicitly);
+ break;
+ }
+
+ case Array::Arguments: {
JSValueOperand value(this, child3);
GPRTemporary scratch(this);
GPRTemporary scratch2(this);
- GPRReg baseReg = base.gpr();
- GPRReg propertyReg = property.gpr();
GPRReg valueReg = value.gpr();
GPRReg scratchReg = scratch.gpr();
GPRReg scratch2Reg = scratch2.gpr();
@@ -2537,15 +2586,6 @@ void SpeculativeJIT::compile(Node& node)
if (!m_compileOkay)
return;
- if (!isArgumentsSpeculation(m_state.forNode(child1).m_type)) {
- speculationCheck(
- BadType, JSValueSource::unboxedCell(baseReg), child1,
- m_jit.branchPtr(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(baseReg, JSCell::classInfoOffset()),
- MacroAssembler::TrustedImmPtr(&Arguments::s_info)));
- }
-
m_jit.loadPtr(
MacroAssembler::Address(baseReg, Arguments::offsetOfData()),
scratchReg);
@@ -2579,225 +2619,51 @@ void SpeculativeJIT::compile(Node& node)
noResult(m_compileIndex);
break;
}
-
- if (at(child1).shouldSpeculateInt8Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), isInt8ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateInt16Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), isInt16ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateInt32Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), isInt32ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateUint8Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateUint8ClampedArray()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ClampedArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray, ClampRounding);
+
+ case Array::Int8Array:
+ compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), SignedTypedArray);
break;
- }
-
- if (at(child1).shouldSpeculateUint16Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), isUint16ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateUint32Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), isUint32ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateFloat32Array()) {
- compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), isFloat32ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateFloat64Array()) {
- compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), isFloat64ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks);
- if (!m_compileOkay)
- return;
- break;
- }
- JSValueOperand value(this, child3);
- GPRTemporary scratch(this);
-
- // Map base, property & value into registers, allocate a scratch register.
- GPRReg baseReg = base.gpr();
- GPRReg propertyReg = property.gpr();
- GPRReg valueReg = value.gpr();
- GPRReg scratchReg = scratch.gpr();
-
- if (!m_compileOkay)
- return;
-
- writeBarrier(baseReg, value.gpr(), child3, WriteBarrierForPropertyAccess, scratchReg);
-
- speculateArray(child1, baseReg);
-
- MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()));
- if (node.op() == PutByVal)
- speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds);
-
- base.use();
- property.use();
- value.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)));
-
- // If we're writing to a hole we might be growing the array;
- MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
- m_jit.add32(TrustedImm32(1), propertyReg);
- m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
- m_jit.sub32(TrustedImm32(1), propertyReg);
-
- lengthDoesNotNeedUpdate.link(&m_jit);
- notHoleValue.link(&m_jit);
-
- // Store the value to the array.
- m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
-
- if (node.op() == PutByValSafe) {
- addSlowPathGenerator(
- slowPathCall(
- beyondArrayBounds, this,
- m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
- NoResult, baseReg, propertyReg, valueReg));
- }
-
- noResult(m_compileIndex, UseChildrenCalledExplicitly);
- break;
- }
-
- case PutByValAlias: {
- Edge child1 = m_jit.graph().varArgChild(node, 0);
- Edge child2 = m_jit.graph().varArgChild(node, 1);
- Edge child3 = m_jit.graph().varArgChild(node, 2);
-
- if (!at(child1).prediction() || !at(child2).prediction()) {
- terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode);
+ case Array::Int16Array:
+ compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), SignedTypedArray);
break;
- }
-
- ASSERT(isActionableMutableArraySpeculation(at(child1).prediction()));
- ASSERT(at(child2).shouldSpeculateInteger());
-
- SpeculateCellOperand base(this, child1);
- SpeculateStrictInt32Operand property(this, child2);
- if (at(child1).shouldSpeculateInt8Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), NoTypedArraySpecCheck, SignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateInt16Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), NoTypedArraySpecCheck, SignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateInt32Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), NoTypedArraySpecCheck, SignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateUint8Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), NoTypedArraySpecCheck, UnsignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateUint8ClampedArray()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), NoTypedArraySpecCheck, UnsignedTypedArray, ClampRounding);
- if (!m_compileOkay)
- return;
+
+ case Array::Int32Array:
+ compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), SignedTypedArray);
+ break;
+
+ case Array::Uint8Array:
+ compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), UnsignedTypedArray);
+ break;
+
+ case Array::Uint8ClampedArray:
+ compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), UnsignedTypedArray, ClampRounding);
+ break;
+
+ case Array::Uint16Array:
+ compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), UnsignedTypedArray);
+ break;
+
+ case Array::Uint32Array:
+ compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), UnsignedTypedArray);
+ break;
+
+ case Array::Float32Array:
+ compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float));
+ break;
+
+ case Array::Float64Array:
+ compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double));
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
break;
}
- if (at(child1).shouldSpeculateUint16Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), NoTypedArraySpecCheck, UnsignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateUint32Array()) {
- compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), NoTypedArraySpecCheck, UnsignedTypedArray);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateFloat32Array()) {
- compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), NoTypedArraySpecCheck);
- if (!m_compileOkay)
- return;
- break;
- }
-
- if (at(child1).shouldSpeculateFloat64Array()) {
- compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), NoTypedArraySpecCheck);
- if (!m_compileOkay)
- return;
- break;
- }
-
- ASSERT(at(child1).shouldSpeculateArray());
-
- JSValueOperand value(this, child3);
- GPRTemporary scratch(this);
-
- GPRReg baseReg = base.gpr();
- GPRReg scratchReg = scratch.gpr();
-
- writeBarrier(base.gpr(), value.gpr(), child3, WriteBarrierForPropertyAccess, scratchReg);
-
- // Get the array storage.
- 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();
- m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
-
- noResult(m_compileIndex);
break;
}
-
+
case RegExpExec: {
if (compileRegExpExec(node))
return;
@@ -2859,7 +2725,7 @@ void SpeculativeJIT::compile(Node& node)
writeBarrier(baseGPR, valueGPR, node.child2(), WriteBarrierForPropertyAccess, storageGPR, storageLengthGPR);
- speculateArray(node.child1(), baseGPR);
+ 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);
@@ -2896,7 +2762,7 @@ void SpeculativeJIT::compile(Node& node)
GPRReg storageGPR = storage.gpr();
GPRReg storageLengthGPR = storageLength.gpr();
- speculateArray(node.child1(), baseGPR);
+ 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);
@@ -3386,81 +3252,10 @@ void SpeculativeJIT::compile(Node& node)
break;
}
- case GetArrayLength: {
- SpeculateCellOperand base(this, node.child1());
- GPRTemporary result(this);
-
- GPRReg baseGPR = base.gpr();
- GPRReg resultGPR = result.gpr();
-
- speculateArray(node.child1(), baseGPR);
-
- m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), resultGPR);
- m_jit.load32(MacroAssembler::Address(resultGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), resultGPR);
-
- speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, resultGPR, MacroAssembler::TrustedImm32(0)));
-
- integerResult(resultGPR, m_compileIndex);
+ case GetArrayLength:
+ compileGetArrayLength(node);
break;
- }
- case GetArgumentsLength: {
- compileGetArgumentsLength(node);
- break;
- }
-
- case GetStringLength: {
- SpeculateCellOperand base(this, node.child1());
- GPRTemporary result(this);
-
- GPRReg baseGPR = base.gpr();
- GPRReg resultGPR = result.gpr();
-
- if (!isStringSpeculation(m_state.forNode(node.child1()).m_type))
- speculationCheck(BadType, JSValueRegs(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
-
- m_jit.load32(MacroAssembler::Address(baseGPR, JSString::offsetOfLength()), resultGPR);
-
- integerResult(resultGPR, m_compileIndex);
- break;
- }
-
- case GetInt8ArrayLength: {
- compileGetTypedArrayLength(m_jit.globalData()->int8ArrayDescriptor(), node, !isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type));
- break;
- }
- case GetInt16ArrayLength: {
- compileGetTypedArrayLength(m_jit.globalData()->int16ArrayDescriptor(), node, !isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type));
- break;
- }
- case GetInt32ArrayLength: {
- compileGetTypedArrayLength(m_jit.globalData()->int32ArrayDescriptor(), node, !isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type));
- break;
- }
- case GetUint8ArrayLength: {
- compileGetTypedArrayLength(m_jit.globalData()->uint8ArrayDescriptor(), node, !isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type));
- break;
- }
- case GetUint8ClampedArrayLength: {
- compileGetTypedArrayLength(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, !isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type));
- break;
- }
- case GetUint16ArrayLength: {
- compileGetTypedArrayLength(m_jit.globalData()->uint16ArrayDescriptor(), node, !isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type));
- break;
- }
- case GetUint32ArrayLength: {
- compileGetTypedArrayLength(m_jit.globalData()->uint32ArrayDescriptor(), node, !isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type));
- break;
- }
- case GetFloat32ArrayLength: {
- compileGetTypedArrayLength(m_jit.globalData()->float32ArrayDescriptor(), node, !isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type));
- break;
- }
- case GetFloat64ArrayLength: {
- compileGetTypedArrayLength(m_jit.globalData()->float64ArrayDescriptor(), node, !isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type));
- break;
- }
case CheckFunction: {
SpeculateCellOperand function(this, node.child1());
speculationCheck(BadCache, JSValueRegs(), NoNode, m_jit.branchWeakPtr(JITCompiler::NotEqual, function.gpr(), node.function()));
diff --git a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
index 68627f95c..eb04a6747 100644
--- a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
@@ -98,7 +98,6 @@ public:
case GetByVal:
case PutByVal:
case PutByValAlias:
- case PutByValSafe:
case GetArrayLength:
case Phantom:
// Don't count these uses.
@@ -215,53 +214,12 @@ public:
}
case GetByVal:
- if (!node.prediction() || !m_graph[node.child1()].prediction() || !m_graph[node.child2()].prediction())
- break;
- if (!isActionableArraySpeculation(m_graph[node.child1()].prediction()) || !m_graph[node.child2()].shouldSpeculateInteger())
- clobber(live);
- break;
-
case PutByVal:
case PutByValAlias:
- case PutByValSafe: {
- Edge child1 = m_graph.varArgChild(node, 0);
- Edge child2 = m_graph.varArgChild(node, 1);
-
- if (!m_graph[child1].prediction() || !m_graph[child2].prediction())
- break;
- if (!m_graph[child2].shouldSpeculateInteger()
-#if USE(JSVALUE32_64)
- || m_graph[child1].shouldSpeculateArguments()
-#endif
- ) {
- clobber(live);
- break;
- }
- if (node.op() != PutByValSafe)
- break;
- if (m_graph[child1].shouldSpeculateArguments())
- break;
- if (m_graph[child1].shouldSpeculateInt8Array())
- break;
- if (m_graph[child1].shouldSpeculateInt16Array())
- break;
- if (m_graph[child1].shouldSpeculateInt32Array())
- break;
- if (m_graph[child1].shouldSpeculateUint8Array())
- break;
- if (m_graph[child1].shouldSpeculateUint8ClampedArray())
- break;
- if (m_graph[child1].shouldSpeculateUint16Array())
- break;
- if (m_graph[child1].shouldSpeculateUint32Array())
- break;
- if (m_graph[child1].shouldSpeculateFloat32Array())
- break;
- if (m_graph[child1].shouldSpeculateFloat64Array())
+ if (m_graph.byValIsPure(node))
break;
clobber(live);
break;
- }
case GetMyArgumentsLengthSafe:
case GetMyArgumentByValSafe: