summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@digia.com>2013-09-13 12:51:20 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-19 20:50:05 +0200
commitd441d6f39bb846989d95bcf5caf387b42414718d (patch)
treee367e64a75991c554930278175d403c072de6bb8 /Source/JavaScriptCore/dfg/DFGAbstractState.cpp
parent0060b2994c07842f4c59de64b5e3e430525c4b90 (diff)
downloadqtwebkit-d441d6f39bb846989d95bcf5caf387b42414718d.tar.gz
Import Qt5x2 branch of QtWebkit for Qt 5.2
Importing a new snapshot of webkit. Change-Id: I2d01ad12cdc8af8cb015387641120a9d7ea5f10c Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGAbstractState.cpp')
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractState.cpp1475
1 files changed, 667 insertions, 808 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index 89b2a971b..2ac79c7c9 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,7 +31,9 @@
#include "CodeBlock.h"
#include "DFGBasicBlock.h"
#include "GetByIdStatus.h"
+#include "Operations.h"
#include "PutByIdStatus.h"
+#include "StringObject.h"
namespace JSC { namespace DFG {
@@ -41,7 +43,6 @@ AbstractState::AbstractState(Graph& graph)
, m_variables(m_codeBlock->numParameters(), graph.m_localVars)
, m_block(0)
{
- m_nodes.resize(graph.size());
}
AbstractState::~AbstractState() { }
@@ -54,12 +55,8 @@ void AbstractState::beginBasicBlock(BasicBlock* basicBlock)
ASSERT(basicBlock->variablesAtTail.numberOfLocals() == basicBlock->valuesAtTail.numberOfLocals());
ASSERT(basicBlock->variablesAtHead.numberOfLocals() == basicBlock->variablesAtTail.numberOfLocals());
- // This is usually a no-op, but it is possible that the graph has grown since the
- // abstract state was last used.
- m_nodes.resize(m_graph.size());
-
for (size_t i = 0; i < basicBlock->size(); i++)
- m_nodes[basicBlock->at(i)].clear();
+ forNode(basicBlock->at(i)).clear();
m_variables = basicBlock->valuesAtHead;
m_haveStructures = false;
@@ -91,21 +88,14 @@ void AbstractState::initialize(Graph& graph)
root->cfaHasVisited = false;
root->cfaFoundConstants = false;
for (size_t i = 0; i < root->valuesAtHead.numberOfArguments(); ++i) {
- Node& node = graph[root->variablesAtHead.argument(i)];
- ASSERT(node.op() == SetArgument);
- if (!node.shouldGenerate()) {
- // The argument is dead. We don't do any checks for such arguments, and so
- // for the purpose of the analysis, they contain no value.
- root->valuesAtHead.argument(i).clear();
- continue;
- }
-
- if (node.variableAccessData()->isCaptured()) {
+ Node* node = root->variablesAtHead.argument(i);
+ ASSERT(node->op() == SetArgument);
+ if (!node->variableAccessData()->shouldUnboxIfPossible()) {
root->valuesAtHead.argument(i).makeTop();
continue;
}
- SpeculatedType prediction = node.variableAccessData()->prediction();
+ SpeculatedType prediction = node->variableAccessData()->prediction();
if (isInt32Speculation(prediction))
root->valuesAtHead.argument(i).set(SpecInt32);
else if (isBooleanSpeculation(prediction))
@@ -118,8 +108,8 @@ void AbstractState::initialize(Graph& graph)
root->valuesAtTail.argument(i).clear();
}
for (size_t i = 0; i < root->valuesAtHead.numberOfLocals(); ++i) {
- NodeIndex nodeIndex = root->variablesAtHead.local(i);
- if (nodeIndex != NoNode && graph[nodeIndex].variableAccessData()->isCaptured())
+ Node* node = root->variablesAtHead.local(i);
+ if (node && node->variableAccessData()->isCaptured())
root->valuesAtHead.local(i).makeTop();
else
root->valuesAtHead.local(i).clear();
@@ -217,11 +207,11 @@ void AbstractState::reset()
m_branchDirection = InvalidBranchDirection;
}
-AbstractState::BooleanResult AbstractState::booleanResult(Node& node, AbstractValue& value)
+AbstractState::BooleanResult AbstractState::booleanResult(Node* node, AbstractValue& value)
{
JSValue childConst = value.value();
if (childConst) {
- if (childConst.toBoolean(m_codeBlock->globalObjectFor(node.codeOrigin)->globalExec()))
+ if (childConst.toBoolean(m_codeBlock->globalObjectFor(node->codeOrigin)->globalExec()))
return DefinitelyTrue;
return DefinitelyFalse;
}
@@ -230,7 +220,7 @@ AbstractState::BooleanResult AbstractState::booleanResult(Node& node, AbstractVa
if (isCellSpeculation(value.m_type)
&& value.m_currentKnownStructure.hasSingleton()) {
Structure* structure = value.m_currentKnownStructure.singleton();
- if (!structure->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node.codeOrigin))
+ if (!structure->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->codeOrigin))
&& structure->typeInfo().type() != StringType)
return DefinitelyTrue;
}
@@ -238,96 +228,109 @@ AbstractState::BooleanResult AbstractState::booleanResult(Node& node, AbstractVa
return UnknownBooleanResult;
}
-bool AbstractState::execute(unsigned indexInBlock)
+bool AbstractState::startExecuting(Node* node)
{
ASSERT(m_block);
ASSERT(m_isValid);
m_didClobber = false;
- NodeIndex nodeIndex = m_block->at(indexInBlock);
- Node& node = m_graph[nodeIndex];
-
- if (!node.shouldGenerate())
- return true;
-
- switch (node.op()) {
+ node->setCanExit(false);
+
+ if (!node->shouldGenerate())
+ return false;
+
+ return true;
+}
+
+bool AbstractState::startExecuting(unsigned indexInBlock)
+{
+ return startExecuting(m_block->at(indexInBlock));
+}
+
+void AbstractState::executeEdges(Node* node)
+{
+ DFG_NODE_DO_TO_CHILDREN(m_graph, node, filterEdgeByUse);
+}
+
+void AbstractState::executeEdges(unsigned indexInBlock)
+{
+ executeEdges(m_block->at(indexInBlock));
+}
+
+void AbstractState::verifyEdge(Node*, Edge edge)
+{
+ RELEASE_ASSERT(!(forNode(edge).m_type & ~typeFilterFor(edge.useKind())));
+}
+
+void AbstractState::verifyEdges(Node* node)
+{
+ DFG_NODE_DO_TO_CHILDREN(m_graph, node, verifyEdge);
+}
+
+bool AbstractState::executeEffects(unsigned indexInBlock, Node* node)
+{
+ if (!ASSERT_DISABLED)
+ verifyEdges(node);
+
+ switch (node->op()) {
case JSConstant:
case WeakJSConstant:
case PhantomArguments: {
- forNode(nodeIndex).set(m_graph.valueOfJSConstant(nodeIndex));
- node.setCanExit(false);
+ forNode(node).set(m_graph.valueOfJSConstant(node));
break;
}
case Identity: {
- forNode(nodeIndex) = forNode(node.child1());
- node.setCanExit(false);
+ forNode(node) = forNode(node->child1());
break;
}
case GetLocal: {
- VariableAccessData* variableAccessData = node.variableAccessData();
+ VariableAccessData* variableAccessData = node->variableAccessData();
if (variableAccessData->prediction() == SpecNone) {
m_isValid = false;
- node.setCanExit(true);
break;
}
- bool canExit = false;
AbstractValue value = m_variables.operand(variableAccessData->local());
if (!variableAccessData->isCaptured()) {
if (value.isClear())
- canExit |= true;
+ node->setCanExit(true);
}
if (value.value())
m_foundConstants = true;
- forNode(nodeIndex) = value;
- node.setCanExit(canExit);
+ forNode(node) = value;
break;
}
case GetLocalUnlinked: {
- AbstractValue value = m_variables.operand(node.unlinkedLocal());
+ AbstractValue value = m_variables.operand(node->unlinkedLocal());
if (value.value())
m_foundConstants = true;
- forNode(nodeIndex) = value;
- node.setCanExit(false);
+ forNode(node) = value;
break;
}
case SetLocal: {
- if (node.variableAccessData()->isCaptured()
- || m_graph.isCreatedThisArgument(node.local())) {
- m_variables.operand(node.local()) = forNode(node.child1());
- node.setCanExit(false);
- break;
- }
-
- if (node.variableAccessData()->shouldUseDoubleFormat()) {
- speculateNumberUnary(node);
- m_variables.operand(node.local()).set(SpecDouble);
- break;
- }
+ m_variables.operand(node->local()) = forNode(node->child1());
+ break;
+ }
- SpeculatedType predictedType = node.variableAccessData()->argumentAwarePrediction();
- if (isInt32Speculation(predictedType))
- speculateInt32Unary(node);
- else if (isCellSpeculation(predictedType)) {
- node.setCanExit(!isCellSpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecCell);
- } else if (isBooleanSpeculation(predictedType))
- speculateBooleanUnary(node);
- else
- node.setCanExit(false);
+ case MovHintAndCheck: {
+ // Don't need to do anything. A MovHint is effectively a promise that the SetLocal
+ // was dead.
+ break;
+ }
- m_variables.operand(node.local()) = forNode(node.child1());
+ case MovHint:
+ case ZombieHint: {
+ RELEASE_ASSERT_NOT_REACHED();
break;
}
case SetArgument:
// Assert that the state of arguments has been set.
- ASSERT(!m_block->valuesAtHead.operand(node.local()).isClear());
- node.setCanExit(false);
+ ASSERT(!m_block->valuesAtHead.operand(node->local()).isClear());
break;
case BitAnd:
@@ -336,230 +339,225 @@ bool AbstractState::execute(unsigned indexInBlock)
case BitRShift:
case BitLShift:
case BitURShift: {
- JSValue left = forNode(node.child1()).value();
- JSValue right = forNode(node.child2()).value();
+ JSValue left = forNode(node->child1()).value();
+ JSValue right = forNode(node->child2()).value();
if (left && right && left.isInt32() && right.isInt32()) {
int32_t a = left.asInt32();
int32_t b = right.asInt32();
bool constantWasSet;
- switch (node.op()) {
+ switch (node->op()) {
case BitAnd:
- constantWasSet = trySetConstant(nodeIndex, JSValue(a & b));
+ constantWasSet = trySetConstant(node, JSValue(a & b));
break;
case BitOr:
- constantWasSet = trySetConstant(nodeIndex, JSValue(a | b));
+ constantWasSet = trySetConstant(node, JSValue(a | b));
break;
case BitXor:
- constantWasSet = trySetConstant(nodeIndex, JSValue(a ^ b));
+ constantWasSet = trySetConstant(node, JSValue(a ^ b));
break;
case BitRShift:
- constantWasSet = trySetConstant(nodeIndex, JSValue(a >> static_cast<uint32_t>(b)));
+ constantWasSet = trySetConstant(node, JSValue(a >> static_cast<uint32_t>(b)));
break;
case BitLShift:
- constantWasSet = trySetConstant(nodeIndex, JSValue(a << static_cast<uint32_t>(b)));
+ constantWasSet = trySetConstant(node, JSValue(a << static_cast<uint32_t>(b)));
break;
case BitURShift:
- constantWasSet = trySetConstant(nodeIndex, JSValue(static_cast<uint32_t>(a) >> static_cast<uint32_t>(b)));
+ constantWasSet = trySetConstant(node, JSValue(static_cast<uint32_t>(a) >> static_cast<uint32_t>(b)));
break;
default:
- ASSERT_NOT_REACHED();
+ RELEASE_ASSERT_NOT_REACHED();
constantWasSet = false;
}
if (constantWasSet) {
m_foundConstants = true;
- node.setCanExit(false);
break;
}
}
- speculateInt32Binary(node);
- forNode(nodeIndex).set(SpecInt32);
+ forNode(node).set(SpecInt32);
break;
}
case UInt32ToNumber: {
- JSValue child = forNode(node.child1()).value();
+ JSValue child = forNode(node->child1()).value();
if (child && child.isNumber()) {
ASSERT(child.isInt32());
- if (trySetConstant(nodeIndex, JSValue(child.asUInt32()))) {
+ if (trySetConstant(node, JSValue(child.asUInt32()))) {
m_foundConstants = true;
- node.setCanExit(false);
break;
}
}
- if (!node.canSpeculateInteger()) {
- forNode(nodeIndex).set(SpecDouble);
- node.setCanExit(false);
- } else {
- forNode(nodeIndex).set(SpecInt32);
- node.setCanExit(true);
+ if (!node->canSpeculateInteger())
+ forNode(node).set(SpecDouble);
+ else {
+ forNode(node).set(SpecInt32);
+ node->setCanExit(true);
}
break;
}
-
case DoubleAsInt32: {
- JSValue child = forNode(node.child1()).value();
+ JSValue child = forNode(node->child1()).value();
if (child && child.isNumber()) {
double asDouble = child.asNumber();
int32_t asInt = JSC::toInt32(asDouble);
if (bitwise_cast<int64_t>(static_cast<double>(asInt)) == bitwise_cast<int64_t>(asDouble)
- && trySetConstant(nodeIndex, JSValue(asInt))) {
+ && trySetConstant(node, JSValue(asInt))) {
m_foundConstants = true;
break;
}
}
- node.setCanExit(true);
- forNode(node.child1()).filter(SpecNumber);
- forNode(nodeIndex).set(SpecInt32);
+ node->setCanExit(true);
+ forNode(node).set(SpecInt32);
break;
}
case ValueToInt32: {
- JSValue child = forNode(node.child1()).value();
+ JSValue child = forNode(node->child1()).value();
if (child && child.isNumber()) {
bool constantWasSet;
if (child.isInt32())
- constantWasSet = trySetConstant(nodeIndex, child);
+ constantWasSet = trySetConstant(node, child);
else
- constantWasSet = trySetConstant(nodeIndex, JSValue(JSC::toInt32(child.asDouble())));
+ constantWasSet = trySetConstant(node, JSValue(JSC::toInt32(child.asDouble())));
if (constantWasSet) {
m_foundConstants = true;
- node.setCanExit(false);
break;
}
}
- if (m_graph[node.child1()].shouldSpeculateInteger())
- speculateInt32Unary(node);
- else if (m_graph[node.child1()].shouldSpeculateNumber())
- speculateNumberUnary(node);
- else if (m_graph[node.child1()].shouldSpeculateBoolean())
- speculateBooleanUnary(node);
- else
- node.setCanExit(false);
- forNode(nodeIndex).set(SpecInt32);
+ forNode(node).set(SpecInt32);
break;
}
-
- case Int32ToDouble: {
- JSValue child = forNode(node.child1()).value();
+
+ case Int32ToDouble:
+ case ForwardInt32ToDouble: {
+ JSValue child = forNode(node->child1()).value();
if (child && child.isNumber()
- && trySetConstant(nodeIndex, JSValue(JSValue::EncodeAsDouble, child.asNumber()))) {
+ && trySetConstant(node, JSValue(JSValue::EncodeAsDouble, child.asNumber()))) {
m_foundConstants = true;
- node.setCanExit(false);
break;
}
- speculateNumberUnary(node);
- if (isInt32Speculation(forNode(node.child1()).m_type))
- forNode(nodeIndex).set(SpecDoubleReal);
+ if (isInt32Speculation(forNode(node->child1()).m_type))
+ forNode(node).set(SpecDoubleReal);
else
- forNode(nodeIndex).set(SpecDouble);
+ forNode(node).set(SpecDouble);
break;
}
- case CheckNumber:
- forNode(node.child1()).filter(SpecNumber);
- break;
-
case ValueAdd:
case ArithAdd: {
- JSValue left = forNode(node.child1()).value();
- JSValue right = forNode(node.child2()).value();
+ JSValue left = forNode(node->child1()).value();
+ JSValue right = forNode(node->child2()).value();
if (left && right && left.isNumber() && right.isNumber()
- && trySetConstant(nodeIndex, JSValue(left.asNumber() + right.asNumber()))) {
+ && trySetConstant(node, JSValue(left.asNumber() + right.asNumber()))) {
m_foundConstants = true;
- node.setCanExit(false);
break;
}
- if (m_graph.addShouldSpeculateInteger(node)) {
- speculateInt32Binary(
- node, !nodeCanTruncateInteger(node.arithNodeFlags()));
- forNode(nodeIndex).set(SpecInt32);
+ switch (node->binaryUseKind()) {
+ case Int32Use:
+ forNode(node).set(SpecInt32);
+ if (!nodeCanTruncateInteger(node->arithNodeFlags()))
+ node->setCanExit(true);
break;
- }
- if (Node::shouldSpeculateNumberExpectingDefined(m_graph[node.child1()], m_graph[node.child2()])) {
- speculateNumberBinary(node);
- if (isRealNumberSpeculation(forNode(node.child1()).m_type)
- && isRealNumberSpeculation(forNode(node.child2()).m_type))
- forNode(nodeIndex).set(SpecDoubleReal);
+ case NumberUse:
+ if (isRealNumberSpeculation(forNode(node->child1()).m_type)
+ && isRealNumberSpeculation(forNode(node->child2()).m_type))
+ forNode(node).set(SpecDoubleReal);
else
- forNode(nodeIndex).set(SpecDouble);
+ forNode(node).set(SpecDouble);
break;
- }
- if (node.op() == ValueAdd) {
- clobberWorld(node.codeOrigin, indexInBlock);
- forNode(nodeIndex).set(SpecString | SpecInt32 | SpecNumber);
- node.setCanExit(false);
+ default:
+ RELEASE_ASSERT(node->op() == ValueAdd);
+ clobberWorld(node->codeOrigin, indexInBlock);
+ forNode(node).set(SpecString | SpecInt32 | SpecNumber);
break;
}
- // We don't handle this yet. :-(
- m_isValid = false;
- node.setCanExit(true);
+ break;
+ }
+
+ case MakeRope: {
+ forNode(node).set(m_graph.m_vm.stringStructure.get());
break;
}
case ArithSub: {
- JSValue left = forNode(node.child1()).value();
- JSValue right = forNode(node.child2()).value();
+ JSValue left = forNode(node->child1()).value();
+ JSValue right = forNode(node->child2()).value();
if (left && right && left.isNumber() && right.isNumber()
- && trySetConstant(nodeIndex, JSValue(left.asNumber() - right.asNumber()))) {
+ && trySetConstant(node, JSValue(left.asNumber() - right.asNumber()))) {
m_foundConstants = true;
- node.setCanExit(false);
break;
}
- if (m_graph.addShouldSpeculateInteger(node)) {
- speculateInt32Binary(
- node, !nodeCanTruncateInteger(node.arithNodeFlags()));
- forNode(nodeIndex).set(SpecInt32);
+ switch (node->binaryUseKind()) {
+ case Int32Use:
+ forNode(node).set(SpecInt32);
+ if (!nodeCanTruncateInteger(node->arithNodeFlags()))
+ node->setCanExit(true);
+ break;
+ case NumberUse:
+ forNode(node).set(SpecDouble);
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
break;
}
- speculateNumberBinary(node);
- forNode(nodeIndex).set(SpecDouble);
break;
}
case ArithNegate: {
- JSValue child = forNode(node.child1()).value();
+ JSValue child = forNode(node->child1()).value();
if (child && child.isNumber()
- && trySetConstant(nodeIndex, JSValue(-child.asNumber()))) {
+ && trySetConstant(node, JSValue(-child.asNumber()))) {
m_foundConstants = true;
- node.setCanExit(false);
break;
}
- if (m_graph.negateShouldSpeculateInteger(node)) {
- speculateInt32Unary(
- node, !nodeCanTruncateInteger(node.arithNodeFlags()));
- forNode(nodeIndex).set(SpecInt32);
+ switch (node->child1().useKind()) {
+ case Int32Use:
+ forNode(node).set(SpecInt32);
+ if (!nodeCanTruncateInteger(node->arithNodeFlags()))
+ node->setCanExit(true);
+ break;
+ case NumberUse:
+ forNode(node).set(SpecDouble);
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
break;
}
- speculateNumberUnary(node);
- forNode(nodeIndex).set(SpecDouble);
break;
}
case ArithMul: {
- JSValue left = forNode(node.child1()).value();
- JSValue right = forNode(node.child2()).value();
+ JSValue left = forNode(node->child1()).value();
+ JSValue right = forNode(node->child2()).value();
if (left && right && left.isNumber() && right.isNumber()
- && trySetConstant(nodeIndex, JSValue(left.asNumber() * right.asNumber()))) {
+ && trySetConstant(node, JSValue(left.asNumber() * right.asNumber()))) {
m_foundConstants = true;
- node.setCanExit(false);
break;
}
- if (m_graph.mulShouldSpeculateInteger(node)) {
- speculateInt32Binary(
- node,
- !nodeCanTruncateInteger(node.arithNodeFlags())
- || !nodeCanIgnoreNegativeZero(node.arithNodeFlags()));
- forNode(nodeIndex).set(SpecInt32);
+ switch (node->binaryUseKind()) {
+ case Int32Use:
+ forNode(node).set(SpecInt32);
+ if (!nodeCanTruncateInteger(node->arithNodeFlags())
+ || !nodeCanIgnoreNegativeZero(node->arithNodeFlags()))
+ node->setCanExit(true);
+ break;
+ case NumberUse:
+ if (isRealNumberSpeculation(forNode(node->child1()).m_type)
+ || isRealNumberSpeculation(forNode(node->child2()).m_type))
+ forNode(node).set(SpecDoubleReal);
+ else
+ forNode(node).set(SpecDouble);
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
break;
}
- speculateNumberBinary(node);
- if (isRealNumberSpeculation(forNode(node.child1()).m_type)
- || isRealNumberSpeculation(forNode(node.child2()).m_type))
- forNode(nodeIndex).set(SpecDoubleReal);
- else
- forNode(nodeIndex).set(SpecDouble);
+ break;
+ }
+
+ case ArithIMul: {
+ forNode(node).set(SpecInt32);
break;
}
@@ -567,110 +565,113 @@ bool AbstractState::execute(unsigned indexInBlock)
case ArithMin:
case ArithMax:
case ArithMod: {
- JSValue left = forNode(node.child1()).value();
- JSValue right = forNode(node.child2()).value();
+ JSValue left = forNode(node->child1()).value();
+ JSValue right = forNode(node->child2()).value();
if (left && right && left.isNumber() && right.isNumber()) {
double a = left.asNumber();
double b = right.asNumber();
bool constantWasSet;
- switch (node.op()) {
+ switch (node->op()) {
case ArithDiv:
- constantWasSet = trySetConstant(nodeIndex, JSValue(a / b));
+ constantWasSet = trySetConstant(node, JSValue(a / b));
break;
case ArithMin:
- constantWasSet = trySetConstant(nodeIndex, JSValue(a < b ? a : (b <= a ? b : a + b)));
+ constantWasSet = trySetConstant(node, JSValue(a < b ? a : (b <= a ? b : a + b)));
break;
case ArithMax:
- constantWasSet = trySetConstant(nodeIndex, JSValue(a > b ? a : (b >= a ? b : a + b)));
+ constantWasSet = trySetConstant(node, JSValue(a > b ? a : (b >= a ? b : a + b)));
break;
case ArithMod:
- constantWasSet = trySetConstant(nodeIndex, JSValue(fmod(a, b)));
+ constantWasSet = trySetConstant(node, JSValue(fmod(a, b)));
break;
default:
- ASSERT_NOT_REACHED();
+ RELEASE_ASSERT_NOT_REACHED();
constantWasSet = false;
break;
}
if (constantWasSet) {
m_foundConstants = true;
- node.setCanExit(false);
break;
}
}
- if (Node::shouldSpeculateIntegerForArithmetic(
- m_graph[node.child1()], m_graph[node.child2()])
- && node.canSpeculateInteger()) {
- speculateInt32Binary(node, true); // forcing can-exit, which is a bit on the conservative side.
- forNode(nodeIndex).set(SpecInt32);
+ switch (node->binaryUseKind()) {
+ case Int32Use:
+ forNode(node).set(SpecInt32);
+ node->setCanExit(true);
+ break;
+ case NumberUse:
+ forNode(node).set(SpecDouble);
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
break;
}
- speculateNumberBinary(node);
- forNode(nodeIndex).set(SpecDouble);
break;
}
case ArithAbs: {
- JSValue child = forNode(node.child1()).value();
+ JSValue child = forNode(node->child1()).value();
if (child && child.isNumber()
- && trySetConstant(nodeIndex, JSValue(fabs(child.asNumber())))) {
+ && trySetConstant(node, JSValue(fabs(child.asNumber())))) {
m_foundConstants = true;
- node.setCanExit(false);
break;
}
- if (m_graph[node.child1()].shouldSpeculateIntegerForArithmetic()
- && node.canSpeculateInteger()) {
- speculateInt32Unary(node, true);
- forNode(nodeIndex).set(SpecInt32);
+ switch (node->child1().useKind()) {
+ case Int32Use:
+ forNode(node).set(SpecInt32);
+ node->setCanExit(true);
+ break;
+ case NumberUse:
+ forNode(node).set(SpecDouble);
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
break;
}
- speculateNumberUnary(node);
- forNode(nodeIndex).set(SpecDouble);
break;
}
case ArithSqrt: {
- JSValue child = forNode(node.child1()).value();
+ JSValue child = forNode(node->child1()).value();
if (child && child.isNumber()
- && trySetConstant(nodeIndex, JSValue(sqrt(child.asNumber())))) {
+ && trySetConstant(node, JSValue(sqrt(child.asNumber())))) {
m_foundConstants = true;
- node.setCanExit(false);
break;
}
- speculateNumberUnary(node);
- forNode(nodeIndex).set(SpecDouble);
+ forNode(node).set(SpecDouble);
break;
}
case LogicalNot: {
bool didSetConstant = false;
- switch (booleanResult(node, forNode(node.child1()))) {
+ switch (booleanResult(node, forNode(node->child1()))) {
case DefinitelyTrue:
- didSetConstant = trySetConstant(nodeIndex, jsBoolean(false));
+ didSetConstant = trySetConstant(node, jsBoolean(false));
break;
case DefinitelyFalse:
- didSetConstant = trySetConstant(nodeIndex, jsBoolean(true));
+ didSetConstant = trySetConstant(node, jsBoolean(true));
break;
default:
break;
}
if (didSetConstant) {
m_foundConstants = true;
- node.setCanExit(false);
break;
}
- Node& child = m_graph[node.child1()];
- if (isBooleanSpeculation(child.prediction()))
- speculateBooleanUnary(node);
- else if (child.shouldSpeculateNonStringCellOrOther()) {
- node.setCanExit(true);
- forNode(node.child1()).filter((SpecCell & ~SpecString) | SpecOther);
- } else if (child.shouldSpeculateInteger())
- speculateInt32Unary(node);
- else if (child.shouldSpeculateNumber())
- speculateNumberUnary(node);
- else
- node.setCanExit(false);
- forNode(nodeIndex).set(SpecBoolean);
+ switch (node->child1().useKind()) {
+ case BooleanUse:
+ case Int32Use:
+ case NumberUse:
+ case UntypedUse:
+ break;
+ case ObjectOrOtherUse:
+ node->setCanExit(true);
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+ forNode(node).set(SpecBoolean);
break;
}
@@ -680,33 +681,38 @@ bool AbstractState::execute(unsigned indexInBlock)
case IsString:
case IsObject:
case IsFunction: {
- node.setCanExit(node.op() == IsUndefined && m_codeBlock->globalObjectFor(node.codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid());
- JSValue child = forNode(node.child1()).value();
+ node->setCanExit(node->op() == IsUndefined && m_codeBlock->globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid());
+ JSValue child = forNode(node->child1()).value();
if (child) {
bool constantWasSet;
- switch (node.op()) {
+ switch (node->op()) {
case IsUndefined:
- if (m_codeBlock->globalObjectFor(node.codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
- constantWasSet = trySetConstant(nodeIndex, jsBoolean(
+ if (m_codeBlock->globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
+ constantWasSet = trySetConstant(node, jsBoolean(
child.isCell()
? false
: child.isUndefined()));
} else {
- constantWasSet = trySetConstant(nodeIndex, jsBoolean(
+ constantWasSet = trySetConstant(node, jsBoolean(
child.isCell()
- ? child.asCell()->structure()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node.codeOrigin))
+ ? child.asCell()->structure()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->codeOrigin))
: child.isUndefined()));
}
break;
case IsBoolean:
- constantWasSet = trySetConstant(nodeIndex, jsBoolean(child.isBoolean()));
+ constantWasSet = trySetConstant(node, jsBoolean(child.isBoolean()));
break;
case IsNumber:
- constantWasSet = trySetConstant(nodeIndex, jsBoolean(child.isNumber()));
+ constantWasSet = trySetConstant(node, jsBoolean(child.isNumber()));
break;
case IsString:
- constantWasSet = trySetConstant(nodeIndex, jsBoolean(isJSString(child)));
+ constantWasSet = trySetConstant(node, jsBoolean(isJSString(child)));
break;
+ case IsObject:
+ if (child.isNull() || !child.isObject()) {
+ constantWasSet = trySetConstant(node, jsBoolean(child.isNull()));
+ break;
+ }
default:
constantWasSet = false;
break;
@@ -716,7 +722,65 @@ bool AbstractState::execute(unsigned indexInBlock)
break;
}
}
- forNode(nodeIndex).set(SpecBoolean);
+
+ forNode(node).set(SpecBoolean);
+ break;
+ }
+
+ case TypeOf: {
+ VM* vm = m_codeBlock->vm();
+ JSValue child = forNode(node->child1()).value();
+ AbstractValue& abstractChild = forNode(node->child1());
+ if (child) {
+ JSValue typeString = jsTypeStringForValue(*vm, m_codeBlock->globalObjectFor(node->codeOrigin), child);
+ if (trySetConstant(node, typeString)) {
+ m_foundConstants = true;
+ break;
+ }
+ } else if (isNumberSpeculation(abstractChild.m_type)) {
+ if (trySetConstant(node, vm->smallStrings.numberString())) {
+ forNode(node->child1()).filter(SpecNumber);
+ m_foundConstants = true;
+ break;
+ }
+ } else if (isStringSpeculation(abstractChild.m_type)) {
+ if (trySetConstant(node, vm->smallStrings.stringString())) {
+ forNode(node->child1()).filter(SpecString);
+ m_foundConstants = true;
+ break;
+ }
+ } else if (isFinalObjectSpeculation(abstractChild.m_type) || isArraySpeculation(abstractChild.m_type) || isArgumentsSpeculation(abstractChild.m_type)) {
+ if (trySetConstant(node, vm->smallStrings.objectString())) {
+ forNode(node->child1()).filter(SpecFinalObject | SpecArray | SpecArguments);
+ m_foundConstants = true;
+ break;
+ }
+ } else if (isFunctionSpeculation(abstractChild.m_type)) {
+ if (trySetConstant(node, vm->smallStrings.functionString())) {
+ forNode(node->child1()).filter(SpecFunction);
+ m_foundConstants = true;
+ break;
+ }
+ } else if (isBooleanSpeculation(abstractChild.m_type)) {
+ if (trySetConstant(node, vm->smallStrings.booleanString())) {
+ forNode(node->child1()).filter(SpecBoolean);
+ m_foundConstants = true;
+ break;
+ }
+ }
+
+ switch (node->child1().useKind()) {
+ case StringUse:
+ case CellUse:
+ node->setCanExit(true);
+ break;
+ case UntypedUse:
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+ forNode(node).set(m_graph.m_vm.stringStructure.get());
break;
}
@@ -724,266 +788,169 @@ bool AbstractState::execute(unsigned indexInBlock)
case CompareLessEq:
case CompareGreater:
case CompareGreaterEq:
- case CompareEq: {
+ case CompareEq:
+ case CompareEqConstant: {
bool constantWasSet = false;
- JSValue leftConst = forNode(node.child1()).value();
- JSValue rightConst = forNode(node.child2()).value();
+ JSValue leftConst = forNode(node->child1()).value();
+ JSValue rightConst = forNode(node->child2()).value();
if (leftConst && rightConst && leftConst.isNumber() && rightConst.isNumber()) {
double a = leftConst.asNumber();
double b = rightConst.asNumber();
- switch (node.op()) {
+ switch (node->op()) {
case CompareLess:
- constantWasSet = trySetConstant(nodeIndex, jsBoolean(a < b));
+ constantWasSet = trySetConstant(node, jsBoolean(a < b));
break;
case CompareLessEq:
- constantWasSet = trySetConstant(nodeIndex, jsBoolean(a <= b));
+ constantWasSet = trySetConstant(node, jsBoolean(a <= b));
break;
case CompareGreater:
- constantWasSet = trySetConstant(nodeIndex, jsBoolean(a > b));
+ constantWasSet = trySetConstant(node, jsBoolean(a > b));
break;
case CompareGreaterEq:
- constantWasSet = trySetConstant(nodeIndex, jsBoolean(a >= b));
+ constantWasSet = trySetConstant(node, jsBoolean(a >= b));
break;
case CompareEq:
- constantWasSet = trySetConstant(nodeIndex, jsBoolean(a == b));
+ constantWasSet = trySetConstant(node, jsBoolean(a == b));
break;
default:
- ASSERT_NOT_REACHED();
+ RELEASE_ASSERT_NOT_REACHED();
constantWasSet = false;
break;
}
}
- if (!constantWasSet && node.op() == CompareEq) {
- SpeculatedType leftType = forNode(node.child1()).m_type;
- SpeculatedType rightType = forNode(node.child2()).m_type;
+ if (!constantWasSet && (node->op() == CompareEqConstant || node->op() == CompareEq)) {
+ SpeculatedType leftType = forNode(node->child1()).m_type;
+ SpeculatedType rightType = forNode(node->child2()).m_type;
if ((isInt32Speculation(leftType) && isOtherSpeculation(rightType))
|| (isOtherSpeculation(leftType) && isInt32Speculation(rightType)))
- constantWasSet = trySetConstant(nodeIndex, jsBoolean(false));
+ constantWasSet = trySetConstant(node, jsBoolean(false));
}
if (constantWasSet) {
m_foundConstants = true;
- node.setCanExit(false);
break;
}
- forNode(nodeIndex).set(SpecBoolean);
+ forNode(node).set(SpecBoolean);
- Node& left = m_graph[node.child1()];
- Node& right = m_graph[node.child2()];
- SpeculatedType filter;
- SpeculatedTypeChecker checker;
- if (Node::shouldSpeculateInteger(left, right)) {
- filter = SpecInt32;
- checker = isInt32Speculation;
- } else if (Node::shouldSpeculateNumber(left, right)) {
- filter = SpecNumber;
- checker = isNumberSpeculation;
- } else if (node.op() == CompareEq) {
- if ((m_graph.isConstant(node.child1().index())
- && m_graph.valueOfJSConstant(node.child1().index()).isNull())
- || (m_graph.isConstant(node.child2().index())
- && m_graph.valueOfJSConstant(node.child2().index()).isNull())) {
- // We can exit if we haven't fired the MasqueradesAsUndefind watchpoint yet.
- node.setCanExit(m_codeBlock->globalObjectFor(node.codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid());
- break;
- }
-
- if (left.shouldSpeculateString() || right.shouldSpeculateString()) {
- node.setCanExit(false);
- break;
- }
- if (left.shouldSpeculateNonStringCell() && right.shouldSpeculateNonStringCellOrOther()) {
- node.setCanExit(true);
- forNode(node.child1()).filter(SpecCell & ~SpecString);
- forNode(node.child2()).filter((SpecCell & ~SpecString) | SpecOther);
- break;
- }
- if (left.shouldSpeculateNonStringCellOrOther() && right.shouldSpeculateNonStringCell()) {
- node.setCanExit(true);
- forNode(node.child1()).filter((SpecCell & ~SpecString) | SpecOther);
- forNode(node.child2()).filter(SpecCell & ~SpecString);
- break;
- }
- if (left.shouldSpeculateNonStringCell() && right.shouldSpeculateNonStringCell()) {
- node.setCanExit(true);
- forNode(node.child1()).filter(SpecCell & ~SpecString);
- forNode(node.child2()).filter(SpecCell & ~SpecString);
- break;
- }
-
- filter = SpecTop;
- checker = isAnySpeculation;
- clobberWorld(node.codeOrigin, indexInBlock);
- } else {
- filter = SpecTop;
- checker = isAnySpeculation;
- clobberWorld(node.codeOrigin, indexInBlock);
- }
- node.setCanExit(
- !checker(forNode(node.child1()).m_type)
- || !checker(forNode(node.child2()).m_type));
- forNode(node.child1()).filter(filter);
- forNode(node.child2()).filter(filter);
+ // This is overly conservative. But the only thing this prevents is store elimination,
+ // and how likely is it, really, that you'll have redundant stores across a comparison
+ // operation? Comparison operations are typically at the end of basic blocks, so
+ // unless we have global store elimination (super unlikely given how unprofitable that
+ // optimization is to begin with), you aren't going to be wanting to store eliminate
+ // across an equality op.
+ node->setCanExit(true);
break;
}
- case CompareStrictEq: {
- JSValue left = forNode(node.child1()).value();
- JSValue right = forNode(node.child2()).value();
+ case CompareStrictEq:
+ case CompareStrictEqConstant: {
+ Node* leftNode = node->child1().node();
+ Node* rightNode = node->child2().node();
+ JSValue left = forNode(leftNode).value();
+ JSValue right = forNode(rightNode).value();
if (left && right && left.isNumber() && right.isNumber()
- && trySetConstant(nodeIndex, jsBoolean(left.asNumber() == right.asNumber()))) {
+ && trySetConstant(node, jsBoolean(left.asNumber() == right.asNumber()))) {
m_foundConstants = true;
- node.setCanExit(false);
- break;
- }
- forNode(nodeIndex).set(SpecBoolean);
- if (m_graph.isJSConstant(node.child1().index())) {
- JSValue value = m_graph.valueOfJSConstant(node.child1().index());
- if (!value.isNumber() && !value.isString()) {
- node.setCanExit(false);
- break;
- }
- }
- if (m_graph.isJSConstant(node.child2().index())) {
- JSValue value = m_graph.valueOfJSConstant(node.child2().index());
- if (!value.isNumber() && !value.isString()) {
- node.setCanExit(false);
- break;
- }
- }
- if (Node::shouldSpeculateInteger(
- m_graph[node.child1()], m_graph[node.child2()])) {
- speculateInt32Binary(node);
break;
}
- if (Node::shouldSpeculateNumber(
- m_graph[node.child1()], m_graph[node.child2()])) {
- speculateNumberBinary(node);
- break;
- }
- Node& leftNode = m_graph[node.child1()];
- Node& rightNode = m_graph[node.child2()];
- if (leftNode.shouldSpeculateString() || rightNode.shouldSpeculateString()) {
- node.setCanExit(false);
- break;
- }
- if (leftNode.shouldSpeculateNonStringCell() && rightNode.shouldSpeculateNonStringCell()) {
- node.setCanExit(true);
- forNode(node.child1()).filter((SpecCell & ~SpecString) | SpecOther);
- forNode(node.child2()).filter((SpecCell & ~SpecString) | SpecOther);
- break;
- }
- node.setCanExit(false);
+ forNode(node).set(SpecBoolean);
+ node->setCanExit(true); // This is overly conservative.
break;
}
case StringCharCodeAt:
- node.setCanExit(true);
- forNode(node.child1()).filter(SpecString);
- forNode(node.child2()).filter(SpecInt32);
- forNode(nodeIndex).set(SpecInt32);
+ node->setCanExit(true);
+ forNode(node).set(SpecInt32);
break;
+ case StringFromCharCode:
+ forNode(node).set(SpecString);
+ break;
+
case StringCharAt:
- node.setCanExit(true);
- forNode(node.child1()).filter(SpecString);
- forNode(node.child2()).filter(SpecInt32);
- forNode(nodeIndex).set(SpecString);
+ node->setCanExit(true);
+ forNode(node).set(m_graph.m_vm.stringStructure.get());
break;
case GetByVal: {
- node.setCanExit(true);
- switch (node.arrayMode().type()) {
+ node->setCanExit(true);
+ switch (node->arrayMode().type()) {
case Array::SelectUsingPredictions:
case Array::Unprofiled:
case Array::Undecided:
- ASSERT_NOT_REACHED();
+ RELEASE_ASSERT_NOT_REACHED();
break;
case Array::ForceExit:
m_isValid = false;
break;
case Array::Generic:
- clobberWorld(node.codeOrigin, indexInBlock);
- forNode(nodeIndex).makeTop();
+ clobberWorld(node->codeOrigin, indexInBlock);
+ forNode(node).makeTop();
break;
case Array::String:
- forNode(node.child2()).filter(SpecInt32);
- forNode(nodeIndex).set(SpecString);
+ forNode(node).set(m_graph.m_vm.stringStructure.get());
break;
case Array::Arguments:
- forNode(node.child2()).filter(SpecInt32);
- forNode(nodeIndex).makeTop();
+ forNode(node).makeTop();
break;
case Array::Int32:
- forNode(node.child2()).filter(SpecInt32);
- if (node.arrayMode().isOutOfBounds()) {
- clobberWorld(node.codeOrigin, indexInBlock);
- forNode(nodeIndex).makeTop();
+ if (node->arrayMode().isOutOfBounds()) {
+ clobberWorld(node->codeOrigin, indexInBlock);
+ forNode(node).makeTop();
} else
- forNode(nodeIndex).set(SpecInt32);
+ forNode(node).set(SpecInt32);
break;
case Array::Double:
- forNode(node.child2()).filter(SpecInt32);
- if (node.arrayMode().isOutOfBounds()) {
- clobberWorld(node.codeOrigin, indexInBlock);
- forNode(nodeIndex).makeTop();
- } else if (node.arrayMode().isSaneChain())
- forNode(nodeIndex).set(SpecDouble);
+ if (node->arrayMode().isOutOfBounds()) {
+ clobberWorld(node->codeOrigin, indexInBlock);
+ forNode(node).makeTop();
+ } else if (node->arrayMode().isSaneChain())
+ forNode(node).set(SpecDouble);
else
- forNode(nodeIndex).set(SpecDoubleReal);
+ forNode(node).set(SpecDoubleReal);
break;
case Array::Contiguous:
case Array::ArrayStorage:
case Array::SlowPutArrayStorage:
- forNode(node.child2()).filter(SpecInt32);
- if (node.arrayMode().isOutOfBounds())
- clobberWorld(node.codeOrigin, indexInBlock);
- forNode(nodeIndex).makeTop();
+ if (node->arrayMode().isOutOfBounds())
+ clobberWorld(node->codeOrigin, indexInBlock);
+ forNode(node).makeTop();
break;
case Array::Int8Array:
- forNode(node.child2()).filter(SpecInt32);
- forNode(nodeIndex).set(SpecInt32);
+ forNode(node).set(SpecInt32);
break;
case Array::Int16Array:
- forNode(node.child2()).filter(SpecInt32);
- forNode(nodeIndex).set(SpecInt32);
+ forNode(node).set(SpecInt32);
break;
case Array::Int32Array:
- forNode(node.child2()).filter(SpecInt32);
- forNode(nodeIndex).set(SpecInt32);
+ forNode(node).set(SpecInt32);
break;
case Array::Uint8Array:
- forNode(node.child2()).filter(SpecInt32);
- forNode(nodeIndex).set(SpecInt32);
+ forNode(node).set(SpecInt32);
break;
case Array::Uint8ClampedArray:
- forNode(node.child2()).filter(SpecInt32);
- forNode(nodeIndex).set(SpecInt32);
+ forNode(node).set(SpecInt32);
break;
case Array::Uint16Array:
- forNode(node.child2()).filter(SpecInt32);
- forNode(nodeIndex).set(SpecInt32);
+ forNode(node).set(SpecInt32);
break;
case Array::Uint32Array:
- forNode(node.child2()).filter(SpecInt32);
- if (node.shouldSpeculateInteger())
- forNode(nodeIndex).set(SpecInt32);
+ if (node->shouldSpeculateInteger())
+ forNode(node).set(SpecInt32);
else
- forNode(nodeIndex).set(SpecDouble);
+ forNode(node).set(SpecDouble);
break;
case Array::Float32Array:
- forNode(node.child2()).filter(SpecInt32);
- forNode(nodeIndex).set(SpecDouble);
+ forNode(node).set(SpecDouble);
break;
case Array::Float64Array:
- forNode(node.child2()).filter(SpecInt32);
- forNode(nodeIndex).set(SpecDouble);
+ forNode(node).set(SpecDouble);
break;
default:
- ASSERT_NOT_REACHED();
+ RELEASE_ASSERT_NOT_REACHED();
break;
}
break;
@@ -991,286 +958,189 @@ bool AbstractState::execute(unsigned indexInBlock)
case PutByVal:
case PutByValAlias: {
- node.setCanExit(true);
- Edge child1 = m_graph.varArgChild(node, 0);
- Edge child2 = m_graph.varArgChild(node, 1);
- Edge child3 = m_graph.varArgChild(node, 2);
- switch (node.arrayMode().modeForPut().type()) {
+ node->setCanExit(true);
+ switch (node->arrayMode().modeForPut().type()) {
case Array::ForceExit:
m_isValid = false;
break;
case Array::Generic:
- clobberWorld(node.codeOrigin, indexInBlock);
+ clobberWorld(node->codeOrigin, indexInBlock);
break;
case Array::Int32:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- forNode(child3).filter(SpecInt32);
- if (node.arrayMode().isOutOfBounds())
- clobberWorld(node.codeOrigin, indexInBlock);
+ if (node->arrayMode().isOutOfBounds())
+ clobberWorld(node->codeOrigin, indexInBlock);
break;
case Array::Double:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- forNode(child3).filter(SpecRealNumber);
- if (node.arrayMode().isOutOfBounds())
- clobberWorld(node.codeOrigin, indexInBlock);
+ if (node->arrayMode().isOutOfBounds())
+ clobberWorld(node->codeOrigin, indexInBlock);
break;
case Array::Contiguous:
case Array::ArrayStorage:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- if (node.arrayMode().isOutOfBounds())
- clobberWorld(node.codeOrigin, indexInBlock);
+ if (node->arrayMode().isOutOfBounds())
+ clobberWorld(node->codeOrigin, indexInBlock);
break;
case Array::SlowPutArrayStorage:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- if (node.arrayMode().mayStoreToHole())
- clobberWorld(node.codeOrigin, indexInBlock);
- break;
- case Array::Arguments:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- break;
- case Array::Int8Array:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- if (m_graph[child3].shouldSpeculateInteger())
- forNode(child3).filter(SpecInt32);
- else
- forNode(child3).filter(SpecNumber);
- break;
- case Array::Int16Array:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- if (m_graph[child3].shouldSpeculateInteger())
- forNode(child3).filter(SpecInt32);
- else
- forNode(child3).filter(SpecNumber);
- break;
- case Array::Int32Array:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- if (m_graph[child3].shouldSpeculateInteger())
- forNode(child3).filter(SpecInt32);
- else
- forNode(child3).filter(SpecNumber);
- break;
- case Array::Uint8Array:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- if (m_graph[child3].shouldSpeculateInteger())
- forNode(child3).filter(SpecInt32);
- else
- forNode(child3).filter(SpecNumber);
- break;
- case Array::Uint8ClampedArray:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- if (m_graph[child3].shouldSpeculateInteger())
- forNode(child3).filter(SpecInt32);
- else
- forNode(child3).filter(SpecNumber);
- break;
- case Array::Uint16Array:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- if (m_graph[child3].shouldSpeculateInteger())
- forNode(child3).filter(SpecInt32);
- else
- forNode(child3).filter(SpecNumber);
- break;
- case Array::Uint32Array:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- if (m_graph[child3].shouldSpeculateInteger())
- forNode(child3).filter(SpecInt32);
- else
- forNode(child3).filter(SpecNumber);
- break;
- case Array::Float32Array:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- forNode(child3).filter(SpecNumber);
- break;
- case Array::Float64Array:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- forNode(child3).filter(SpecNumber);
+ if (node->arrayMode().mayStoreToHole())
+ clobberWorld(node->codeOrigin, indexInBlock);
break;
default:
- CRASH();
break;
}
break;
}
case ArrayPush:
- node.setCanExit(true);
- switch (node.arrayMode().type()) {
- case Array::Int32:
- forNode(node.child2()).filter(SpecInt32);
- break;
- case Array::Double:
- forNode(node.child2()).filter(SpecRealNumber);
- break;
- default:
- break;
- }
- clobberWorld(node.codeOrigin, indexInBlock);
- forNode(nodeIndex).set(SpecNumber);
+ node->setCanExit(true);
+ clobberWorld(node->codeOrigin, indexInBlock);
+ forNode(node).set(SpecNumber);
break;
case ArrayPop:
- node.setCanExit(true);
- clobberWorld(node.codeOrigin, indexInBlock);
- forNode(nodeIndex).makeTop();
+ node->setCanExit(true);
+ clobberWorld(node->codeOrigin, indexInBlock);
+ forNode(node).makeTop();
break;
case RegExpExec:
+ forNode(node).makeTop();
+ break;
+
case RegExpTest:
- node.setCanExit(
- !isCellSpeculation(forNode(node.child1()).m_type)
- || !isCellSpeculation(forNode(node.child2()).m_type));
- forNode(node.child1()).filter(SpecCell);
- forNode(node.child2()).filter(SpecCell);
- forNode(nodeIndex).makeTop();
+ forNode(node).set(SpecBoolean);
break;
case Jump:
- node.setCanExit(false);
break;
case Branch: {
- BooleanResult result = booleanResult(node, forNode(node.child1()));
+ Node* child = node->child1().node();
+ BooleanResult result = booleanResult(node, forNode(child));
if (result == DefinitelyTrue) {
m_branchDirection = TakeTrue;
- node.setCanExit(false);
break;
}
if (result == DefinitelyFalse) {
m_branchDirection = TakeFalse;
- node.setCanExit(false);
break;
}
// FIXME: The above handles the trivial cases of sparse conditional
// constant propagation, but we can do better:
// We can specialize the source variable's value on each direction of
// the branch.
- Node& child = m_graph[node.child1()];
- if (child.shouldSpeculateBoolean())
- speculateBooleanUnary(node);
- else if (child.shouldSpeculateNonStringCellOrOther()) {
- node.setCanExit(true);
- forNode(node.child1()).filter((SpecCell & ~SpecString) | SpecOther);
- } else if (child.shouldSpeculateInteger())
- speculateInt32Unary(node);
- else if (child.shouldSpeculateNumber())
- speculateNumberUnary(node);
- else
- node.setCanExit(false);
+ node->setCanExit(true); // This is overly conservative.
m_branchDirection = TakeBoth;
break;
}
case Return:
m_isValid = false;
- node.setCanExit(false);
break;
case Throw:
case ThrowReferenceError:
m_isValid = false;
- node.setCanExit(true);
+ node->setCanExit(true);
break;
case ToPrimitive: {
- JSValue childConst = forNode(node.child1()).value();
- if (childConst && childConst.isNumber() && trySetConstant(nodeIndex, childConst)) {
+ JSValue childConst = forNode(node->child1()).value();
+ if (childConst && childConst.isNumber() && trySetConstant(node, childConst)) {
m_foundConstants = true;
- node.setCanExit(false);
break;
}
- Node& child = m_graph[node.child1()];
- if (child.shouldSpeculateInteger()) {
- speculateInt32Unary(node);
- forNode(nodeIndex).set(SpecInt32);
- break;
- }
-
- AbstractValue& source = forNode(node.child1());
- AbstractValue& destination = forNode(nodeIndex);
-
+ ASSERT(node->child1().useKind() == UntypedUse);
+
+ AbstractValue& source = forNode(node->child1());
+ AbstractValue& destination = forNode(node);
+
+ // NB. The more canonical way of writing this would have been:
+ //
+ // destination = source;
+ // if (destination.m_type & !(SpecNumber | SpecString | SpecBoolean)) {
+ // destination.filter(SpecNumber | SpecString | SpecBoolean);
+ // AbstractValue string;
+ // string.set(vm->stringStructure);
+ // destination.merge(string);
+ // }
+ //
+ // The reason why this would, in most other cases, have been better is that
+ // then destination would preserve any non-SpeculatedType knowledge of source.
+ // As it stands, the code below forgets any non-SpeculatedType knowledge that
+ // source would have had. Fortunately, though, for things like strings and
+ // numbers and booleans, we don't care about the non-SpeculatedType knowedge:
+ // the structure won't tell us anything we don't already know, and neither
+ // will ArrayModes. And if the source was a meaningful constant then we
+ // would have handled that above. Unfortunately, this does mean that
+ // ToPrimitive will currently forget string constants. But that's not a big
+ // deal since we don't do any optimization on those currently.
+
+ clobberWorld(node->codeOrigin, indexInBlock);
+
SpeculatedType type = source.m_type;
if (type & ~(SpecNumber | SpecString | SpecBoolean)) {
type &= (SpecNumber | SpecString | SpecBoolean);
type |= SpecString;
}
destination.set(type);
- node.setCanExit(false);
break;
}
-
- case StrCat:
- node.setCanExit(false);
- forNode(nodeIndex).set(SpecString);
+
+ case ToString: {
+ switch (node->child1().useKind()) {
+ case StringObjectUse:
+ // This also filters that the StringObject has the primordial StringObject
+ // structure.
+ forNode(node->child1()).filter(m_graph.globalObjectFor(node->codeOrigin)->stringObjectStructure());
+ node->setCanExit(true); // We could be more precise but it's likely not worth it.
+ break;
+ case StringOrStringObjectUse:
+ node->setCanExit(true); // We could be more precise but it's likely not worth it.
+ break;
+ case CellUse:
+ case UntypedUse:
+ clobberWorld(node->codeOrigin, indexInBlock);
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+ forNode(node).set(m_graph.m_vm.stringStructure.get());
+ break;
+ }
+
+ case NewStringObject: {
+ ASSERT(node->structure()->classInfo() == &StringObject::s_info);
+ forNode(node).set(node->structure());
break;
+ }
case NewArray:
- node.setCanExit(true);
- forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()));
+ node->setCanExit(true);
+ forNode(node).set(m_graph.globalObjectFor(node->codeOrigin)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
m_haveStructures = true;
break;
case NewArrayBuffer:
- node.setCanExit(true);
- forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()));
+ node->setCanExit(true);
+ forNode(node).set(m_graph.globalObjectFor(node->codeOrigin)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
m_haveStructures = true;
break;
case NewArrayWithSize:
- node.setCanExit(true);
- forNode(node.child1()).filter(SpecInt32);
- forNode(nodeIndex).set(SpecArray);
+ node->setCanExit(true);
+ forNode(node).set(SpecArray);
m_haveStructures = true;
break;
case NewRegexp:
- node.setCanExit(false);
- forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->regExpStructure());
+ forNode(node).set(m_graph.globalObjectFor(node->codeOrigin)->regExpStructure());
m_haveStructures = true;
break;
case ConvertThis: {
- Node& child = m_graph[node.child1()];
- AbstractValue& source = forNode(node.child1());
- AbstractValue& destination = forNode(nodeIndex);
-
- if (isObjectSpeculation(source.m_type)) {
- // This is the simple case. We already know that the source is an
- // object, so there's nothing to do. I don't think this case will
- // be hit, but then again, you never know.
- destination = source;
- node.setCanExit(false);
- m_foundConstants = true; // Tell the constant folder to turn this into Identity.
- break;
- }
-
- node.setCanExit(true);
-
- if (isOtherSpeculation(child.prediction())) {
- source.filter(SpecOther);
- destination.set(SpecObjectOther);
- break;
- }
-
- if (isObjectSpeculation(child.prediction())) {
- source.filter(SpecObjectMask);
- destination = source;
- break;
- }
+ AbstractValue& source = forNode(node->child1());
+ AbstractValue& destination = forNode(node);
destination = source;
destination.merge(SpecObjectOther);
@@ -1278,52 +1148,41 @@ bool AbstractState::execute(unsigned indexInBlock)
}
case CreateThis: {
- AbstractValue& source = forNode(node.child1());
- AbstractValue& destination = forNode(nodeIndex);
-
- node.setCanExit(!isCellSpeculation(source.m_type));
-
- source.filter(SpecFunction);
- destination.set(SpecFinalObject);
+ forNode(node).set(SpecFinalObject);
break;
}
- case InheritorIDWatchpoint:
- node.setCanExit(true);
+ case AllocationProfileWatchpoint:
+ node->setCanExit(true);
break;
case NewObject:
- node.setCanExit(false);
- forNode(nodeIndex).set(node.structure());
+ forNode(node).set(node->structure());
m_haveStructures = true;
break;
case CreateActivation:
- node.setCanExit(false);
- forNode(nodeIndex).set(m_codeBlock->globalObjectFor(node.codeOrigin)->activationStructure());
+ forNode(node).set(m_codeBlock->globalObjectFor(node->codeOrigin)->activationStructure());
m_haveStructures = true;
break;
case CreateArguments:
- node.setCanExit(false);
- forNode(nodeIndex).set(m_codeBlock->globalObjectFor(node.codeOrigin)->argumentsStructure());
+ forNode(node).set(m_codeBlock->globalObjectFor(node->codeOrigin)->argumentsStructure());
m_haveStructures = true;
break;
case TearOffActivation:
case TearOffArguments:
- node.setCanExit(false);
// Does nothing that is user-visible.
break;
case CheckArgumentsNotCreated:
if (isEmptySpeculation(
m_variables.operand(
- m_graph.argumentsRegisterFor(node.codeOrigin)).m_type)) {
- node.setCanExit(false);
+ m_graph.argumentsRegisterFor(node->codeOrigin)).m_type))
m_foundConstants = true;
- } else
- node.setCanExit(true);
+ else
+ node->setCanExit(true);
break;
case GetMyArgumentsLength:
@@ -1331,93 +1190,108 @@ bool AbstractState::execute(unsigned indexInBlock)
// the arguments a bit. Note that this is not sufficient to force constant folding
// of GetMyArgumentsLength, because GetMyArgumentsLength is a clobbering operation.
// We perform further optimizations on this later on.
- if (node.codeOrigin.inlineCallFrame)
- forNode(nodeIndex).set(jsNumber(node.codeOrigin.inlineCallFrame->arguments.size() - 1));
+ if (node->codeOrigin.inlineCallFrame)
+ forNode(node).set(jsNumber(node->codeOrigin.inlineCallFrame->arguments.size() - 1));
else
- forNode(nodeIndex).set(SpecInt32);
- node.setCanExit(
+ forNode(node).set(SpecInt32);
+ node->setCanExit(
!isEmptySpeculation(
m_variables.operand(
- m_graph.argumentsRegisterFor(node.codeOrigin)).m_type));
+ m_graph.argumentsRegisterFor(node->codeOrigin)).m_type));
break;
case GetMyArgumentsLengthSafe:
- node.setCanExit(false);
// This potentially clobbers all structures if the arguments object had a getter
// installed on the length property.
- clobberWorld(node.codeOrigin, indexInBlock);
+ clobberWorld(node->codeOrigin, indexInBlock);
// We currently make no guarantee about what this returns because it does not
// speculate that the length property is actually a length.
- forNode(nodeIndex).makeTop();
+ forNode(node).makeTop();
break;
case GetMyArgumentByVal:
- node.setCanExit(true);
+ node->setCanExit(true);
// We know that this executable does not escape its arguments, so we can optimize
// the arguments a bit. Note that this ends up being further optimized by the
// ArgumentsSimplificationPhase.
- forNode(node.child1()).filter(SpecInt32);
- forNode(nodeIndex).makeTop();
+ forNode(node).makeTop();
break;
case GetMyArgumentByValSafe:
- node.setCanExit(true);
+ node->setCanExit(true);
// This potentially clobbers all structures if the property we're accessing has
// a getter. We don't speculate against this.
- clobberWorld(node.codeOrigin, indexInBlock);
- // But we do speculate that the index is an integer.
- forNode(node.child1()).filter(SpecInt32);
+ clobberWorld(node->codeOrigin, indexInBlock);
// And the result is unknown.
- forNode(nodeIndex).makeTop();
+ forNode(node).makeTop();
break;
- case NewFunction:
+ case NewFunction: {
+ AbstractValue& value = forNode(node);
+ value = forNode(node->child1());
+
+ if (!(value.m_type & SpecEmpty)) {
+ m_foundConstants = true;
+ break;
+ }
+
+ value.set((value.m_type & ~SpecEmpty) | SpecFunction);
+ break;
+ }
+
case NewFunctionExpression:
case NewFunctionNoCheck:
- node.setCanExit(false);
- forNode(nodeIndex).set(m_codeBlock->globalObjectFor(node.codeOrigin)->functionStructure());
+ forNode(node).set(m_codeBlock->globalObjectFor(node->codeOrigin)->functionStructure());
break;
case GetCallee:
- node.setCanExit(false);
- forNode(nodeIndex).set(SpecFunction);
+ forNode(node).set(SpecFunction);
+ break;
+
+ case SetCallee:
+ case SetMyScope:
break;
- case GetScope:
- node.setCanExit(false);
- forNode(nodeIndex).set(SpecCellOther);
+ case GetScope: // FIXME: We could get rid of these if we know that the JSFunction is a constant. https://bugs.webkit.org/show_bug.cgi?id=106202
+ case GetMyScope:
+ case SkipTopScope:
+ forNode(node).set(SpecCellOther);
+ break;
+
+ case SkipScope: {
+ JSValue child = forNode(node->child1()).value();
+ if (child && trySetConstant(node, JSValue(jsCast<JSScope*>(child.asCell())->next()))) {
+ m_foundConstants = true;
+ break;
+ }
+ forNode(node).set(SpecCellOther);
break;
+ }
case GetScopeRegisters:
- node.setCanExit(false);
- forNode(node.child1()).filter(SpecCell);
- forNode(nodeIndex).clear(); // The result is not a JS value.
+ forNode(node).clear(); // The result is not a JS value.
break;
case GetScopedVar:
- node.setCanExit(false);
- forNode(nodeIndex).makeTop();
+ forNode(node).makeTop();
break;
case PutScopedVar:
- node.setCanExit(false);
- clobberCapturedVars(node.codeOrigin);
+ clobberCapturedVars(node->codeOrigin);
break;
case GetById:
case GetByIdFlush:
- node.setCanExit(true);
- if (!node.prediction()) {
+ node->setCanExit(true);
+ if (!node->prediction()) {
m_isValid = false;
break;
}
- if (isCellSpeculation(m_graph[node.child1()].prediction())) {
- forNode(node.child1()).filter(SpecCell);
-
- if (Structure* structure = forNode(node.child1()).bestProvenStructure()) {
+ if (isCellSpeculation(node->child1()->prediction())) {
+ if (Structure* structure = forNode(node->child1()).bestProvenStructure()) {
GetByIdStatus status = GetByIdStatus::computeFor(
- m_graph.m_globalData, structure,
- m_graph.m_codeBlock->identifier(node.identifierNumber()));
+ m_graph.m_vm, structure,
+ m_graph.m_codeBlock->identifier(node->identifierNumber()));
if (status.isSimple()) {
// Assert things that we can't handle and that the computeFor() method
// above won't be able to return.
@@ -1425,39 +1299,48 @@ bool AbstractState::execute(unsigned indexInBlock)
ASSERT(status.chain().isEmpty());
if (status.specificValue())
- forNode(nodeIndex).set(status.specificValue());
+ forNode(node).set(status.specificValue());
else
- forNode(nodeIndex).makeTop();
- forNode(node.child1()).filter(status.structureSet());
+ forNode(node).makeTop();
+ forNode(node->child1()).filter(status.structureSet());
m_foundConstants = true;
break;
}
}
}
- clobberWorld(node.codeOrigin, indexInBlock);
- forNode(nodeIndex).makeTop();
+ clobberWorld(node->codeOrigin, indexInBlock);
+ forNode(node).makeTop();
break;
case GetArrayLength:
- node.setCanExit(true); // Lies, but it's true for the common case of JSArray, so it's good enough.
- forNode(nodeIndex).set(SpecInt32);
+ node->setCanExit(true); // Lies, but it's true for the common case of JSArray, so it's good enough.
+ forNode(node).set(SpecInt32);
break;
+
+ case CheckExecutable: {
+ // FIXME: We could track executables in AbstractValue, which would allow us to get rid of these checks
+ // more thoroughly. https://bugs.webkit.org/show_bug.cgi?id=106200
+ // FIXME: We could eliminate these entirely if we know the exact value that flows into this.
+ // https://bugs.webkit.org/show_bug.cgi?id=106201
+ node->setCanExit(true);
+ break;
+ }
case CheckStructure:
case ForwardCheckStructure: {
// FIXME: We should be able to propagate the structure sets of constants (i.e. prototypes).
- AbstractValue& value = forNode(node.child1());
+ AbstractValue& value = forNode(node->child1());
+ ASSERT(!(value.m_type & ~SpecCell)); // Edge filtering should have already ensured this.
// If this structure check is attempting to prove knowledge already held in
// the futurePossibleStructure set then the constant folding phase should
// turn this into a watchpoint instead.
- StructureSet& set = node.structureSet();
+ StructureSet& set = node->structureSet();
if (value.m_futurePossibleStructure.isSubsetOf(set)
|| value.m_currentKnownStructure.isSubsetOf(set))
m_foundConstants = true;
- node.setCanExit(
- !value.m_currentKnownStructure.isSubsetOf(set)
- || !isCellSpeculation(value.m_type));
+ if (!value.m_currentKnownStructure.isSubsetOf(set))
+ node->setCanExit(true);
value.filter(set);
m_haveStructures = true;
break;
@@ -1465,7 +1348,7 @@ bool AbstractState::execute(unsigned indexInBlock)
case StructureTransitionWatchpoint:
case ForwardStructureTransitionWatchpoint: {
- AbstractValue& value = forNode(node.child1());
+ AbstractValue& value = forNode(node->child1());
// It's only valid to issue a structure transition watchpoint if we already
// know that the watchpoint covers a superset of the structures known to
@@ -1473,229 +1356,185 @@ bool AbstractState::execute(unsigned indexInBlock)
// Currently, we only issue singleton watchpoints (that check one structure)
// and our futurePossibleStructure set can only contain zero, one, or an
// infinity of structures.
- ASSERT(value.m_futurePossibleStructure.isSubsetOf(StructureSet(node.structure())));
+ ASSERT(value.m_futurePossibleStructure.isSubsetOf(StructureSet(node->structure())));
- ASSERT(value.isClear() || isCellSpeculation(value.m_type)); // Value could be clear if we've proven must-exit due to a speculation statically known to be bad.
- value.filter(node.structure());
+ value.filter(node->structure());
m_haveStructures = true;
- node.setCanExit(true);
+ node->setCanExit(true);
break;
}
case PutStructure:
case PhantomPutStructure:
- node.setCanExit(false);
- if (!forNode(node.child1()).m_currentKnownStructure.isClear()) {
+ if (!forNode(node->child1()).m_currentKnownStructure.isClear()) {
clobberStructures(indexInBlock);
- forNode(node.child1()).set(node.structureTransitionData().newStructure);
+ forNode(node->child1()).set(node->structureTransitionData().newStructure);
m_haveStructures = true;
}
break;
case GetButterfly:
case AllocatePropertyStorage:
case ReallocatePropertyStorage:
- node.setCanExit(!isCellSpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecCell);
- forNode(nodeIndex).clear(); // The result is not a JS value.
+ forNode(node).clear(); // The result is not a JS value.
break;
case CheckArray: {
- if (node.arrayMode().alreadyChecked(m_graph, node, forNode(node.child1()))) {
+ if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
m_foundConstants = true;
- node.setCanExit(false);
break;
}
- node.setCanExit(true); // Lies, but this is followed by operations (like GetByVal) that always exit, so there is no point in us trying to be clever here.
- switch (node.arrayMode().type()) {
+ node->setCanExit(true); // Lies, but this is followed by operations (like GetByVal) that always exit, so there is no point in us trying to be clever here.
+ switch (node->arrayMode().type()) {
case Array::String:
- forNode(node.child1()).filter(SpecString);
+ forNode(node->child1()).filter(SpecString);
break;
case Array::Int32:
case Array::Double:
case Array::Contiguous:
case Array::ArrayStorage:
case Array::SlowPutArrayStorage:
- forNode(node.child1()).filter(SpecCell);
break;
case Array::Arguments:
- forNode(node.child1()).filter(SpecArguments);
+ forNode(node->child1()).filter(SpecArguments);
break;
case Array::Int8Array:
- forNode(node.child1()).filter(SpecInt8Array);
+ forNode(node->child1()).filter(SpecInt8Array);
break;
case Array::Int16Array:
- forNode(node.child1()).filter(SpecInt16Array);
+ forNode(node->child1()).filter(SpecInt16Array);
break;
case Array::Int32Array:
- forNode(node.child1()).filter(SpecInt32Array);
+ forNode(node->child1()).filter(SpecInt32Array);
break;
case Array::Uint8Array:
- forNode(node.child1()).filter(SpecUint8Array);
+ forNode(node->child1()).filter(SpecUint8Array);
break;
case Array::Uint8ClampedArray:
- forNode(node.child1()).filter(SpecUint8ClampedArray);
+ forNode(node->child1()).filter(SpecUint8ClampedArray);
break;
case Array::Uint16Array:
- forNode(node.child1()).filter(SpecUint16Array);
+ forNode(node->child1()).filter(SpecUint16Array);
break;
case Array::Uint32Array:
- forNode(node.child1()).filter(SpecUint32Array);
+ forNode(node->child1()).filter(SpecUint32Array);
break;
case Array::Float32Array:
- forNode(node.child1()).filter(SpecFloat32Array);
+ forNode(node->child1()).filter(SpecFloat32Array);
break;
case Array::Float64Array:
- forNode(node.child1()).filter(SpecFloat64Array);
+ forNode(node->child1()).filter(SpecFloat64Array);
break;
default:
- ASSERT_NOT_REACHED();
+ RELEASE_ASSERT_NOT_REACHED();
break;
}
- forNode(node.child1()).filterArrayModes(node.arrayMode().arrayModesThatPassFiltering());
+ forNode(node->child1()).filterArrayModes(node->arrayMode().arrayModesThatPassFiltering());
m_haveStructures = true;
break;
}
case Arrayify: {
- if (node.arrayMode().alreadyChecked(m_graph, node, forNode(node.child1()))) {
+ if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
m_foundConstants = true;
- node.setCanExit(false);
break;
}
- ASSERT(node.arrayMode().conversion() == Array::Convert);
- node.setCanExit(true);
- forNode(node.child1()).filter(SpecCell);
- if (node.child2())
- forNode(node.child2()).filter(SpecInt32);
+ ASSERT(node->arrayMode().conversion() == Array::Convert
+ || node->arrayMode().conversion() == Array::RageConvert);
+ node->setCanExit(true);
clobberStructures(indexInBlock);
- forNode(node.child1()).filterArrayModes(node.arrayMode().arrayModesThatPassFiltering());
+ forNode(node->child1()).filterArrayModes(node->arrayMode().arrayModesThatPassFiltering());
m_haveStructures = true;
break;
}
case ArrayifyToStructure: {
- AbstractValue& value = forNode(node.child1());
- StructureSet set = node.structure();
+ AbstractValue& value = forNode(node->child1());
+ StructureSet set = node->structure();
if (value.m_futurePossibleStructure.isSubsetOf(set)
|| value.m_currentKnownStructure.isSubsetOf(set))
m_foundConstants = true;
- node.setCanExit(true);
+ node->setCanExit(true);
clobberStructures(indexInBlock);
value.filter(set);
m_haveStructures = true;
break;
}
case GetIndexedPropertyStorage: {
- switch (node.arrayMode().type()) {
- case Array::String:
- // Strings are weird - we may spec fail if the string was a rope. That is of course
- // stupid, and we should fix that, but for now let's at least be honest about it.
- node.setCanExit(true);
- break;
- default:
- node.setCanExit(false);
- break;
- }
- forNode(nodeIndex).clear();
+ forNode(node).clear();
break;
}
- case GetByOffset:
- if (!m_graph[node.child1()].hasStorageResult()) {
- node.setCanExit(!isCellSpeculation(forNode(node.child1()).m_type));
- forNode(node.child1()).filter(SpecCell);
- }
- forNode(nodeIndex).makeTop();
+ case GetByOffset: {
+ forNode(node).makeTop();
break;
+ }
case PutByOffset: {
- bool canExit = false;
- if (!m_graph[node.child1()].hasStorageResult()) {
- canExit |= !isCellSpeculation(forNode(node.child1()).m_type);
- forNode(node.child1()).filter(SpecCell);
- }
- canExit |= !isCellSpeculation(forNode(node.child2()).m_type);
- forNode(node.child2()).filter(SpecCell);
- node.setCanExit(canExit);
break;
}
case CheckFunction: {
- JSValue value = forNode(node.child1()).value();
- if (value == node.function()) {
+ JSValue value = forNode(node->child1()).value();
+ if (value == node->function()) {
m_foundConstants = true;
ASSERT(value);
- node.setCanExit(false);
break;
}
- node.setCanExit(true); // Lies! We can do better.
- if (!forNode(node.child1()).filterByValue(node.function())) {
- m_isValid = false;
- break;
- }
+ node->setCanExit(true); // Lies! We can do better.
+ forNode(node->child1()).filterByValue(node->function());
break;
}
case PutById:
case PutByIdDirect:
- node.setCanExit(true);
- if (Structure* structure = forNode(node.child1()).bestProvenStructure()) {
+ node->setCanExit(true);
+ if (Structure* structure = forNode(node->child1()).bestProvenStructure()) {
PutByIdStatus status = PutByIdStatus::computeFor(
- m_graph.m_globalData,
- m_graph.globalObjectFor(node.codeOrigin),
+ m_graph.m_vm,
+ m_graph.globalObjectFor(node->codeOrigin),
structure,
- m_graph.m_codeBlock->identifier(node.identifierNumber()),
- node.op() == PutByIdDirect);
+ m_graph.m_codeBlock->identifier(node->identifierNumber()),
+ node->op() == PutByIdDirect);
if (status.isSimpleReplace()) {
- forNode(node.child1()).filter(structure);
+ forNode(node->child1()).filter(structure);
m_foundConstants = true;
break;
}
if (status.isSimpleTransition()) {
clobberStructures(indexInBlock);
- forNode(node.child1()).set(status.newStructure());
+ forNode(node->child1()).set(status.newStructure());
m_haveStructures = true;
m_foundConstants = true;
break;
}
}
- forNode(node.child1()).filter(SpecCell);
- clobberWorld(node.codeOrigin, indexInBlock);
+ clobberWorld(node->codeOrigin, indexInBlock);
break;
case GetGlobalVar:
- node.setCanExit(false);
- forNode(nodeIndex).makeTop();
+ forNode(node).makeTop();
break;
case GlobalVarWatchpoint:
- node.setCanExit(true);
+ node->setCanExit(true);
break;
case PutGlobalVar:
case PutGlobalVarCheck:
- node.setCanExit(false);
break;
case CheckHasInstance:
- node.setCanExit(true);
- forNode(node.child1()).filter(SpecCell);
+ node->setCanExit(true);
// Sadly, we don't propagate the fact that we've done CheckHasInstance
break;
case InstanceOf:
- node.setCanExit(true);
+ node->setCanExit(true);
// Again, sadly, we don't propagate the fact that we've done InstanceOf
- if (!(m_graph[node.child1()].prediction() & ~SpecCell) && !(forNode(node.child1()).m_type & ~SpecCell))
- forNode(node.child1()).filter(SpecCell);
- forNode(node.child2()).filter(SpecCell);
- forNode(nodeIndex).set(SpecBoolean);
+ forNode(node).set(SpecBoolean);
break;
case Phi:
case Flush:
- node.setCanExit(false);
- break;
-
+ case PhantomLocal:
case Breakpoint:
- node.setCanExit(false);
break;
case Call:
@@ -1704,35 +1543,54 @@ bool AbstractState::execute(unsigned indexInBlock)
case ResolveBase:
case ResolveBaseStrictPut:
case ResolveGlobal:
- node.setCanExit(true);
- clobberWorld(node.codeOrigin, indexInBlock);
- forNode(nodeIndex).makeTop();
+ node->setCanExit(true);
+ clobberWorld(node->codeOrigin, indexInBlock);
+ forNode(node).makeTop();
break;
case GarbageValue:
- clobberWorld(node.codeOrigin, indexInBlock);
- forNode(nodeIndex).makeTop();
+ clobberWorld(node->codeOrigin, indexInBlock);
+ forNode(node).makeTop();
break;
case ForceOSRExit:
- node.setCanExit(true);
+ node->setCanExit(true);
m_isValid = false;
break;
+ case CheckWatchdogTimer:
+ node->setCanExit(true);
+ break;
+
case Phantom:
case InlineStart:
case Nop:
- node.setCanExit(false);
+ case CountExecution:
break;
case LastNodeType:
- ASSERT_NOT_REACHED();
+ RELEASE_ASSERT_NOT_REACHED();
break;
}
return m_isValid;
}
+bool AbstractState::executeEffects(unsigned indexInBlock)
+{
+ return executeEffects(indexInBlock, m_block->at(indexInBlock));
+}
+
+bool AbstractState::execute(unsigned indexInBlock)
+{
+ Node* node = m_block->at(indexInBlock);
+ if (!startExecuting(node))
+ return true;
+
+ executeEdges(node);
+ return executeEffects(indexInBlock, node);
+}
+
inline void AbstractState::clobberWorld(const CodeOrigin& codeOrigin, unsigned indexInBlock)
{
clobberCapturedVars(codeOrigin);
@@ -1775,22 +1633,19 @@ inline void AbstractState::clobberStructures(unsigned indexInBlock)
m_didClobber = true;
}
-inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, NodeIndex nodeIndex)
+inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, Node* node)
{
- if (nodeIndex == NoNode)
+ if (!node)
return false;
AbstractValue source;
-
- Node& node = m_graph[nodeIndex];
- if (!node.refCount())
- return false;
-
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLogF(" It's live, node @%u.\n", nodeIndex);
-#endif
- if (node.variableAccessData()->isCaptured()) {
+ if (node->variableAccessData()->isCaptured()) {
+ // If it's captured then we know that whatever value was stored into the variable last is the
+ // one we care about. This is true even if the variable at tail is dead, which might happen if
+ // the last thing we did to the variable was a GetLocal and then ended up now using the
+ // GetLocal's result.
+
source = inVariable;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLogF(" Transfering ");
@@ -1798,9 +1653,14 @@ inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
dataLogF(" from last access due to captured variable.\n");
#endif
} else {
- switch (node.op()) {
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ dataLogF(" It's live, node @%u.\n", node->index());
+#endif
+
+ switch (node->op()) {
case Phi:
case SetArgument:
+ case PhantomLocal:
case Flush:
// The block transfers the value from head to tail.
source = inVariable;
@@ -1813,7 +1673,7 @@ inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
case GetLocal:
// The block refines the value with additional speculations.
- source = forNode(nodeIndex);
+ source = forNode(node);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLogF(" Refining to ");
source.dump(WTF::dataFile());
@@ -1824,11 +1684,11 @@ inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
case SetLocal:
// The block sets the variable, and potentially refines it, both
// before and after setting it.
- if (node.variableAccessData()->shouldUseDoubleFormat()) {
+ if (node->variableAccessData()->shouldUseDoubleFormat()) {
// FIXME: This unnecessarily loses precision.
source.set(SpecDouble);
} else
- source = forNode(node.child1());
+ source = forNode(node->child1());
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLogF(" Setting to ");
source.dump(WTF::dataFile());
@@ -1837,7 +1697,7 @@ inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
break;
default:
- ASSERT_NOT_REACHED();
+ RELEASE_ASSERT_NOT_REACHED();
break;
}
}
@@ -1886,35 +1746,34 @@ inline bool AbstractState::merge(BasicBlock* from, BasicBlock* to)
return changed;
}
-inline bool AbstractState::mergeToSuccessors(
- Graph& graph, BasicBlock* basicBlock)
+inline bool AbstractState::mergeToSuccessors(Graph& graph, BasicBlock* basicBlock)
{
- Node& terminal = graph[basicBlock->last()];
+ Node* terminal = basicBlock->last();
- ASSERT(terminal.isTerminal());
+ ASSERT(terminal->isTerminal());
- switch (terminal.op()) {
+ switch (terminal->op()) {
case Jump: {
ASSERT(basicBlock->cfaBranchDirection == InvalidBranchDirection);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLogF(" Merging to block #%u.\n", terminal.takenBlockIndex());
+ dataLogF(" Merging to block #%u.\n", terminal->takenBlockIndex());
#endif
- return merge(basicBlock, graph.m_blocks[terminal.takenBlockIndex()].get());
+ return merge(basicBlock, graph.m_blocks[terminal->takenBlockIndex()].get());
}
case Branch: {
ASSERT(basicBlock->cfaBranchDirection != InvalidBranchDirection);
bool changed = false;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLogF(" Merging to block #%u.\n", terminal.takenBlockIndex());
+ dataLogF(" Merging to block #%u.\n", terminal->takenBlockIndex());
#endif
if (basicBlock->cfaBranchDirection != TakeFalse)
- changed |= merge(basicBlock, graph.m_blocks[terminal.takenBlockIndex()].get());
+ changed |= merge(basicBlock, graph.m_blocks[terminal->takenBlockIndex()].get());
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLogF(" Merging to block #%u.\n", terminal.notTakenBlockIndex());
+ dataLogF(" Merging to block #%u.\n", terminal->notTakenBlockIndex());
#endif
if (basicBlock->cfaBranchDirection != TakeTrue)
- changed |= merge(basicBlock, graph.m_blocks[terminal.notTakenBlockIndex()].get());
+ changed |= merge(basicBlock, graph.m_blocks[terminal->notTakenBlockIndex()].get());
return changed;
}
@@ -1925,17 +1784,17 @@ inline bool AbstractState::mergeToSuccessors(
return false;
default:
- ASSERT_NOT_REACHED();
+ RELEASE_ASSERT_NOT_REACHED();
return false;
}
}
-inline bool AbstractState::mergeVariableBetweenBlocks(AbstractValue& destination, AbstractValue& source, NodeIndex destinationNodeIndex, NodeIndex sourceNodeIndex)
+inline bool AbstractState::mergeVariableBetweenBlocks(AbstractValue& destination, AbstractValue& source, Node* destinationNode, Node* sourceNode)
{
- if (destinationNodeIndex == NoNode)
+ if (!destinationNode)
return false;
- ASSERT_UNUSED(sourceNodeIndex, sourceNodeIndex != NoNode);
+ ASSERT_UNUSED(sourceNode, sourceNode);
// FIXME: We could do some sparse conditional propagation here!
@@ -1946,15 +1805,15 @@ void AbstractState::dump(PrintStream& out)
{
bool first = true;
for (size_t i = 0; i < m_block->size(); ++i) {
- NodeIndex index = m_block->at(i);
- AbstractValue& value = m_nodes[index];
+ Node* node = m_block->at(i);
+ AbstractValue& value = forNode(node);
if (value.isClear())
continue;
if (first)
first = false;
else
out.printf(" ");
- out.printf("@%lu:", static_cast<unsigned long>(index));
+ out.printf("@%lu:", static_cast<unsigned long>(node->index()));
value.dump(out);
}
}