summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGAbstractState.cpp')
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractState.cpp1056
1 files changed, 1056 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
new file mode 100644
index 000000000..40ad857cf
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -0,0 +1,1056 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DFGAbstractState.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "CodeBlock.h"
+#include "DFGBasicBlock.h"
+
+namespace JSC { namespace DFG {
+
+#define CFA_PROFILING 0
+
+#if CFA_PROFILING
+#define PROFILE(flag) SamplingFlags::ScopedFlag scopedFlag(flag)
+#else
+#define PROFILE(flag) do { } while (false)
+#endif
+
+// Profiling flags
+#define FLAG_FOR_BLOCK_INITIALIZATION 17
+#define FLAG_FOR_BLOCK_END 18
+#define FLAG_FOR_EXECUTION 19
+#define FLAG_FOR_MERGE_TO_SUCCESSORS 20
+#define FLAG_FOR_STRUCTURE_CLOBBERING 21
+
+AbstractState::AbstractState(CodeBlock* codeBlock, Graph& graph)
+ : m_codeBlock(codeBlock)
+ , m_graph(graph)
+ , m_variables(codeBlock->m_numParameters, graph.m_localVars)
+ , m_block(0)
+{
+ size_t maxBlockSize = 0;
+ for (size_t i = 0; i < graph.m_blocks.size(); ++i) {
+ BasicBlock* block = graph.m_blocks[i].get();
+ if (block->end - block->begin > maxBlockSize)
+ maxBlockSize = block->end - block->begin;
+ }
+ m_nodes.resize(maxBlockSize);
+}
+
+AbstractState::~AbstractState() { }
+
+void AbstractState::beginBasicBlock(BasicBlock* basicBlock)
+{
+ PROFILE(FLAG_FOR_BLOCK_INITIALIZATION);
+
+ ASSERT(!m_block);
+
+ ASSERT(basicBlock->variablesAtHead.numberOfLocals() == basicBlock->valuesAtHead.numberOfLocals());
+ ASSERT(basicBlock->variablesAtTail.numberOfLocals() == basicBlock->valuesAtTail.numberOfLocals());
+ ASSERT(basicBlock->variablesAtHead.numberOfLocals() == basicBlock->variablesAtTail.numberOfLocals());
+
+ for (size_t i = 0; i < basicBlock->end - basicBlock->begin; ++i)
+ m_nodes[i].clear();
+ m_variables = basicBlock->valuesAtHead;
+ m_haveStructures = false;
+ for (size_t i = 0; i < m_variables.numberOfArguments(); ++i) {
+ if (m_variables.argument(i).m_structure.isNeitherClearNorTop()) {
+ m_haveStructures = true;
+ break;
+ }
+ }
+ for (size_t i = 0; i < m_variables.numberOfLocals(); ++i) {
+ if (m_variables.local(i).m_structure.isNeitherClearNorTop()) {
+ m_haveStructures = true;
+ break;
+ }
+ }
+
+ basicBlock->cfaShouldRevisit = false;
+ basicBlock->cfaHasVisited = true;
+ m_block = basicBlock;
+ m_isValid = true;
+}
+
+void AbstractState::initialize(Graph& graph)
+{
+ PROFILE(FLAG_FOR_BLOCK_INITIALIZATION);
+ BasicBlock* root = graph.m_blocks[0].get();
+ root->cfaShouldRevisit = true;
+ for (size_t i = 0; i < root->valuesAtHead.numberOfArguments(); ++i) {
+ PredictedType prediction = graph[root->variablesAtHead.argument(i)].variableAccessData()->prediction();
+ if (isInt32Prediction(prediction))
+ root->valuesAtHead.argument(i).set(PredictInt32);
+ else if (isArrayPrediction(prediction))
+ root->valuesAtHead.argument(i).set(PredictArray);
+ else if (isByteArrayPrediction(prediction))
+ root->valuesAtHead.argument(i).set(PredictByteArray);
+ else if (isBooleanPrediction(prediction))
+ root->valuesAtHead.argument(i).set(PredictBoolean);
+ else if (isInt8ArrayPrediction(prediction))
+ root->valuesAtHead.argument(i).set(PredictInt8Array);
+ else if (isInt16ArrayPrediction(prediction))
+ root->valuesAtHead.argument(i).set(PredictInt16Array);
+ else if (isInt32ArrayPrediction(prediction))
+ root->valuesAtHead.argument(i).set(PredictInt32Array);
+ else if (isUint8ArrayPrediction(prediction))
+ root->valuesAtHead.argument(i).set(PredictUint8Array);
+ else if (isUint16ArrayPrediction(prediction))
+ root->valuesAtHead.argument(i).set(PredictUint16Array);
+ else if (isUint32ArrayPrediction(prediction))
+ root->valuesAtHead.argument(i).set(PredictUint32Array);
+ else if (isFloat32ArrayPrediction(prediction))
+ root->valuesAtHead.argument(i).set(PredictFloat32Array);
+ else if (isFloat64ArrayPrediction(prediction))
+ root->valuesAtHead.argument(i).set(PredictFloat64Array);
+ else
+ root->valuesAtHead.argument(i).makeTop();
+ }
+}
+
+bool AbstractState::endBasicBlock(MergeMode mergeMode)
+{
+ PROFILE(FLAG_FOR_BLOCK_END);
+ ASSERT(m_block);
+
+ BasicBlock* block = m_block; // Save the block for successor merging.
+
+ if (!m_isValid) {
+ reset();
+ return false;
+ }
+
+ bool changed = false;
+
+ if (mergeMode != DontMerge || !ASSERT_DISABLED) {
+ for (size_t argument = 0; argument < block->variablesAtTail.numberOfArguments(); ++argument) {
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ printf(" Merging state for argument %lu.\n", argument);
+#endif
+ changed |= mergeStateAtTail(block->valuesAtTail.argument(argument), m_variables.argument(argument), block->variablesAtTail.argument(argument));
+ }
+
+ for (size_t local = 0; local < block->variablesAtTail.numberOfLocals(); ++local) {
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ printf(" Merging state for local %lu.\n", local);
+#endif
+ changed |= mergeStateAtTail(block->valuesAtTail.local(local), m_variables.local(local), block->variablesAtTail.local(local));
+ }
+ }
+
+ ASSERT(mergeMode != DontMerge || !changed);
+
+ reset();
+
+ if (mergeMode != MergeToSuccessors)
+ return changed;
+
+ return mergeToSuccessors(m_graph, block);
+}
+
+void AbstractState::reset()
+{
+ m_block = 0;
+ m_isValid = false;
+}
+
+bool AbstractState::execute(NodeIndex nodeIndex)
+{
+ PROFILE(FLAG_FOR_EXECUTION);
+ ASSERT(m_block);
+ ASSERT(m_isValid);
+
+ Node& node = m_graph[nodeIndex];
+
+ if (!node.shouldGenerate())
+ return true;
+
+ switch (node.op) {
+ case JSConstant:
+ case WeakJSConstant: {
+ JSValue value = m_graph.valueOfJSConstant(m_codeBlock, nodeIndex);
+ if (value.isCell())
+ m_haveStructures = true;
+ forNode(nodeIndex).set(value);
+ break;
+ }
+
+ case GetLocal: {
+ forNode(nodeIndex) = m_variables.operand(node.local());
+ break;
+ }
+
+ case SetLocal: {
+ if (node.variableAccessData()->shouldUseDoubleFormat()) {
+ forNode(node.child1()).filter(PredictNumber);
+ m_variables.operand(node.local()).set(PredictDouble);
+ break;
+ }
+
+ PredictedType predictedType = node.variableAccessData()->prediction();
+ if (isInt32Prediction(predictedType))
+ forNode(node.child1()).filter(PredictInt32);
+ else if (isArrayPrediction(predictedType))
+ forNode(node.child1()).filter(PredictArray);
+ else if (isByteArrayPrediction(predictedType))
+ forNode(node.child1()).filter(PredictByteArray);
+ else if (isBooleanPrediction(predictedType))
+ forNode(node.child1()).filter(PredictBoolean);
+
+ m_variables.operand(node.local()) = forNode(node.child1());
+ break;
+ }
+
+ case SetArgument:
+ // Assert that the state of arguments has been set.
+ ASSERT(!m_block->valuesAtHead.operand(node.local()).isClear());
+ break;
+
+ case BitAnd:
+ case BitOr:
+ case BitXor:
+ case BitRShift:
+ case BitLShift:
+ case BitURShift:
+ forNode(node.child1()).filter(PredictInt32);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+
+ case UInt32ToNumber:
+ if (!node.canSpeculateInteger())
+ forNode(nodeIndex).set(PredictDouble);
+ else
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+
+ case ValueToInt32:
+ if (!m_graph[node.child1()].shouldNotSpeculateInteger()) {
+ if (m_graph[node.child1()].shouldSpeculateDouble())
+ forNode(node.child1()).filter(PredictNumber);
+ else
+ forNode(node.child1()).filter(PredictInt32);
+ }
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+
+ case ValueToNumber:
+ if (m_graph[node.child1()].shouldNotSpeculateInteger()) {
+ forNode(node.child1()).filter(PredictNumber);
+ forNode(nodeIndex).set(PredictDouble);
+ break;
+ }
+
+ forNode(node.child1()).filter(PredictInt32);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+
+ case ValueToDouble:
+ forNode(node.child1()).filter(PredictNumber);
+ forNode(nodeIndex).set(PredictDouble);
+ break;
+
+ case ValueAdd:
+ case ArithAdd: {
+ if (Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child2()]) && node.canSpeculateInteger()) {
+ forNode(node.child1()).filter(PredictInt32);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+ }
+ if (Node::shouldSpeculateNumber(m_graph[node.child1()], m_graph[node.child2()])) {
+ forNode(node.child1()).filter(PredictNumber);
+ forNode(node.child2()).filter(PredictNumber);
+ forNode(nodeIndex).set(PredictDouble);
+ break;
+ }
+ ASSERT(node.op == ValueAdd);
+ clobberStructures(nodeIndex);
+ forNode(nodeIndex).set(PredictString | PredictInt32 | PredictNumber);
+ break;
+ }
+
+ case ArithSub:
+ case ArithMul:
+ case ArithDiv:
+ case ArithMin:
+ case ArithMax: {
+ if (Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child2()]) && node.canSpeculateInteger()) {
+ forNode(node.child1()).filter(PredictInt32);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+ }
+ forNode(node.child1()).filter(PredictNumber);
+ forNode(node.child2()).filter(PredictNumber);
+ forNode(nodeIndex).set(PredictDouble);
+ break;
+ }
+
+ case ArithMod: {
+ if (m_graph[node.child1()].shouldNotSpeculateInteger() || m_graph[node.child2()].shouldNotSpeculateInteger() || !node.canSpeculateInteger()) {
+ forNode(node.child1()).filter(PredictNumber);
+ forNode(node.child2()).filter(PredictNumber);
+ forNode(nodeIndex).set(PredictDouble);
+ break;
+ }
+ forNode(node.child1()).filter(PredictInt32);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+ }
+
+ case ArithAbs:
+ if (m_graph[node.child1()].shouldSpeculateInteger() && node.canSpeculateInteger()) {
+ forNode(node.child1()).filter(PredictInt32);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+ }
+ forNode(node.child1()).filter(PredictNumber);
+ forNode(nodeIndex).set(PredictDouble);
+ break;
+
+ case ArithSqrt:
+ forNode(node.child1()).filter(PredictNumber);
+ forNode(nodeIndex).set(PredictDouble);
+ break;
+
+ case LogicalNot: {
+ Node& child = m_graph[node.child1()];
+ if (isBooleanPrediction(child.prediction()) || !child.prediction())
+ forNode(node.child1()).filter(PredictBoolean);
+ else if (child.shouldSpeculateFinalObjectOrOther())
+ forNode(node.child1()).filter(PredictFinalObject | PredictOther);
+ else if (child.shouldSpeculateArrayOrOther())
+ forNode(node.child1()).filter(PredictArray | PredictOther);
+ else if (child.shouldSpeculateInteger())
+ forNode(node.child1()).filter(PredictInt32);
+ else if (child.shouldSpeculateNumber())
+ forNode(node.child1()).filter(PredictNumber);
+ else
+ clobberStructures(nodeIndex);
+ forNode(nodeIndex).set(PredictBoolean);
+ break;
+ }
+
+ case CompareLess:
+ case CompareLessEq:
+ case CompareGreater:
+ case CompareGreaterEq:
+ case CompareEq: {
+ Node& left = m_graph[node.child1()];
+ Node& right = m_graph[node.child2()];
+ PredictedType filter;
+ if (Node::shouldSpeculateInteger(left, right))
+ filter = PredictInt32;
+ else if (Node::shouldSpeculateNumber(left, right))
+ filter = PredictNumber;
+ else if (node.op == CompareEq && Node::shouldSpeculateFinalObject(left, right))
+ filter = PredictFinalObject;
+ else if (node.op == CompareEq && Node::shouldSpeculateArray(left, right))
+ filter = PredictArray;
+ else {
+ filter = PredictTop;
+ clobberStructures(nodeIndex);
+ }
+ forNode(node.child1()).filter(filter);
+ forNode(node.child2()).filter(filter);
+ forNode(nodeIndex).set(PredictBoolean);
+ break;
+ }
+
+ case CompareStrictEq:
+ forNode(nodeIndex).set(PredictBoolean);
+ break;
+
+ case StringCharCodeAt:
+ forNode(node.child1()).filter(PredictString);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+
+ case StringCharAt:
+ forNode(node.child1()).filter(PredictString);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(nodeIndex).set(PredictString);
+ break;
+
+ case GetByVal: {
+ if (!node.prediction() || !m_graph[node.child1()].prediction() || !m_graph[node.child2()].prediction()) {
+ m_isValid = false;
+ break;
+ }
+ if (!isActionableArrayPrediction(m_graph[node.child1()].prediction()) || !m_graph[node.child2()].shouldSpeculateInteger()) {
+ clobberStructures(nodeIndex);
+ forNode(nodeIndex).makeTop();
+ break;
+ }
+ if (m_graph[node.child1()].prediction() == PredictString) {
+ forNode(node.child1()).filter(PredictString);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(nodeIndex).set(PredictString);
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateByteArray()) {
+ forNode(node.child1()).filter(PredictByteArray);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+ }
+
+ if (m_graph[node.child1()].shouldSpeculateInt8Array()) {
+ forNode(node.child1()).filter(PredictInt8Array);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateInt16Array()) {
+ forNode(node.child1()).filter(PredictInt16Array);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateInt32Array()) {
+ forNode(node.child1()).filter(PredictInt32Array);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateUint8Array()) {
+ forNode(node.child1()).filter(PredictUint8Array);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateUint16Array()) {
+ forNode(node.child1()).filter(PredictUint16Array);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateUint32Array()) {
+ forNode(node.child1()).filter(PredictUint32Array);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(nodeIndex).set(PredictDouble);
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateFloat32Array()) {
+ forNode(node.child1()).filter(PredictFloat32Array);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(nodeIndex).set(PredictDouble);
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateFloat64Array()) {
+ forNode(node.child1()).filter(PredictFloat64Array);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(nodeIndex).set(PredictDouble);
+ break;
+ }
+ ASSERT(m_graph[node.child1()].shouldSpeculateArray());
+ forNode(node.child1()).filter(PredictArray);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(nodeIndex).makeTop();
+ break;
+ }
+
+ case PutByVal:
+ case PutByValAlias: {
+ if (!m_graph[node.child1()].prediction() || !m_graph[node.child2()].prediction()) {
+ m_isValid = false;
+ break;
+ }
+ if (!m_graph[node.child2()].shouldSpeculateInteger() || !isActionableMutableArrayPrediction(m_graph[node.child1()].prediction())) {
+ ASSERT(node.op == PutByVal);
+ clobberStructures(nodeIndex);
+ forNode(nodeIndex).makeTop();
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateByteArray()) {
+ forNode(node.child1()).filter(PredictByteArray);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(node.child3()).filter(PredictNumber);
+ break;
+ }
+
+ if (m_graph[node.child1()].shouldSpeculateInt8Array()) {
+ forNode(node.child1()).filter(PredictInt8Array);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(node.child3()).filter(PredictNumber);
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateInt16Array()) {
+ forNode(node.child1()).filter(PredictInt16Array);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(node.child3()).filter(PredictNumber);
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateInt32Array()) {
+ forNode(node.child1()).filter(PredictInt32Array);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(node.child3()).filter(PredictNumber);
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateUint8Array()) {
+ forNode(node.child1()).filter(PredictUint8Array);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(node.child3()).filter(PredictNumber);
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateUint16Array()) {
+ forNode(node.child1()).filter(PredictUint16Array);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(node.child3()).filter(PredictNumber);
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateUint32Array()) {
+ forNode(node.child1()).filter(PredictUint32Array);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(node.child3()).filter(PredictNumber);
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateFloat32Array()) {
+ forNode(node.child1()).filter(PredictFloat32Array);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(node.child3()).filter(PredictNumber);
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateFloat64Array()) {
+ forNode(node.child1()).filter(PredictFloat64Array);
+ forNode(node.child2()).filter(PredictInt32);
+ forNode(node.child3()).filter(PredictNumber);
+ break;
+ }
+ ASSERT(m_graph[node.child1()].shouldSpeculateArray());
+ forNode(node.child1()).filter(PredictArray);
+ forNode(node.child2()).filter(PredictInt32);
+ break;
+ }
+
+ case ArrayPush:
+ forNode(node.child1()).filter(PredictArray);
+ forNode(nodeIndex).set(PredictNumber);
+ break;
+
+ case ArrayPop:
+ forNode(node.child1()).filter(PredictArray);
+ forNode(nodeIndex).makeTop();
+ break;
+
+ case Jump:
+ break;
+
+ case Branch: {
+ // There is probably profit to be found in doing sparse conditional constant
+ // propagation, and to take it one step further, where a variable's value
+ // is specialized on each direction of a branch. For now, we don't do this.
+ Node& child = m_graph[node.child1()];
+ if (isBooleanPrediction(child.prediction()) || !child.prediction())
+ forNode(node.child1()).filter(PredictBoolean);
+ else if (child.shouldSpeculateFinalObjectOrOther())
+ forNode(node.child1()).filter(PredictFinalObject | PredictOther);
+ else if (child.shouldSpeculateArrayOrOther())
+ forNode(node.child1()).filter(PredictArray | PredictOther);
+ else if (child.shouldSpeculateInteger())
+ forNode(node.child1()).filter(PredictInt32);
+ else if (child.shouldSpeculateNumber())
+ forNode(node.child1()).filter(PredictNumber);
+ break;
+ }
+
+ case Return:
+ case Throw:
+ case ThrowReferenceError:
+ m_isValid = false;
+ break;
+
+ case ToPrimitive: {
+ Node& child = m_graph[node.child1()];
+ if (child.shouldSpeculateInteger()) {
+ forNode(node.child1()).filter(PredictInt32);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+ }
+
+ AbstractValue& source = forNode(node.child1());
+ AbstractValue& destination = forNode(nodeIndex);
+
+ PredictedType type = source.m_type;
+ if (type & ~(PredictNumber | PredictString | PredictBoolean)) {
+ type &= (PredictNumber | PredictString | PredictBoolean);
+ type |= PredictString;
+ }
+ destination.set(type);
+ break;
+ }
+
+ case StrCat:
+ forNode(nodeIndex).set(PredictString);
+ break;
+
+ case NewArray:
+ case NewArrayBuffer:
+ forNode(nodeIndex).set(m_codeBlock->globalObject()->arrayStructure());
+ m_haveStructures = true;
+ break;
+
+ case NewRegexp:
+ forNode(nodeIndex).set(m_codeBlock->globalObject()->regExpStructure());
+ m_haveStructures = true;
+ break;
+
+ case ConvertThis: {
+ Node& child = m_graph[node.child1()];
+ AbstractValue& source = forNode(node.child1());
+ AbstractValue& destination = forNode(nodeIndex);
+
+ if (isObjectPrediction(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;
+ break;
+ }
+
+ if (isOtherPrediction(child.prediction())) {
+ source.filter(PredictOther);
+ destination.set(PredictObjectOther);
+ break;
+ }
+
+ if (isObjectPrediction(child.prediction())) {
+ source.filter(PredictObjectMask);
+ destination = source;
+ break;
+ }
+
+ destination = source;
+ destination.merge(PredictObjectOther);
+ break;
+ }
+
+ case CreateThis: {
+ Node& child = m_graph[node.child1()];
+ AbstractValue& source = forNode(node.child1());
+ AbstractValue& destination = forNode(nodeIndex);
+
+ if (child.shouldSpeculateFinalObject())
+ source.filter(PredictFinalObject);
+
+ destination.set(PredictFinalObject);
+ break;
+ }
+
+ case NewObject:
+ forNode(nodeIndex).set(m_codeBlock->globalObject()->emptyObjectStructure());
+ m_haveStructures = true;
+ break;
+
+ case GetCallee:
+ forNode(nodeIndex).set(PredictFunction);
+ break;
+
+ case GetScopeChain:
+ forNode(nodeIndex).set(PredictCellOther);
+ break;
+
+ case GetScopedVar:
+ forNode(nodeIndex).makeTop();
+ break;
+
+ case PutScopedVar:
+ clobberStructures(nodeIndex);
+ break;
+
+ case GetById:
+ if (!node.prediction()) {
+ m_isValid = false;
+ break;
+ }
+ if (isCellPrediction(m_graph[node.child1()].prediction()))
+ forNode(node.child1()).filter(PredictCell);
+ clobberStructures(nodeIndex);
+ forNode(nodeIndex).makeTop();
+ break;
+
+ case GetArrayLength:
+ forNode(node.child1()).filter(PredictArray);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+
+ case GetStringLength:
+ forNode(node.child1()).filter(PredictString);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+
+ case GetByteArrayLength:
+ forNode(node.child1()).filter(PredictByteArray);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+ case GetInt8ArrayLength:
+ forNode(node.child1()).filter(PredictInt8Array);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+ case GetInt16ArrayLength:
+ forNode(node.child1()).filter(PredictInt16Array);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+ case GetInt32ArrayLength:
+ forNode(node.child1()).filter(PredictInt32Array);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+ case GetUint8ArrayLength:
+ forNode(node.child1()).filter(PredictUint8Array);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+ case GetUint16ArrayLength:
+ forNode(node.child1()).filter(PredictUint16Array);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+ case GetUint32ArrayLength:
+ forNode(node.child1()).filter(PredictUint32Array);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+ case GetFloat32ArrayLength:
+ forNode(node.child1()).filter(PredictFloat32Array);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+ case GetFloat64ArrayLength:
+ forNode(node.child1()).filter(PredictFloat64Array);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+
+ case CheckStructure:
+ // FIXME: We should be able to propagate the structure sets of constants (i.e. prototypes).
+ forNode(node.child1()).filter(node.structureSet());
+ m_haveStructures = true;
+ break;
+
+ case PutStructure:
+ clobberStructures(nodeIndex);
+ forNode(node.child1()).set(node.structureTransitionData().newStructure);
+ m_haveStructures = true;
+ break;
+ case GetPropertyStorage:
+ forNode(node.child1()).filter(PredictCell);
+ forNode(nodeIndex).clear(); // The result is not a JS value.
+ break;
+ case GetIndexedPropertyStorage: {
+ PredictedType basePrediction = m_graph[node.child2()].prediction();
+ if (!(basePrediction & PredictInt32) && basePrediction) {
+ forNode(nodeIndex).clear();
+ break;
+ }
+ if (m_graph[node.child1()].prediction() == PredictString) {
+ forNode(node.child1()).filter(PredictString);
+ forNode(nodeIndex).clear();
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateByteArray()) {
+ forNode(node.child1()).filter(PredictByteArray);
+ forNode(nodeIndex).clear();
+ break;
+ }
+
+ if (m_graph[node.child1()].shouldSpeculateInt8Array()) {
+ forNode(node.child1()).filter(PredictInt8Array);
+ forNode(nodeIndex).clear();
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateInt16Array()) {
+ forNode(node.child1()).filter(PredictInt16Array);
+ forNode(nodeIndex).clear();
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateInt32Array()) {
+ forNode(node.child1()).filter(PredictInt32Array);
+ forNode(nodeIndex).clear();
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateUint8Array()) {
+ forNode(node.child1()).filter(PredictUint8Array);
+ forNode(nodeIndex).clear();
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateUint16Array()) {
+ forNode(node.child1()).filter(PredictUint16Array);
+ forNode(nodeIndex).set(PredictOther);
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateUint32Array()) {
+ forNode(node.child1()).filter(PredictUint32Array);
+ forNode(nodeIndex).clear();
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateFloat32Array()) {
+ forNode(node.child1()).filter(PredictFloat32Array);
+ forNode(nodeIndex).clear();
+ break;
+ }
+ if (m_graph[node.child1()].shouldSpeculateFloat64Array()) {
+ forNode(node.child1()).filter(PredictFloat64Array);
+ forNode(nodeIndex).clear();
+ break;
+ }
+ forNode(node.child1()).filter(PredictArray);
+ forNode(nodeIndex).clear();
+ break;
+ }
+ case GetByOffset:
+ forNode(node.child1()).filter(PredictCell);
+ forNode(nodeIndex).makeTop();
+ break;
+
+ case PutByOffset:
+ forNode(node.child1()).filter(PredictCell);
+ break;
+
+ case CheckFunction:
+ forNode(node.child1()).filter(PredictFunction);
+ // FIXME: Should be able to propagate the fact that we know what the function is.
+ break;
+
+ case PutById:
+ case PutByIdDirect:
+ forNode(node.child1()).filter(PredictCell);
+ clobberStructures(nodeIndex);
+ break;
+
+ case GetGlobalVar:
+ forNode(nodeIndex).makeTop();
+ break;
+
+ case PutGlobalVar:
+ break;
+
+ case CheckHasInstance:
+ forNode(node.child1()).filter(PredictCell);
+ // Sadly, we don't propagate the fact that we've done CheckHasInstance
+ break;
+
+ case InstanceOf:
+ // Again, sadly, we don't propagate the fact that we've done InstanceOf
+ if (!(m_graph[node.child1()].prediction() & ~PredictCell) && !(forNode(node.child1()).m_type & ~PredictCell))
+ forNode(node.child1()).filter(PredictCell);
+ forNode(node.child3()).filter(PredictCell);
+ forNode(nodeIndex).set(PredictBoolean);
+ break;
+
+ case Phi:
+ case Flush:
+ break;
+
+ case Breakpoint:
+ break;
+
+ case Call:
+ case Construct:
+ case Resolve:
+ case ResolveBase:
+ case ResolveBaseStrictPut:
+ case ResolveGlobal:
+ clobberStructures(nodeIndex);
+ forNode(nodeIndex).makeTop();
+ break;
+
+ case ForceOSRExit:
+ m_isValid = false;
+ break;
+
+ case Phantom:
+ case InlineStart:
+ case Nop:
+ break;
+ }
+
+ return m_isValid;
+}
+
+inline void AbstractState::clobberStructures(NodeIndex nodeIndex)
+{
+ PROFILE(FLAG_FOR_STRUCTURE_CLOBBERING);
+ if (!m_haveStructures)
+ return;
+ for (size_t i = nodeIndex - m_block->begin + 1; i-- > 0;)
+ m_nodes[i].clobberStructures();
+ for (size_t i = 0; i < m_variables.numberOfArguments(); ++i)
+ m_variables.argument(i).clobberStructures();
+ for (size_t i = 0; i < m_variables.numberOfLocals(); ++i)
+ m_variables.local(i).clobberStructures();
+ m_haveStructures = false;
+}
+
+inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, NodeIndex nodeIndex)
+{
+ if (nodeIndex == NoNode)
+ return false;
+
+ AbstractValue* source;
+
+ Node& node = m_graph[nodeIndex];
+ if (!node.refCount())
+ return false;
+
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ printf(" It's live, node @%u.\n", nodeIndex);
+#endif
+
+ switch (node.op) {
+ case Phi:
+ case SetArgument:
+ case Flush:
+ // The block transfers the value from head to tail.
+ source = &inVariable;
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ printf(" Transfering from head to tail.\n");
+#endif
+ break;
+
+ case GetLocal:
+ // The block refines the value with additional speculations.
+ source = &forNode(nodeIndex);
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ printf(" Refining.\n");
+#endif
+ break;
+
+ case SetLocal:
+ // The block sets the variable, and potentially refines it, both
+ // before and after setting it.
+ source = &forNode(node.child1());
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ printf(" Setting.\n");
+#endif
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ source = 0;
+ break;
+ }
+
+ if (destination == *source) {
+ // Abstract execution did not change the output value of the variable, for this
+ // basic block, on this iteration.
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ printf(" Not changed!\n");
+#endif
+ return false;
+ }
+
+ // Abstract execution reached a new conclusion about the speculations reached about
+ // this variable after execution of this basic block. Update the state, and return
+ // true to indicate that the fixpoint must go on!
+ destination = *source;
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ printf(" Changed!\n");
+#endif
+ return true;
+}
+
+inline bool AbstractState::merge(BasicBlock* from, BasicBlock* to)
+{
+ ASSERT(from->variablesAtTail.numberOfArguments() == to->variablesAtHead.numberOfArguments());
+ ASSERT(from->variablesAtTail.numberOfLocals() == to->variablesAtHead.numberOfLocals());
+
+ bool changed = false;
+
+ for (size_t argument = 0; argument < from->variablesAtTail.numberOfArguments(); ++argument)
+ changed |= mergeVariableBetweenBlocks(to->valuesAtHead.argument(argument), from->valuesAtTail.argument(argument), to->variablesAtHead.argument(argument), from->variablesAtTail.argument(argument));
+
+ for (size_t local = 0; local < from->variablesAtTail.numberOfLocals(); ++local)
+ changed |= mergeVariableBetweenBlocks(to->valuesAtHead.local(local), from->valuesAtTail.local(local), to->variablesAtHead.local(local), from->variablesAtTail.local(local));
+
+ if (!to->cfaHasVisited)
+ changed = true;
+
+ to->cfaShouldRevisit |= changed;
+
+ return changed;
+}
+
+inline bool AbstractState::mergeToSuccessors(Graph& graph, BasicBlock* basicBlock)
+{
+ PROFILE(FLAG_FOR_MERGE_TO_SUCCESSORS);
+
+ Node& terminal = graph[basicBlock->end - 1];
+
+ ASSERT(terminal.isTerminal());
+
+ switch (terminal.op) {
+ case Jump:
+ return merge(basicBlock, graph.m_blocks[terminal.takenBlockIndex()].get());
+
+ case Branch:
+ return merge(basicBlock, graph.m_blocks[terminal.takenBlockIndex()].get())
+ | merge(basicBlock, graph.m_blocks[terminal.notTakenBlockIndex()].get());
+
+ case Return:
+ case Throw:
+ case ThrowReferenceError:
+ return false;
+
+ default:
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+}
+
+inline bool AbstractState::mergeVariableBetweenBlocks(AbstractValue& destination, AbstractValue& source, NodeIndex destinationNodeIndex, NodeIndex sourceNodeIndex)
+{
+ if (destinationNodeIndex == NoNode)
+ return false;
+
+ ASSERT_UNUSED(sourceNodeIndex, sourceNodeIndex != NoNode);
+
+ // FIXME: We could do some sparse conditional propagation here!
+
+ return destination.merge(source);
+}
+
+#ifndef NDEBUG
+void AbstractState::dump(FILE* out)
+{
+ bool first = true;
+ for (size_t i = 0; i < m_nodes.size(); ++i) {
+ if (m_nodes[i].isClear())
+ continue;
+ if (first)
+ first = false;
+ else
+ fprintf(out, " ");
+ fprintf(out, "@%lu:", static_cast<unsigned long>(i + m_block->begin));
+ m_nodes[i].dump(out);
+ }
+}
+#endif
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+