]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - dfg/DFGAbstractState.cpp
JavaScriptCore-1218.35.tar.gz
[apple/javascriptcore.git] / dfg / DFGAbstractState.cpp
index 6df40ca6f44c31ec9754da236f911ca47bb19634..78ebb4aa800680c756ffa64917619b92c593e2b5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 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
 
 #include "CodeBlock.h"
 #include "DFGBasicBlock.h"
+#include "GetByIdStatus.h"
+#include "Operations.h"
+#include "PutByIdStatus.h"
+#include "StringObject.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(Graph& graph)
     : m_codeBlock(graph.m_codeBlock)
     , m_graph(graph)
     , m_variables(m_codeBlock->numParameters(), graph.m_localVars)
     , m_block(0)
 {
-    m_nodes.resize(graph.size());
 }
 
 AbstractState::~AbstractState() { }
 
 void AbstractState::beginBasicBlock(BasicBlock* basicBlock)
 {
-    PROFILE(FLAG_FOR_BLOCK_INITIALIZATION);
-    
     ASSERT(!m_block);
     
     ASSERT(basicBlock->variablesAtHead.numberOfLocals() == basicBlock->valuesAtHead.numberOfLocals());
@@ -70,18 +56,18 @@ void AbstractState::beginBasicBlock(BasicBlock* basicBlock)
     ASSERT(basicBlock->variablesAtHead.numberOfLocals() == basicBlock->variablesAtTail.numberOfLocals());
     
     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;
     for (size_t i = 0; i < m_variables.numberOfArguments(); ++i) {
-        if (m_variables.argument(i).m_structure.isNeitherClearNorTop()) {
+        if (m_variables.argument(i).m_currentKnownStructure.isNeitherClearNorTop()) {
             m_haveStructures = true;
             break;
         }
     }
     for (size_t i = 0; i < m_variables.numberOfLocals(); ++i) {
-        if (m_variables.local(i).m_structure.isNeitherClearNorTop()) {
+        if (m_variables.local(i).m_currentKnownStructure.isNeitherClearNorTop()) {
             m_haveStructures = true;
             break;
         }
@@ -91,70 +77,90 @@ void AbstractState::beginBasicBlock(BasicBlock* basicBlock)
     basicBlock->cfaHasVisited = true;
     m_block = basicBlock;
     m_isValid = true;
+    m_foundConstants = false;
+    m_branchDirection = InvalidBranchDirection;
 }
 
 void AbstractState::initialize(Graph& graph)
 {
-    PROFILE(FLAG_FOR_BLOCK_INITIALIZATION);
     BasicBlock* root = graph.m_blocks[0].get();
     root->cfaShouldRevisit = true;
+    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 (graph.argumentIsCaptured(i)) {
+        Node* node = root->variablesAtHead.argument(i);
+        ASSERT(node->op() == SetArgument);
+        if (!node->variableAccessData()->shouldUnboxIfPossible()) {
             root->valuesAtHead.argument(i).makeTop();
             continue;
         }
         
-        PredictedType prediction = node.variableAccessData()->prediction();
-        if (isInt32Prediction(prediction))
-            root->valuesAtHead.argument(i).set(PredictInt32);
-        else if (isArrayPrediction(prediction))
-            root->valuesAtHead.argument(i).set(PredictArray);
-        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 (isUint8ClampedArrayPrediction(prediction))
-            root->valuesAtHead.argument(i).set(PredictUint8ClampedArray);
-        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);
+        SpeculatedType prediction = node->variableAccessData()->prediction();
+        if (isInt32Speculation(prediction))
+            root->valuesAtHead.argument(i).set(SpecInt32);
+        else if (isBooleanSpeculation(prediction))
+            root->valuesAtHead.argument(i).set(SpecBoolean);
+        else if (isCellSpeculation(prediction))
+            root->valuesAtHead.argument(i).set(SpecCell);
         else
             root->valuesAtHead.argument(i).makeTop();
+        
+        root->valuesAtTail.argument(i).clear();
     }
     for (size_t i = 0; i < root->valuesAtHead.numberOfLocals(); ++i) {
-        if (!graph.localIsCaptured(i))
+        Node* node = root->variablesAtHead.local(i);
+        if (node && node->variableAccessData()->isCaptured())
+            root->valuesAtHead.local(i).makeTop();
+        else
+            root->valuesAtHead.local(i).clear();
+        root->valuesAtTail.local(i).clear();
+    }
+    for (BlockIndex blockIndex = 1 ; blockIndex < graph.m_blocks.size(); ++blockIndex) {
+        BasicBlock* block = graph.m_blocks[blockIndex].get();
+        if (!block)
+            continue;
+        if (!block->isReachable)
+            continue;
+        block->cfaShouldRevisit = false;
+        block->cfaHasVisited = false;
+        block->cfaFoundConstants = false;
+        for (size_t i = 0; i < block->valuesAtHead.numberOfArguments(); ++i) {
+            block->valuesAtHead.argument(i).clear();
+            block->valuesAtTail.argument(i).clear();
+        }
+        for (size_t i = 0; i < block->valuesAtHead.numberOfLocals(); ++i) {
+            block->valuesAtHead.local(i).clear();
+            block->valuesAtTail.local(i).clear();
+        }
+        if (!block->isOSRTarget)
+            continue;
+        if (block->bytecodeBegin != graph.m_osrEntryBytecodeIndex)
             continue;
-        root->valuesAtHead.local(i).makeTop();
+        for (size_t i = 0; i < graph.m_mustHandleValues.size(); ++i) {
+            AbstractValue value;
+            value.setMostSpecific(graph.m_mustHandleValues[i]);
+            int operand = graph.m_mustHandleValues.operandForIndex(i);
+            block->valuesAtHead.operand(operand).merge(value);
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+            dataLogF("    Initializing Block #%u, operand r%d, to ", blockIndex, operand);
+            block->valuesAtHead.operand(operand).dump(WTF::dataFile());
+            dataLogF("\n");
+#endif
+        }
+        block->cfaShouldRevisit = true;
     }
 }
 
 bool AbstractState::endBasicBlock(MergeMode mergeMode)
 {
-    PROFILE(FLAG_FOR_BLOCK_END);
     ASSERT(m_block);
     
     BasicBlock* block = m_block; // Save the block for successor merging.
     
+    block->cfaFoundConstants = m_foundConstants;
+    block->cfaDidFinish = m_isValid;
+    block->cfaBranchDirection = m_branchDirection;
+    
     if (!m_isValid) {
         reset();
         return false;
@@ -165,35 +171,27 @@ bool AbstractState::endBasicBlock(MergeMode mergeMode)
     if (mergeMode != DontMerge || !ASSERT_DISABLED) {
         for (size_t argument = 0; argument < block->variablesAtTail.numberOfArguments(); ++argument) {
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-            dataLog("        Merging state for argument %zu.\n", argument);
+            dataLogF("        Merging state for argument %zu.\n", argument);
 #endif
             AbstractValue& destination = block->valuesAtTail.argument(argument);
-            if (m_graph.argumentIsCaptured(argument)) {
-                if (!destination.isTop()) {
-                    destination.makeTop();
-                    changed = true;
-                }
-            } else
-                changed |= mergeStateAtTail(destination, m_variables.argument(argument), block->variablesAtTail.argument(argument));
+            changed |= mergeStateAtTail(destination, m_variables.argument(argument), block->variablesAtTail.argument(argument));
         }
         
         for (size_t local = 0; local < block->variablesAtTail.numberOfLocals(); ++local) {
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-            dataLog("        Merging state for local %zu.\n", local);
+            dataLogF("        Merging state for local %zu.\n", local);
 #endif
             AbstractValue& destination = block->valuesAtTail.local(local);
-            if (m_graph.localIsCaptured(local)) {
-                if (!destination.isTop()) {
-                    destination.makeTop();
-                    changed = true;
-                }
-            } else
-                changed |= mergeStateAtTail(destination, m_variables.local(local), block->variablesAtTail.local(local));
+            changed |= mergeStateAtTail(destination, m_variables.local(local), block->variablesAtTail.local(local));
         }
     }
     
     ASSERT(mergeMode != DontMerge || !changed);
     
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+    dataLogF("        Branch direction = %s\n", branchDirectionToString(m_branchDirection));
+#endif
+    
     reset();
     
     if (mergeMode != MergeToSuccessors)
@@ -206,66 +204,133 @@ void AbstractState::reset()
 {
     m_block = 0;
     m_isValid = false;
+    m_branchDirection = InvalidBranchDirection;
 }
 
-bool AbstractState::execute(unsigned indexInBlock)
+AbstractState::BooleanResult AbstractState::booleanResult(Node* node, AbstractValue& value)
+{
+    JSValue childConst = value.value();
+    if (childConst) {
+        if (childConst.toBoolean(m_codeBlock->globalObjectFor(node->codeOrigin)->globalExec()))
+            return DefinitelyTrue;
+        return DefinitelyFalse;
+    }
+
+    // Next check if we can fold because we know that the source is an object or string and does not equal undefined.
+    if (isCellSpeculation(value.m_type)
+        && value.m_currentKnownStructure.hasSingleton()) {
+        Structure* structure = value.m_currentKnownStructure.singleton();
+        if (!structure->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->codeOrigin))
+            && structure->typeInfo().type() != StringType)
+            return DefinitelyTrue;
+    }
+    
+    return UnknownBooleanResult;
+}
+
+bool AbstractState::startExecuting(Node* node)
 {
-    PROFILE(FLAG_FOR_EXECUTION);
     ASSERT(m_block);
     ASSERT(m_isValid);
-        
-    NodeIndex nodeIndex = m_block->at(indexInBlock);
-    Node& node = m_graph[nodeIndex];
-        
-    if (!node.shouldGenerate())
-        return true;
-        
-    switch (node.op()) {
+    
+    m_didClobber = false;
+    
+    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: {
-        JSValue value = m_graph.valueOfJSConstant(nodeIndex);
-        // Have to be careful here! It's tempting to call set(value), but
-        // that would be wrong, since that would constitute a proof that this
-        // value will always have the same structure. The whole point of a value
-        // having a structure is that it may change in the future - for example
-        // between when we compile the code and when we run it.
-        forNode(nodeIndex).set(predictionFromValue(value));
+    case WeakJSConstant:
+    case PhantomArguments: {
+        forNode(node).set(m_graph.valueOfJSConstant(node));
+        break;
+    }
+        
+    case Identity: {
+        forNode(node) = forNode(node->child1());
         break;
     }
             
     case GetLocal: {
-        if (m_graph.isCaptured(node.local()))
-            forNode(nodeIndex).makeTop();
-        else
-            forNode(nodeIndex) = m_variables.operand(node.local());
+        VariableAccessData* variableAccessData = node->variableAccessData();
+        if (variableAccessData->prediction() == SpecNone) {
+            m_isValid = false;
+            break;
+        }
+        AbstractValue value = m_variables.operand(variableAccessData->local());
+        if (!variableAccessData->isCaptured()) {
+            if (value.isClear())
+                node->setCanExit(true);
+        }
+        if (value.value())
+            m_foundConstants = true;
+        forNode(node) = value;
         break;
     }
         
-    case SetLocal: {
-        if (m_graph.isCaptured(node.local()))
-            break;
+    case GetLocalUnlinked: {
+        AbstractValue value = m_variables.operand(node->unlinkedLocal());
+        if (value.value())
+            m_foundConstants = true;
+        forNode(node) = value;
+        break;
+    }
         
-        if (node.variableAccessData()->shouldUseDoubleFormat()) {
-            forNode(node.child1()).filter(PredictNumber);
-            m_variables.operand(node.local()).set(PredictDouble);
-            break;
-        }
+    case SetLocal: {
+        m_variables.operand(node->local()) = forNode(node->child1());
+        break;
+    }
         
-        PredictedType predictedType = node.variableAccessData()->argumentAwarePrediction();
-        if (isInt32Prediction(predictedType))
-            forNode(node.child1()).filter(PredictInt32);
-        else if (isArrayPrediction(predictedType))
-            forNode(node.child1()).filter(PredictArray);
-        else if (isBooleanPrediction(predictedType))
-            forNode(node.child1()).filter(PredictBoolean);
+    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());
+        ASSERT(!m_block->valuesAtHead.operand(node->local()).isClear());
         break;
             
     case BitAnd:
@@ -273,139 +338,341 @@ bool AbstractState::execute(unsigned indexInBlock)
     case BitXor:
     case BitRShift:
     case BitLShift:
-    case BitURShift:
-        forNode(node.child1()).filter(PredictInt32);
-        forNode(node.child2()).filter(PredictInt32);
-        forNode(nodeIndex).set(PredictInt32);
+    case BitURShift: {
+        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()) {
+            case BitAnd:
+                constantWasSet = trySetConstant(node, JSValue(a & b));
+                break;
+            case BitOr:
+                constantWasSet = trySetConstant(node, JSValue(a | b));
+                break;
+            case BitXor:
+                constantWasSet = trySetConstant(node, JSValue(a ^ b));
+                break;
+            case BitRShift:
+                constantWasSet = trySetConstant(node, JSValue(a >> static_cast<uint32_t>(b)));
+                break;
+            case BitLShift:
+                constantWasSet = trySetConstant(node, JSValue(a << static_cast<uint32_t>(b)));
+                break;
+            case BitURShift:
+                constantWasSet = trySetConstant(node, JSValue(static_cast<uint32_t>(a) >> static_cast<uint32_t>(b)));
+                break;
+            default:
+                RELEASE_ASSERT_NOT_REACHED();
+                constantWasSet = false;
+            }
+            if (constantWasSet) {
+                m_foundConstants = true;
+                break;
+            }
+        }
+        forNode(node).set(SpecInt32);
         break;
+    }
         
-    case UInt32ToNumber:
-        if (!node.canSpeculateInteger())
-            forNode(nodeIndex).set(PredictDouble);
-        else
-            forNode(nodeIndex).set(PredictInt32);
+    case UInt32ToNumber: {
+        JSValue child = forNode(node->child1()).value();
+        if (child && child.isNumber()) {
+            ASSERT(child.isInt32());
+            if (trySetConstant(node, JSValue(child.asUInt32()))) {
+                m_foundConstants = true;
+                break;
+            }
+        }
+        if (!node->canSpeculateInteger())
+            forNode(node).set(SpecDouble);
+        else {
+            forNode(node).set(SpecInt32);
+            node->setCanExit(true);
+        }
         break;
+    }
             
-    case DoubleAsInt32:
-        forNode(node.child1()).filter(PredictNumber);
-        forNode(nodeIndex).set(PredictInt32);
+    case DoubleAsInt32: {
+        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(node, JSValue(asInt))) {
+                m_foundConstants = true;
+                break;
+            }
+        }
+        node->setCanExit(true);
+        forNode(node).set(SpecInt32);
         break;
+    }
             
-    case ValueToInt32:
-        if (m_graph[node.child1()].shouldSpeculateInteger())
-            forNode(node.child1()).filter(PredictInt32);
-        else if (m_graph[node.child1()].shouldSpeculateNumber())
-            forNode(node.child1()).filter(PredictNumber);
-        else if (m_graph[node.child1()].shouldSpeculateBoolean())
-            forNode(node.child1()).filter(PredictBoolean);
+    case ValueToInt32: {
+        JSValue child = forNode(node->child1()).value();
+        if (child && child.isNumber()) {
+            bool constantWasSet;
+            if (child.isInt32())
+                constantWasSet = trySetConstant(node, child);
+            else
+                constantWasSet = trySetConstant(node, JSValue(JSC::toInt32(child.asDouble())));
+            if (constantWasSet) {
+                m_foundConstants = true;
+                break;
+            }
+        }
         
-        forNode(nodeIndex).set(PredictInt32);
+        forNode(node).set(SpecInt32);
         break;
-        
+    }
+
     case Int32ToDouble:
-        forNode(node.child1()).filter(PredictNumber);
-        forNode(nodeIndex).set(PredictDouble);
+    case ForwardInt32ToDouble: {
+        JSValue child = forNode(node->child1()).value();
+        if (child && child.isNumber()
+            && trySetConstant(node, JSValue(JSValue::EncodeAsDouble, child.asNumber()))) {
+            m_foundConstants = true;
+            break;
+        }
+        if (isInt32Speculation(forNode(node->child1()).m_type))
+            forNode(node).set(SpecDoubleReal);
+        else
+            forNode(node).set(SpecDouble);
         break;
+    }
         
-    case CheckNumber:
-        forNode(node.child1()).filter(PredictNumber);
-        break;
-            
     case ValueAdd:
     case ArithAdd: {
-        if (m_graph.addShouldSpeculateInteger(node)) {
-            forNode(node.child1()).filter(PredictInt32);
-            forNode(node.child2()).filter(PredictInt32);
-            forNode(nodeIndex).set(PredictInt32);
+        JSValue left = forNode(node->child1()).value();
+        JSValue right = forNode(node->child2()).value();
+        if (left && right && left.isNumber() && right.isNumber()
+            && trySetConstant(node, JSValue(left.asNumber() + right.asNumber()))) {
+            m_foundConstants = true;
             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);
+        switch (node->binaryUseKind()) {
+        case Int32Use:
+            forNode(node).set(SpecInt32);
+            if (!nodeCanTruncateInteger(node->arithNodeFlags()))
+                node->setCanExit(true);
             break;
-        }
-        if (node.op() == ValueAdd) {
-            clobberStructures(indexInBlock);
-            forNode(nodeIndex).set(PredictString | PredictInt32 | PredictNumber);
+        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(node->op() == ValueAdd);
+            clobberWorld(node->codeOrigin, indexInBlock);
+            forNode(node).set(SpecString | SpecInt32 | SpecNumber);
             break;
         }
-        // We don't handle this yet. :-(
-        m_isValid = false;
+        break;
+    }
+        
+    case MakeRope: {
+        node->setCanExit(true);
+        forNode(node).set(m_graph.m_vm.stringStructure.get());
         break;
     }
             
     case ArithSub: {
-        if (m_graph.addShouldSpeculateInteger(node)) {
-            forNode(node.child1()).filter(PredictInt32);
-            forNode(node.child2()).filter(PredictInt32);
-            forNode(nodeIndex).set(PredictInt32);
+        JSValue left = forNode(node->child1()).value();
+        JSValue right = forNode(node->child2()).value();
+        if (left && right && left.isNumber() && right.isNumber()
+            && trySetConstant(node, JSValue(left.asNumber() - right.asNumber()))) {
+            m_foundConstants = true;
+            break;
+        }
+        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;
         }
-        forNode(node.child1()).filter(PredictNumber);
-        forNode(node.child2()).filter(PredictNumber);
-        forNode(nodeIndex).set(PredictDouble);
         break;
     }
         
     case ArithNegate: {
-        if (m_graph.negateShouldSpeculateInteger(node)) {
-            forNode(node.child1()).filter(PredictInt32);
-            forNode(nodeIndex).set(PredictInt32);
+        JSValue child = forNode(node->child1()).value();
+        if (child && child.isNumber()
+            && trySetConstant(node, JSValue(-child.asNumber()))) {
+            m_foundConstants = true;
+            break;
+        }
+        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;
+        }
+        break;
+    }
+        
+    case ArithMul: {
+        JSValue left = forNode(node->child1()).value();
+        JSValue right = forNode(node->child2()).value();
+        if (left && right && left.isNumber() && right.isNumber()
+            && trySetConstant(node, JSValue(left.asNumber() * right.asNumber()))) {
+            m_foundConstants = true;
+            break;
+        }
+        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;
         }
-        forNode(node.child1()).filter(PredictNumber);
-        forNode(nodeIndex).set(PredictDouble);
+        break;
+    }
+
+    case ArithIMul: {
+        forNode(node).set(SpecInt32);
         break;
     }
         
-    case ArithMul:
     case ArithDiv:
     case ArithMin:
     case ArithMax:
     case ArithMod: {
-        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);
+        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()) {
+            case ArithDiv:
+                constantWasSet = trySetConstant(node, JSValue(a / b));
+                break;
+            case ArithMin:
+                constantWasSet = trySetConstant(node, JSValue(a < b ? a : (b <= a ? b : a + b)));
+                break;
+            case ArithMax:
+                constantWasSet = trySetConstant(node, JSValue(a > b ? a : (b >= a ? b : a + b)));
+                break;
+            case ArithMod:
+                constantWasSet = trySetConstant(node, JSValue(fmod(a, b)));
+                break;
+            default:
+                RELEASE_ASSERT_NOT_REACHED();
+                constantWasSet = false;
+                break;
+            }
+            if (constantWasSet) {
+                m_foundConstants = true;
+                break;
+            }
+        }
+        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;
         }
-        forNode(node.child1()).filter(PredictNumber);
-        forNode(node.child2()).filter(PredictNumber);
-        forNode(nodeIndex).set(PredictDouble);
         break;
     }
             
-    case ArithAbs:
-        if (m_graph[node.child1()].shouldSpeculateInteger() && node.canSpeculateInteger()) {
-            forNode(node.child1()).filter(PredictInt32);
-            forNode(nodeIndex).set(PredictInt32);
+    case ArithAbs: {
+        JSValue child = forNode(node->child1()).value();
+        if (child && child.isNumber()
+            && trySetConstant(node, JSValue(fabs(child.asNumber())))) {
+            m_foundConstants = true;
+            break;
+        }
+        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;
         }
-        forNode(node.child1()).filter(PredictNumber);
-        forNode(nodeIndex).set(PredictDouble);
         break;
+    }
             
-    case ArithSqrt:
-        forNode(node.child1()).filter(PredictNumber);
-        forNode(nodeIndex).set(PredictDouble);
+    case ArithSqrt: {
+        JSValue child = forNode(node->child1()).value();
+        if (child && child.isNumber()
+            && trySetConstant(node, JSValue(sqrt(child.asNumber())))) {
+            m_foundConstants = true;
+            break;
+        }
+        forNode(node).set(SpecDouble);
         break;
+    }
             
     case LogicalNot: {
-        Node& child = m_graph[node.child1()];
-        if (isBooleanPrediction(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(indexInBlock);
-        forNode(nodeIndex).set(PredictBoolean);
+        bool didSetConstant = false;
+        switch (booleanResult(node, forNode(node->child1()))) {
+        case DefinitelyTrue:
+            didSetConstant = trySetConstant(node, jsBoolean(false));
+            break;
+        case DefinitelyFalse:
+            didSetConstant = trySetConstant(node, jsBoolean(true));
+            break;
+        default:
+            break;
+        }
+        if (didSetConstant) {
+            m_foundConstants = true;
+            break;
+        }
+        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;
     }
         
@@ -415,7 +682,106 @@ bool AbstractState::execute(unsigned indexInBlock)
     case IsString:
     case IsObject:
     case IsFunction: {
-        forNode(nodeIndex).set(PredictBoolean);
+        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()) {
+            case IsUndefined:
+                if (m_codeBlock->globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
+                    constantWasSet = trySetConstant(node, jsBoolean(
+                        child.isCell()
+                        ? false 
+                        : child.isUndefined()));
+                } else {
+                    constantWasSet = trySetConstant(node, jsBoolean(
+                        child.isCell()
+                        ? child.asCell()->structure()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->codeOrigin))
+                        : child.isUndefined()));
+                }
+                break;
+            case IsBoolean:
+                constantWasSet = trySetConstant(node, jsBoolean(child.isBoolean()));
+                break;
+            case IsNumber:
+                constantWasSet = trySetConstant(node, jsBoolean(child.isNumber()));
+                break;
+            case IsString:
+                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;
+            }
+            if (constantWasSet) {
+                m_foundConstants = true;
+                break;
+            }
+        }
+
+        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;
     }
             
@@ -423,585 +789,751 @@ bool AbstractState::execute(unsigned indexInBlock)
     case CompareLessEq:
     case CompareGreater:
     case CompareGreaterEq:
-    case CompareEq: {
-        forNode(nodeIndex).set(PredictBoolean);
-        
-        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) {
-            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 know that this won't clobber the world. But that's all we know.
+    case CompareEq:
+    case CompareEqConstant: {
+        bool constantWasSet = false;
+
+        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()) {
+            case CompareLess:
+                constantWasSet = trySetConstant(node, jsBoolean(a < b));
                 break;
-            }
-            
-            if (Node::shouldSpeculateFinalObject(left, right))
-                filter = PredictFinalObject;
-            else if (Node::shouldSpeculateArray(left, right))
-                filter = PredictArray;
-            else if (left.shouldSpeculateFinalObject() && right.shouldSpeculateFinalObjectOrOther()) {
-                forNode(node.child1()).filter(PredictFinalObject);
-                forNode(node.child2()).filter(PredictFinalObject | PredictOther);
+            case CompareLessEq:
+                constantWasSet = trySetConstant(node, jsBoolean(a <= b));
                 break;
-            } else if (right.shouldSpeculateFinalObject() && left.shouldSpeculateFinalObjectOrOther()) {
-                forNode(node.child1()).filter(PredictFinalObject | PredictOther);
-                forNode(node.child2()).filter(PredictFinalObject);
+            case CompareGreater:
+                constantWasSet = trySetConstant(node, jsBoolean(a > b));
                 break;
-            } else if (left.shouldSpeculateArray() && right.shouldSpeculateArrayOrOther()) {
-                forNode(node.child1()).filter(PredictFinalObject);
-                forNode(node.child2()).filter(PredictFinalObject | PredictOther);
+            case CompareGreaterEq:
+                constantWasSet = trySetConstant(node, jsBoolean(a >= b));
                 break;
-            } else if (right.shouldSpeculateArray() && left.shouldSpeculateArrayOrOther()) {
-                forNode(node.child1()).filter(PredictFinalObject | PredictOther);
-                forNode(node.child2()).filter(PredictFinalObject);
+            case CompareEq:
+                constantWasSet = trySetConstant(node, jsBoolean(a == b));
+                break;
+            default:
+                RELEASE_ASSERT_NOT_REACHED();
+                constantWasSet = false;
                 break;
-            } else {
-                filter = PredictTop;
-                clobberStructures(indexInBlock);
             }
-        } else {
-            filter = PredictTop;
-            clobberStructures(indexInBlock);
         }
-        forNode(node.child1()).filter(filter);
-        forNode(node.child2()).filter(filter);
+        
+        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(node, jsBoolean(false));
+        }
+        
+        if (constantWasSet) {
+            m_foundConstants = true;
+            break;
+        }
+        
+        forNode(node).set(SpecBoolean);
+        
+        // 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:
-        forNode(nodeIndex).set(PredictBoolean);
+    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(node, jsBoolean(left.asNumber() == right.asNumber()))) {
+            m_foundConstants = true;
+            break;
+        }
+        forNode(node).set(SpecBoolean);
+        node->setCanExit(true); // This is overly conservative.
         break;
+    }
         
     case StringCharCodeAt:
-        forNode(node.child1()).filter(PredictString);
-        forNode(node.child2()).filter(PredictInt32);
-        forNode(nodeIndex).set(PredictInt32);
+        node->setCanExit(true);
+        forNode(node).set(SpecInt32);
         break;
         
+    case StringFromCharCode:
+        forNode(node).set(SpecString);
+        break;
+
     case StringCharAt:
-        forNode(node.child1()).filter(PredictString);
-        forNode(node.child2()).filter(PredictInt32);
-        forNode(nodeIndex).set(PredictString);
+        node->setCanExit(true);
+        forNode(node).set(m_graph.m_vm.stringStructure.get());
         break;
             
     case GetByVal: {
-        if (!node.prediction() || !m_graph[node.child1()].prediction() || !m_graph[node.child2()].prediction()) {
+        node->setCanExit(true);
+        switch (node->arrayMode().type()) {
+        case Array::SelectUsingPredictions:
+        case Array::Unprofiled:
+        case Array::Undecided:
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+        case Array::ForceExit:
             m_isValid = false;
             break;
-        }
-        if (!isActionableArrayPrediction(m_graph[node.child1()].prediction()) || !m_graph[node.child2()].shouldSpeculateInteger()) {
-            clobberStructures(indexInBlock);
-            forNode(nodeIndex).makeTop();
+        case Array::Generic:
+            clobberWorld(node->codeOrigin, indexInBlock);
+            forNode(node).makeTop();
             break;
-        }
-        if (m_graph[node.child1()].prediction() == PredictString) {
-            forNode(node.child1()).filter(PredictString);
-            forNode(node.child2()).filter(PredictInt32);
-            forNode(nodeIndex).set(PredictString);
+        case Array::String:
+            forNode(node).set(m_graph.m_vm.stringStructure.get());
             break;
-        }
-        
-        if (m_graph[node.child1()].shouldSpeculateInt8Array()) {
-            forNode(node.child1()).filter(PredictInt8Array);
-            forNode(node.child2()).filter(PredictInt32);
-            forNode(nodeIndex).set(PredictInt32);
+        case Array::Arguments:
+            forNode(node).makeTop();
             break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateInt16Array()) {
-            forNode(node.child1()).filter(PredictInt16Array);
-            forNode(node.child2()).filter(PredictInt32);
-            forNode(nodeIndex).set(PredictInt32);
+        case Array::Int32:
+            if (node->arrayMode().isOutOfBounds()) {
+                clobberWorld(node->codeOrigin, indexInBlock);
+                forNode(node).makeTop();
+            } else
+                forNode(node).set(SpecInt32);
             break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateInt32Array()) {
-            forNode(node.child1()).filter(PredictInt32Array);
-            forNode(node.child2()).filter(PredictInt32);
-            forNode(nodeIndex).set(PredictInt32);
+        case Array::Double:
+            if (node->arrayMode().isOutOfBounds()) {
+                clobberWorld(node->codeOrigin, indexInBlock);
+                forNode(node).makeTop();
+            } else if (node->arrayMode().isSaneChain())
+                forNode(node).set(SpecDouble);
+            else
+                forNode(node).set(SpecDoubleReal);
             break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateUint8Array()) {
-            forNode(node.child1()).filter(PredictUint8Array);
-            forNode(node.child2()).filter(PredictInt32);
-            forNode(nodeIndex).set(PredictInt32);
+        case Array::Contiguous:
+        case Array::ArrayStorage:
+        case Array::SlowPutArrayStorage:
+            if (node->arrayMode().isOutOfBounds())
+                clobberWorld(node->codeOrigin, indexInBlock);
+            forNode(node).makeTop();
             break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateUint8ClampedArray()) {
-            forNode(node.child1()).filter(PredictUint8ClampedArray);
-            forNode(node.child2()).filter(PredictInt32);
-            forNode(nodeIndex).set(PredictInt32);
+        case Array::Int8Array:
+            forNode(node).set(SpecInt32);
             break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateUint16Array()) {
-            forNode(node.child1()).filter(PredictUint16Array);
-            forNode(node.child2()).filter(PredictInt32);
-            forNode(nodeIndex).set(PredictInt32);
+        case Array::Int16Array:
+            forNode(node).set(SpecInt32);
             break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateUint32Array()) {
-            forNode(node.child1()).filter(PredictUint32Array);
-            forNode(node.child2()).filter(PredictInt32);
-            if (node.shouldSpeculateInteger())
-                forNode(nodeIndex).set(PredictInt32);
+        case Array::Int32Array:
+            forNode(node).set(SpecInt32);
+            break;
+        case Array::Uint8Array:
+            forNode(node).set(SpecInt32);
+            break;
+        case Array::Uint8ClampedArray:
+            forNode(node).set(SpecInt32);
+            break;
+        case Array::Uint16Array:
+            forNode(node).set(SpecInt32);
+            break;
+        case Array::Uint32Array:
+            if (node->shouldSpeculateInteger())
+                forNode(node).set(SpecInt32);
             else
-                forNode(nodeIndex).set(PredictDouble);
+                forNode(node).set(SpecDouble);
             break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateFloat32Array()) {
-            forNode(node.child1()).filter(PredictFloat32Array);
-            forNode(node.child2()).filter(PredictInt32);
-            forNode(nodeIndex).set(PredictDouble);
+        case Array::Float32Array:
+            forNode(node).set(SpecDouble);
             break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateFloat64Array()) {
-            forNode(node.child1()).filter(PredictFloat64Array);
-            forNode(node.child2()).filter(PredictInt32);
-            forNode(nodeIndex).set(PredictDouble);
+        case Array::Float64Array:
+            forNode(node).set(SpecDouble);
+            break;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
             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()) {
+        node->setCanExit(true);
+        switch (node->arrayMode().modeForPut().type()) {
+        case Array::ForceExit:
             m_isValid = false;
             break;
-        }
-        if (!m_graph[node.child2()].shouldSpeculateInteger() || !isActionableMutableArrayPrediction(m_graph[node.child1()].prediction())) {
-            ASSERT(node.op() == PutByVal);
-            clobberStructures(indexInBlock);
-            forNode(nodeIndex).makeTop();
-            break;
-        }
-        
-        if (m_graph[node.child1()].shouldSpeculateInt8Array()) {
-            forNode(node.child1()).filter(PredictInt8Array);
-            forNode(node.child2()).filter(PredictInt32);
-            if (m_graph[node.child3()].shouldSpeculateInteger())
-                forNode(node.child3()).filter(PredictInt32);
-            else
-                forNode(node.child3()).filter(PredictNumber);
-            break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateInt16Array()) {
-            forNode(node.child1()).filter(PredictInt16Array);
-            forNode(node.child2()).filter(PredictInt32);
-            if (m_graph[node.child3()].shouldSpeculateInteger())
-                forNode(node.child3()).filter(PredictInt32);
-            else
-                forNode(node.child3()).filter(PredictNumber);
-            break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateInt32Array()) {
-            forNode(node.child1()).filter(PredictInt32Array);
-            forNode(node.child2()).filter(PredictInt32);
-            if (m_graph[node.child3()].shouldSpeculateInteger())
-                forNode(node.child3()).filter(PredictInt32);
-            else
-                forNode(node.child3()).filter(PredictNumber);
-            break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateUint8Array()) {
-            forNode(node.child1()).filter(PredictUint8Array);
-            forNode(node.child2()).filter(PredictInt32);
-            if (m_graph[node.child3()].shouldSpeculateInteger())
-                forNode(node.child3()).filter(PredictInt32);
-            else
-                forNode(node.child3()).filter(PredictNumber);
+        case Array::Generic:
+            clobberWorld(node->codeOrigin, indexInBlock);
             break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateUint8ClampedArray()) {
-            forNode(node.child1()).filter(PredictUint8ClampedArray);
-            forNode(node.child2()).filter(PredictInt32);
-            if (m_graph[node.child3()].shouldSpeculateInteger())
-                forNode(node.child3()).filter(PredictInt32);
-            else
-                forNode(node.child3()).filter(PredictNumber);
+        case Array::Int32:
+            if (node->arrayMode().isOutOfBounds())
+                clobberWorld(node->codeOrigin, indexInBlock);
             break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateUint16Array()) {
-            forNode(node.child1()).filter(PredictUint16Array);
-            forNode(node.child2()).filter(PredictInt32);
-            if (m_graph[node.child3()].shouldSpeculateInteger())
-                forNode(node.child3()).filter(PredictInt32);
-            else
-                forNode(node.child3()).filter(PredictNumber);
+        case Array::Double:
+            if (node->arrayMode().isOutOfBounds())
+                clobberWorld(node->codeOrigin, indexInBlock);
             break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateUint32Array()) {
-            forNode(node.child1()).filter(PredictUint32Array);
-            forNode(node.child2()).filter(PredictInt32);
-            if (m_graph[node.child3()].shouldSpeculateInteger())
-                forNode(node.child3()).filter(PredictInt32);
-            else
-                forNode(node.child3()).filter(PredictNumber);
+        case Array::Contiguous:
+        case Array::ArrayStorage:
+            if (node->arrayMode().isOutOfBounds())
+                clobberWorld(node->codeOrigin, indexInBlock);
             break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateFloat32Array()) {
-            forNode(node.child1()).filter(PredictFloat32Array);
-            forNode(node.child2()).filter(PredictInt32);
-            forNode(node.child3()).filter(PredictNumber);
+        case Array::SlowPutArrayStorage:
+            if (node->arrayMode().mayStoreToHole())
+                clobberWorld(node->codeOrigin, indexInBlock);
             break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateFloat64Array()) {
-            forNode(node.child1()).filter(PredictFloat64Array);
-            forNode(node.child2()).filter(PredictInt32);
-            forNode(node.child3()).filter(PredictNumber);
+        default:
             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);
+        node->setCanExit(true);
+        clobberWorld(node->codeOrigin, indexInBlock);
+        forNode(node).set(SpecNumber);
         break;
             
     case ArrayPop:
-        forNode(node.child1()).filter(PredictArray);
-        forNode(nodeIndex).makeTop();
+        node->setCanExit(true);
+        clobberWorld(node->codeOrigin, indexInBlock);
+        forNode(node).makeTop();
         break;
             
     case RegExpExec:
+        forNode(node).makeTop();
+        break;
+
     case RegExpTest:
-        forNode(node.child1()).filter(PredictCell);
-        forNode(node.child2()).filter(PredictCell);
-        forNode(nodeIndex).makeTop();
+        forNode(node).set(SpecBoolean);
         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 (child.shouldSpeculateBoolean())
-            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);
+        Node* child = node->child1().node();
+        BooleanResult result = booleanResult(node, forNode(child));
+        if (result == DefinitelyTrue) {
+            m_branchDirection = TakeTrue;
+            break;
+        }
+        if (result == DefinitelyFalse) {
+            m_branchDirection = TakeFalse;
+            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->setCanExit(true); // This is overly conservative.
+        m_branchDirection = TakeBoth;
         break;
     }
             
     case Return:
+        m_isValid = false;
+        break;
+        
     case Throw:
     case ThrowReferenceError:
         m_isValid = false;
+        node->setCanExit(true);
         break;
             
     case ToPrimitive: {
-        Node& child = m_graph[node.child1()];
-        if (child.shouldSpeculateInteger()) {
-            forNode(node.child1()).filter(PredictInt32);
-            forNode(nodeIndex).set(PredictInt32);
+        JSValue childConst = forNode(node->child1()).value();
+        if (childConst && childConst.isNumber() && trySetConstant(node, childConst)) {
+            m_foundConstants = true;
             break;
         }
+        
+        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 = (SpecTop & ~SpecCell) | SpecString;
 
-        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);
+        
+    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(node).set(m_graph.globalObjectFor(node->codeOrigin)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
+        m_haveStructures = true;
+        break;
+        
     case NewArrayBuffer:
-        forNode(nodeIndex).set(m_codeBlock->globalObject()->arrayStructure());
+        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).set(SpecArray);
         m_haveStructures = true;
         break;
             
     case NewRegexp:
-        forNode(nodeIndex).set(m_codeBlock->globalObject()->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 (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;
-        }
+        AbstractValue& source = forNode(node->child1());
+        AbstractValue& destination = forNode(node);
             
         destination = source;
-        destination.merge(PredictObjectOther);
+        destination.merge(SpecObjectOther);
         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);
+        forNode(node).set(SpecFinalObject);
         break;
     }
-            
+        
+    case AllocationProfileWatchpoint:
+        node->setCanExit(true);
+        break;
+
     case NewObject:
-        forNode(nodeIndex).set(m_codeBlock->globalObjectFor(node.codeOrigin)->emptyObjectStructure());
+        forNode(node).set(node->structure());
         m_haveStructures = true;
         break;
         
     case CreateActivation:
-        forNode(nodeIndex).set(m_graph.m_globalData.activationStructure.get());
+        forNode(node).set(m_codeBlock->globalObjectFor(node->codeOrigin)->activationStructure());
+        m_haveStructures = true;
+        break;
+        
+    case CreateArguments:
+        forNode(node).set(m_codeBlock->globalObjectFor(node->codeOrigin)->argumentsStructure());
         m_haveStructures = true;
         break;
         
     case TearOffActivation:
+    case TearOffArguments:
         // Does nothing that is user-visible.
         break;
+
+    case CheckArgumentsNotCreated:
+        if (isEmptySpeculation(
+                m_variables.operand(
+                    m_graph.argumentsRegisterFor(node->codeOrigin)).m_type))
+            m_foundConstants = true;
+        else
+            node->setCanExit(true);
+        break;
+        
+    case GetMyArgumentsLength:
+        // We know that this executable does not escape its arguments, so we can optimize
+        // 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(node).set(jsNumber(node->codeOrigin.inlineCallFrame->arguments.size() - 1));
+        else
+            forNode(node).set(SpecInt32);
+        node->setCanExit(
+            !isEmptySpeculation(
+                m_variables.operand(
+                    m_graph.argumentsRegisterFor(node->codeOrigin)).m_type));
+        break;
+        
+    case GetMyArgumentsLengthSafe:
+        // This potentially clobbers all structures if the arguments object had a getter
+        // installed on the length property.
+        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(node).makeTop();
+        break;
+        
+    case GetMyArgumentByVal:
+        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).makeTop();
+        break;
+        
+    case GetMyArgumentByValSafe:
+        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);
+        // And the result is unknown.
+        forNode(node).makeTop();
+        break;
+        
+    case NewFunction: {
+        AbstractValue& value = forNode(node);
+        value = forNode(node->child1());
         
-    case NewFunction:
+        if (!(value.m_type & SpecEmpty)) {
+            m_foundConstants = true;
+            break;
+        }
+
+        value.set((value.m_type & ~SpecEmpty) | SpecFunction);
+        break;
+    }
+
     case NewFunctionExpression:
     case NewFunctionNoCheck:
-        forNode(nodeIndex).set(m_codeBlock->globalObjectFor(node.codeOrigin)->functionStructure());
+        forNode(node).set(m_codeBlock->globalObjectFor(node->codeOrigin)->functionStructure());
         break;
         
     case GetCallee:
-        forNode(nodeIndex).set(PredictFunction);
+        forNode(node).set(SpecFunction);
         break;
-            
-    case GetScopeChain:
-        forNode(nodeIndex).set(PredictCellOther);
+        
+    case SetCallee:
+    case SetMyScope:
         break;
             
+    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(SpecObjectOther);
+        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(SpecObjectOther);
+        break;
+    }
+
+    case GetScopeRegisters:
+        forNode(node).clear(); // The result is not a JS value.
+        break;
+
     case GetScopedVar:
-        forNode(nodeIndex).makeTop();
+        forNode(node).makeTop();
         break;
             
     case PutScopedVar:
-        clobberStructures(indexInBlock);
+        clobberCapturedVars(node->codeOrigin);
         break;
             
     case GetById:
     case GetByIdFlush:
-        if (!node.prediction()) {
+        node->setCanExit(true);
+        if (!node->prediction()) {
             m_isValid = false;
             break;
         }
-        if (isCellPrediction(m_graph[node.child1()].prediction()))
-            forNode(node.child1()).filter(PredictCell);
-        clobberStructures(indexInBlock);
-        forNode(nodeIndex).makeTop();
+        if (isCellSpeculation(node->child1()->prediction())) {
+            if (Structure* structure = forNode(node->child1()).bestProvenStructure()) {
+                GetByIdStatus status = GetByIdStatus::computeFor(
+                    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.
+                    ASSERT(status.structureSet().size() == 1);
+                    ASSERT(status.chain().isEmpty());
+                    
+                    if (status.specificValue())
+                        forNode(node).set(status.specificValue());
+                    else
+                        forNode(node).makeTop();
+                    forNode(node->child1()).filter(status.structureSet());
+                    
+                    m_foundConstants = true;
+                    break;
+                }
+            }
+        }
+        clobberWorld(node->codeOrigin, indexInBlock);
+        forNode(node).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);
+        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 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);
+    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 GetUint8ArrayLength:
-        forNode(node.child1()).filter(PredictUint8Array);
-        forNode(nodeIndex).set(PredictInt32);
-        break;
-    case GetUint8ClampedArrayLength:
-        forNode(node.child1()).filter(PredictUint8ClampedArray);
-        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:
+    case ForwardCheckStructure: {
         // FIXME: We should be able to propagate the structure sets of constants (i.e. prototypes).
-        forNode(node.child1()).filter(node.structureSet());
+        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();
+        if (value.m_futurePossibleStructure.isSubsetOf(set)
+            || value.m_currentKnownStructure.isSubsetOf(set))
+            m_foundConstants = true;
+        if (!value.m_currentKnownStructure.isSubsetOf(set))
+            node->setCanExit(true);
+        value.filter(set);
+        m_haveStructures = true;
+        break;
+    }
+        
+    case StructureTransitionWatchpoint:
+    case ForwardStructureTransitionWatchpoint: {
+        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
+        // belong to the set of future structures that this value may have.
+        // 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())));
+        
+        value.filter(node->structure());
         m_haveStructures = true;
+        node->setCanExit(true);
         break;
+    }
             
     case PutStructure:
-        clobberStructures(indexInBlock);
-        forNode(node.child1()).set(node.structureTransitionData().newStructure);
-        m_haveStructures = true;
+    case PhantomPutStructure:
+        if (!forNode(node->child1()).m_currentKnownStructure.isClear()) {
+            clobberStructures(indexInBlock);
+            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.
+    case GetButterfly:
+    case AllocatePropertyStorage:
+    case ReallocatePropertyStorage:
+        forNode(node).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();
+    case CheckArray: {
+        if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
+            m_foundConstants = true;
             break;
         }
-        if (m_graph[node.child1()].prediction() == PredictString) {
-            forNode(node.child1()).filter(PredictString);
-            forNode(nodeIndex).clear();
+        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);
             break;
-        }
-        
-        if (m_graph[node.child1()].shouldSpeculateInt8Array()) {
-            forNode(node.child1()).filter(PredictInt8Array);
-            forNode(nodeIndex).clear();
+        case Array::Int32:
+        case Array::Double:
+        case Array::Contiguous:
+        case Array::ArrayStorage:
+        case Array::SlowPutArrayStorage:
             break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateInt16Array()) {
-            forNode(node.child1()).filter(PredictInt16Array);
-            forNode(nodeIndex).clear();
+        case Array::Arguments:
+            forNode(node->child1()).filter(SpecArguments);
             break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateInt32Array()) {
-            forNode(node.child1()).filter(PredictInt32Array);
-            forNode(nodeIndex).clear();
+        case Array::Int8Array:
+            forNode(node->child1()).filter(SpecInt8Array);
             break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateUint8Array()) {
-            forNode(node.child1()).filter(PredictUint8Array);
-            forNode(nodeIndex).clear();
+        case Array::Int16Array:
+            forNode(node->child1()).filter(SpecInt16Array);
             break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateUint8ClampedArray()) {
-            forNode(node.child1()).filter(PredictUint8ClampedArray);
-            forNode(nodeIndex).clear();
+        case Array::Int32Array:
+            forNode(node->child1()).filter(SpecInt32Array);
             break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateUint16Array()) {
-            forNode(node.child1()).filter(PredictUint16Array);
-            forNode(nodeIndex).set(PredictOther);
+        case Array::Uint8Array:
+            forNode(node->child1()).filter(SpecUint8Array);
             break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateUint32Array()) {
-            forNode(node.child1()).filter(PredictUint32Array);
-            forNode(nodeIndex).clear();
+        case Array::Uint8ClampedArray:
+            forNode(node->child1()).filter(SpecUint8ClampedArray);
             break;
-        }
-        if (m_graph[node.child1()].shouldSpeculateFloat32Array()) {
-            forNode(node.child1()).filter(PredictFloat32Array);
-            forNode(nodeIndex).clear();
+        case Array::Uint16Array:
+            forNode(node->child1()).filter(SpecUint16Array);
+            break;
+        case Array::Uint32Array:
+            forNode(node->child1()).filter(SpecUint32Array);
+            break;
+        case Array::Float32Array:
+            forNode(node->child1()).filter(SpecFloat32Array);
+            break;
+        case Array::Float64Array:
+            forNode(node->child1()).filter(SpecFloat64Array);
+            break;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
             break;
         }
-        if (m_graph[node.child1()].shouldSpeculateFloat64Array()) {
-            forNode(node.child1()).filter(PredictFloat64Array);
-            forNode(nodeIndex).clear();
+        forNode(node->child1()).filterArrayModes(node->arrayMode().arrayModesThatPassFiltering());
+        m_haveStructures = true;
+        break;
+    }
+    case Arrayify: {
+        if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
+            m_foundConstants = true;
             break;
         }
-        forNode(node.child1()).filter(PredictArray);
-        forNode(nodeIndex).clear();
+        ASSERT(node->arrayMode().conversion() == Array::Convert
+            || node->arrayMode().conversion() == Array::RageConvert);
+        node->setCanExit(true);
+        clobberStructures(indexInBlock);
+        forNode(node->child1()).filterArrayModes(node->arrayMode().arrayModesThatPassFiltering());
+        m_haveStructures = true;
+        break;
+    }
+    case ArrayifyToStructure: {
+        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);
+        clobberStructures(indexInBlock);
+        value.filter(set);
+        m_haveStructures = true;
+        break;
+    }
+    case GetIndexedPropertyStorage: {
+        forNode(node).clear();
         break; 
     }
-    case GetByOffset:
-        forNode(node.child1()).filter(PredictCell);
-        forNode(nodeIndex).makeTop();
+    case GetByOffset: {
+        forNode(node).makeTop();
         break;
+    }
             
-    case PutByOffset:
-        forNode(node.child1()).filter(PredictCell);
+    case PutByOffset: {
         break;
+    }
             
-    case CheckFunction:
-        forNode(node.child1()).filter(PredictFunction);
-        // FIXME: Should be able to propagate the fact that we know what the function is.
+    case CheckFunction: {
+        JSValue value = forNode(node->child1()).value();
+        if (value == node->function()) {
+            m_foundConstants = true;
+            ASSERT(value);
+            break;
+        }
+        
+        node->setCanExit(true); // Lies! We can do better.
+        forNode(node->child1()).filterByValue(node->function());
         break;
-            
+    }
+        
     case PutById:
     case PutByIdDirect:
-        forNode(node.child1()).filter(PredictCell);
-        clobberStructures(indexInBlock);
+        node->setCanExit(true);
+        if (Structure* structure = forNode(node->child1()).bestProvenStructure()) {
+            PutByIdStatus status = PutByIdStatus::computeFor(
+                m_graph.m_vm,
+                m_graph.globalObjectFor(node->codeOrigin),
+                structure,
+                m_graph.m_codeBlock->identifier(node->identifierNumber()),
+                node->op() == PutByIdDirect);
+            if (status.isSimpleReplace()) {
+                forNode(node->child1()).filter(structure);
+                m_foundConstants = true;
+                break;
+            }
+            if (status.isSimpleTransition()) {
+                clobberStructures(indexInBlock);
+                forNode(node->child1()).set(status.newStructure());
+                m_haveStructures = true;
+                m_foundConstants = true;
+                break;
+            }
+        }
+        clobberWorld(node->codeOrigin, indexInBlock);
         break;
             
     case GetGlobalVar:
-        forNode(nodeIndex).makeTop();
+        forNode(node).makeTop();
+        break;
+        
+    case GlobalVarWatchpoint:
+        node->setCanExit(true);
         break;
             
     case PutGlobalVar:
+    case PutGlobalVarCheck:
         break;
             
     case CheckHasInstance:
-        forNode(node.child1()).filter(PredictCell);
+        node->setCanExit(true);
         // Sadly, we don't propagate the fact that we've done CheckHasInstance
         break;
             
     case InstanceOf:
+        node->setCanExit(true);
         // 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);
+        forNode(node).set(SpecBoolean);
         break;
-            
+
     case Phi:
     case Flush:
-        break;
-            
+    case PhantomLocal:
     case Breakpoint:
         break;
             
@@ -1011,97 +1543,174 @@ bool AbstractState::execute(unsigned indexInBlock)
     case ResolveBase:
     case ResolveBaseStrictPut:
     case ResolveGlobal:
-        clobberStructures(indexInBlock);
-        forNode(nodeIndex).makeTop();
+        node->setCanExit(true);
+        clobberWorld(node->codeOrigin, indexInBlock);
+        forNode(node).makeTop();
         break;
-            
+
+    case GarbageValue:
+        clobberWorld(node->codeOrigin, indexInBlock);
+        forNode(node).makeTop();
+        break;
+
+    case Unreachable:
+        RELEASE_ASSERT_NOT_REACHED();
+        break;
+
     case ForceOSRExit:
+        node->setCanExit(true);
         m_isValid = false;
         break;
             
+    case CheckWatchdogTimer:
+        node->setCanExit(true);
+        break;
+            
     case Phantom:
     case InlineStart:
     case Nop:
+    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);
+    clobberStructures(indexInBlock);
+}
+
+inline void AbstractState::clobberCapturedVars(const CodeOrigin& codeOrigin)
+{
+    if (codeOrigin.inlineCallFrame) {
+        const BitVector& capturedVars = codeOrigin.inlineCallFrame->capturedVars;
+        for (size_t i = capturedVars.size(); i--;) {
+            if (!capturedVars.quickGet(i))
+                continue;
+            m_variables.local(i).makeTop();
+        }
+    } else {
+        for (size_t i = m_codeBlock->m_numVars; i--;) {
+            if (m_codeBlock->isCaptured(i))
+                m_variables.local(i).makeTop();
+        }
+    }
+
+    for (size_t i = m_variables.numberOfArguments(); i--;) {
+        if (m_codeBlock->isCaptured(argumentToOperand(i)))
+            m_variables.argument(i).makeTop();
+    }
+}
+
 inline void AbstractState::clobberStructures(unsigned indexInBlock)
 {
-    PROFILE(FLAG_FOR_STRUCTURE_CLOBBERING);
     if (!m_haveStructures)
         return;
     for (size_t i = indexInBlock + 1; i--;)
         forNode(m_block->at(i)).clobberStructures();
-    for (size_t i = 0; i < m_variables.numberOfArguments(); ++i)
+    for (size_t i = m_variables.numberOfArguments(); i--;)
         m_variables.argument(i).clobberStructures();
-    for (size_t i = 0; i < m_variables.numberOfLocals(); ++i)
+    for (size_t i = m_variables.numberOfLocals(); i--;)
         m_variables.local(i).clobberStructures();
     m_haveStructures = false;
+    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 (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)
-    dataLog("          It's live, node @%u.\n", nodeIndex);
+        dataLogF("          Transfering ");
+        source.dump(WTF::dataFile());
+        dataLogF(" from last access due to captured variable.\n");
+#endif
+    } else {
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+        dataLogF("          It's live, node @%u.\n", node->index());
 #endif
     
-    switch (node.op()) {
-    case Phi:
-    case SetArgument:
-    case Flush:
-        // The block transfers the value from head to tail.
-        source = inVariable;
+        switch (node->op()) {
+        case Phi:
+        case SetArgument:
+        case PhantomLocal:
+        case Flush:
+            // The block transfers the value from head to tail.
+            source = inVariable;
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-        dataLog("          Transfering from head to tail.\n");
+            dataLogF("          Transfering ");
+            source.dump(WTF::dataFile());
+            dataLogF(" from head to tail.\n");
 #endif
-        break;
+            break;
             
-    case GetLocal:
-        // The block refines the value with additional speculations.
-        source = forNode(nodeIndex);
+        case GetLocal:
+            // The block refines the value with additional speculations.
+            source = forNode(node);
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-        dataLog("          Refining.\n");
+            dataLogF("          Refining to ");
+            source.dump(WTF::dataFile());
+            dataLogF("\n");
 #endif
-        break;
+            break;
             
-    case SetLocal:
-        // The block sets the variable, and potentially refines it, both
-        // before and after setting it.
-        if (node.variableAccessData()->shouldUseDoubleFormat())
-            source.set(PredictDouble);
-        else
-            source = forNode(node.child1());
+        case SetLocal:
+            // The block sets the variable, and potentially refines it, both
+            // before and after setting it.
+            if (node->variableAccessData()->shouldUseDoubleFormat()) {
+                // FIXME: This unnecessarily loses precision.
+                source.set(SpecDouble);
+            } else
+                source = forNode(node->child1());
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-        dataLog("          Setting.\n");
+            dataLogF("          Setting to ");
+            source.dump(WTF::dataFile());
+            dataLogF("\n");
 #endif
-        break;
+            break;
         
-    default:
-        ASSERT_NOT_REACHED();
-        break;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            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)
-        dataLog("          Not changed!\n");
+        dataLogF("          Not changed!\n");
 #endif
         return false;
     }
@@ -1111,7 +1720,7 @@ inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
     // true to indicate that the fixpoint must go on!
     destination = source;
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-    dataLog("          Changed!\n");
+    dataLogF("          Changed!\n");
 #endif
     return true;
 }
@@ -1125,25 +1734,11 @@ inline bool AbstractState::merge(BasicBlock* from, BasicBlock* to)
     
     for (size_t argument = 0; argument < from->variablesAtTail.numberOfArguments(); ++argument) {
         AbstractValue& destination = to->valuesAtHead.argument(argument);
-        if (m_graph.argumentIsCaptured(argument)) {
-            if (destination.isTop())
-                continue;
-            destination.makeTop();
-            changed = true;
-            continue;
-        }
         changed |= mergeVariableBetweenBlocks(destination, from->valuesAtTail.argument(argument), to->variablesAtHead.argument(argument), from->variablesAtTail.argument(argument));
     }
     
     for (size_t local = 0; local < from->variablesAtTail.numberOfLocals(); ++local) {
         AbstractValue& destination = to->valuesAtHead.local(local);
-        if (m_graph.localIsCaptured(local)) {
-            if (destination.isTop())
-                continue;
-            destination.makeTop();
-            changed = true;
-            continue;
-        }
         changed |= mergeVariableBetweenBlocks(destination, from->valuesAtTail.local(local), to->variablesAtHead.local(local), from->variablesAtTail.local(local));
     }
 
@@ -1157,61 +1752,74 @@ inline bool AbstractState::merge(BasicBlock* from, BasicBlock* to)
 
 inline bool AbstractState::mergeToSuccessors(Graph& graph, BasicBlock* basicBlock)
 {
-    PROFILE(FLAG_FOR_MERGE_TO_SUCCESSORS);
-
-    Node& terminal = graph[basicBlock->last()];
+    Node* terminal = basicBlock->last();
     
-    ASSERT(terminal.isTerminal());
+    ASSERT(terminal->isTerminal());
     
-    switch (terminal.op()) {
-    case Jump:
-        return merge(basicBlock, graph.m_blocks[terminal.takenBlockIndex()].get());
+    switch (terminal->op()) {
+    case Jump: {
+        ASSERT(basicBlock->cfaBranchDirection == InvalidBranchDirection);
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+        dataLogF("        Merging to block #%u.\n", terminal->takenBlockIndex());
+#endif
+        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 Branch: {
+        ASSERT(basicBlock->cfaBranchDirection != InvalidBranchDirection);
+        bool changed = false;
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+        dataLogF("        Merging to block #%u.\n", terminal->takenBlockIndex());
+#endif
+        if (basicBlock->cfaBranchDirection != TakeFalse)
+            changed |= merge(basicBlock, graph.m_blocks[terminal->takenBlockIndex()].get());
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+        dataLogF("        Merging to block #%u.\n", terminal->notTakenBlockIndex());
+#endif
+        if (basicBlock->cfaBranchDirection != TakeTrue)
+            changed |= merge(basicBlock, graph.m_blocks[terminal->notTakenBlockIndex()].get());
+        return changed;
+    }
         
     case Return:
-    case Throw:
-    case ThrowReferenceError:
+    case Unreachable:
+        ASSERT(basicBlock->cfaBranchDirection == InvalidBranchDirection);
         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!
     
     return destination.merge(source);
 }
 
-#ifndef NDEBUG
-void AbstractState::dump(FILE* out)
+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
-            fprintf(out, " ");
-        fprintf(out, "@%lu:", static_cast<unsigned long>(index));
+            out.printf(" ");
+        out.printf("@%lu:", static_cast<unsigned long>(node->index()));
         value.dump(out);
     }
 }
-#endif
 
 } } // namespace JSC::DFG