]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - dfg/DFGFixupPhase.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / dfg / DFGFixupPhase.cpp
index f8b8fcb2ed81e2faa3dfd8fec35517f0ee3bbb44..1affa1ab8fe9c1302381e82a1e2ee47a2ffe62c0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 #if ENABLE(DFG_JIT)
 
+#include "ArrayPrototype.h"
 #include "DFGGraph.h"
 #include "DFGInsertionSet.h"
 #include "DFGPhase.h"
 #include "DFGPredictionPropagationPhase.h"
 #include "DFGVariableAccessDataDump.h"
-#include "Operations.h"
+#include "JSCInlines.h"
+#include "TypeLocation.h"
 
 namespace JSC { namespace DFG {
 
@@ -51,8 +53,8 @@ public:
         ASSERT(m_graph.m_form == ThreadedCPS);
         
         m_profitabilityChanged = false;
-        for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex)
-            fixupBlock(m_graph.m_blocks[blockIndex].get());
+        for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex)
+            fixupBlock(m_graph.block(blockIndex));
         
         while (m_profitabilityChanged) {
             m_profitabilityChanged = false;
@@ -60,10 +62,15 @@ public:
             for (unsigned i = m_graph.m_argumentPositions.size(); i--;)
                 m_graph.m_argumentPositions[i].mergeArgumentUnboxingAwareness();
             
-            for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex)
-                fixupSetLocalsInBlock(m_graph.m_blocks[blockIndex].get());
+            for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex)
+                fixupGetAndSetLocalsInBlock(m_graph.block(blockIndex));
         }
         
+        for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex)
+            injectTypeConversionsInBlock(m_graph.block(blockIndex));
+
+        m_graph.m_planStage = PlanStage::AfterFixup;
+
         return true;
     }
 
@@ -85,14 +92,10 @@ private:
     {
         NodeType op = node->op();
 
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-        dataLogF("   %s @%u: ", Graph::opName(op), node->index());
-#endif
-        
         switch (op) {
         case SetLocal: {
-            // This gets handled by fixupSetLocalsInBlock().
-            break;
+            // This gets handled by fixupGetAndSetLocalsInBlock().
+            return;
         }
             
         case BitAnd:
@@ -100,55 +103,51 @@ private:
         case BitXor:
         case BitRShift:
         case BitLShift:
-        case BitURShift:
-        case ArithIMul: {
-            fixIntEdge(node->child1());
-            fixIntEdge(node->child2());
+        case BitURShift: {
+            fixIntConvertingEdge(node->child1());
+            fixIntConvertingEdge(node->child2());
             break;
         }
-            
-        case UInt32ToNumber: {
-            setUseKindAndUnboxIfProfitable<KnownInt32Use>(node->child1());
+
+        case ArithIMul: {
+            fixIntConvertingEdge(node->child1());
+            fixIntConvertingEdge(node->child2());
+            node->setOp(ArithMul);
+            node->setArithMode(Arith::Unchecked);
+            node->child1().setUseKind(Int32Use);
+            node->child2().setUseKind(Int32Use);
             break;
         }
-            
-        case DoubleAsInt32: {
-            RELEASE_ASSERT_NOT_REACHED();
+
+        case ArithClz32: {
+            fixIntConvertingEdge(node->child1());
+            node->setArithMode(Arith::Unchecked);
             break;
         }
             
-        case ValueToInt32: {
-            if (node->child1()->shouldSpeculateInteger()) {
-                setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
-                node->setOpAndDefaultFlags(Identity);
-                break;
-            }
-            
-            if (node->child1()->shouldSpeculateNumber()) {
-                setUseKindAndUnboxIfProfitable<NumberUse>(node->child1());
-                break;
-            }
-            
-            if (node->child1()->shouldSpeculateBoolean()) {
-                setUseKindAndUnboxIfProfitable<BooleanUse>(node->child1());
-                break;
+        case UInt32ToNumber: {
+            fixIntConvertingEdge(node->child1());
+            if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
+                node->convertToIdentity();
+            else if (node->canSpeculateInt32(FixupPass))
+                node->setArithMode(Arith::CheckOverflow);
+            else {
+                node->setArithMode(Arith::DoOverflow);
+                node->setResult(NodeResultDouble);
             }
-            
-            setUseKindAndUnboxIfProfitable<NotCellUse>(node->child1());
-            break;
-        }
-            
-        case Int32ToDouble: {
-            RELEASE_ASSERT_NOT_REACHED();
             break;
         }
             
         case ValueAdd: {
-            if (attemptToMakeIntegerAdd(node))
+            if (attemptToMakeIntegerAdd(node)) {
+                node->setOp(ArithAdd);
                 break;
-            if (Node::shouldSpeculateNumberExpectingDefined(node->child1().node(), node->child2().node())) {
-                fixDoubleEdge<NumberUse>(node->child1());
-                fixDoubleEdge<NumberUse>(node->child2());
+            }
+            if (Node::shouldSpeculateNumberOrBooleanExpectingDefined(node->child1().node(), node->child2().node())) {
+                fixDoubleOrBooleanEdge(node->child1());
+                fixDoubleOrBooleanEdge(node->child2());
+                node->setOp(ArithAdd);
+                node->setResult(NodeResultDouble);
                 break;
             }
             
@@ -187,102 +186,186 @@ private:
         case ArithSub: {
             if (attemptToMakeIntegerAdd(node))
                 break;
-            fixDoubleEdge<NumberUse>(node->child1());
-            fixDoubleEdge<NumberUse>(node->child2());
+            fixDoubleOrBooleanEdge(node->child1());
+            fixDoubleOrBooleanEdge(node->child2());
+            node->setResult(NodeResultDouble);
             break;
         }
             
         case ArithNegate: {
-            if (m_graph.negateShouldSpeculateInteger(node)) {
-                setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
+            if (m_graph.negateShouldSpeculateInt32(node, FixupPass)) {
+                fixIntOrBooleanEdge(node->child1());
+                if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
+                    node->setArithMode(Arith::Unchecked);
+                else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
+                    node->setArithMode(Arith::CheckOverflow);
+                else
+                    node->setArithMode(Arith::CheckOverflowAndNegativeZero);
+                break;
+            }
+            if (m_graph.negateShouldSpeculateMachineInt(node, FixupPass)) {
+                fixEdge<Int52RepUse>(node->child1());
+                if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
+                    node->setArithMode(Arith::CheckOverflow);
+                else
+                    node->setArithMode(Arith::CheckOverflowAndNegativeZero);
+                node->setResult(NodeResultInt52);
                 break;
             }
-            fixDoubleEdge<NumberUse>(node->child1());
+            fixDoubleOrBooleanEdge(node->child1());
+            node->setResult(NodeResultDouble);
             break;
         }
             
         case ArithMul: {
-            if (m_graph.mulShouldSpeculateInteger(node)) {
-                setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
-                setUseKindAndUnboxIfProfitable<Int32Use>(node->child2());
+            if (m_graph.mulShouldSpeculateInt32(node, FixupPass)) {
+                fixIntOrBooleanEdge(node->child1());
+                fixIntOrBooleanEdge(node->child2());
+                if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
+                    node->setArithMode(Arith::Unchecked);
+                else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
+                    node->setArithMode(Arith::CheckOverflow);
+                else
+                    node->setArithMode(Arith::CheckOverflowAndNegativeZero);
+                break;
+            }
+            if (m_graph.mulShouldSpeculateMachineInt(node, FixupPass)) {
+                fixEdge<Int52RepUse>(node->child1());
+                fixEdge<Int52RepUse>(node->child2());
+                if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
+                    node->setArithMode(Arith::CheckOverflow);
+                else
+                    node->setArithMode(Arith::CheckOverflowAndNegativeZero);
+                node->setResult(NodeResultInt52);
                 break;
             }
-            fixDoubleEdge<NumberUse>(node->child1());
-            fixDoubleEdge<NumberUse>(node->child2());
+            fixDoubleOrBooleanEdge(node->child1());
+            fixDoubleOrBooleanEdge(node->child2());
+            node->setResult(NodeResultDouble);
             break;
         }
 
-        case ArithDiv: {
-            if (Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node())
-                && node->canSpeculateInteger()) {
-                if (isX86() || isARM64() || isARMv7s()) {
-                    setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
-                    setUseKindAndUnboxIfProfitable<Int32Use>(node->child2());
+        case ArithDiv:
+        case ArithMod: {
+            if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node())
+                && node->canSpeculateInt32(FixupPass)) {
+                if (optimizeForX86() || optimizeForARM64() || optimizeForARMv7IDIVSupported()) {
+                    fixIntOrBooleanEdge(node->child1());
+                    fixIntOrBooleanEdge(node->child2());
+                    if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
+                        node->setArithMode(Arith::Unchecked);
+                    else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
+                        node->setArithMode(Arith::CheckOverflow);
+                    else
+                        node->setArithMode(Arith::CheckOverflowAndNegativeZero);
                     break;
                 }
-                injectInt32ToDoubleNode(node->child1());
-                injectInt32ToDoubleNode(node->child2());
-
+                
+                // This will cause conversion nodes to be inserted later.
+                fixDoubleOrBooleanEdge(node->child1());
+                fixDoubleOrBooleanEdge(node->child2());
+                
                 // We don't need to do ref'ing on the children because we're stealing them from
                 // the original division.
                 Node* newDivision = m_insertionSet.insertNode(
-                    m_indexInBlock, SpecDouble, *node);
+                    m_indexInBlock, SpecBytecodeDouble, *node);
+                newDivision->setResult(NodeResultDouble);
                 
                 node->setOp(DoubleAsInt32);
-                node->children.initialize(Edge(newDivision, KnownNumberUse), Edge(), Edge());
+                node->children.initialize(Edge(newDivision, DoubleRepUse), Edge(), Edge());
+                if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
+                    node->setArithMode(Arith::CheckOverflow);
+                else
+                    node->setArithMode(Arith::CheckOverflowAndNegativeZero);
                 break;
             }
-            fixDoubleEdge<NumberUse>(node->child1());
-            fixDoubleEdge<NumberUse>(node->child2());
+            fixDoubleOrBooleanEdge(node->child1());
+            fixDoubleOrBooleanEdge(node->child2());
+            node->setResult(NodeResultDouble);
             break;
         }
             
         case ArithMin:
-        case ArithMax:
-        case ArithMod: {
-            if (Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node())
-                && node->canSpeculateInteger()) {
-                setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
-                setUseKindAndUnboxIfProfitable<Int32Use>(node->child2());
+        case ArithMax: {
+            if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node())
+                && node->canSpeculateInt32(FixupPass)) {
+                fixIntOrBooleanEdge(node->child1());
+                fixIntOrBooleanEdge(node->child2());
                 break;
             }
-            fixDoubleEdge<NumberUse>(node->child1());
-            fixDoubleEdge<NumberUse>(node->child2());
+            fixDoubleOrBooleanEdge(node->child1());
+            fixDoubleOrBooleanEdge(node->child2());
+            node->setResult(NodeResultDouble);
             break;
         }
             
         case ArithAbs: {
-            if (node->child1()->shouldSpeculateIntegerForArithmetic()
-                && node->canSpeculateInteger()) {
-                setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
+            if (node->child1()->shouldSpeculateInt32OrBooleanForArithmetic()
+                && node->canSpeculateInt32(FixupPass)) {
+                fixIntOrBooleanEdge(node->child1());
+                break;
+            }
+            fixDoubleOrBooleanEdge(node->child1());
+            node->setResult(NodeResultDouble);
+            break;
+        }
+
+        case ArithPow: {
+            node->setResult(NodeResultDouble);
+            if (node->child2()->shouldSpeculateInt32OrBooleanForArithmetic()) {
+                fixDoubleOrBooleanEdge(node->child1());
+                fixIntOrBooleanEdge(node->child2());
+                break;
+            }
+
+            fixDoubleOrBooleanEdge(node->child1());
+            fixDoubleOrBooleanEdge(node->child2());
+            break;
+        }
+
+        case ArithRound: {
+            if (node->child1()->shouldSpeculateInt32OrBooleanForArithmetic() && node->canSpeculateInt32(FixupPass)) {
+                fixIntOrBooleanEdge(node->child1());
+                insertCheck<Int32Use>(m_indexInBlock, node->child1().node());
+                node->convertToIdentity();
                 break;
             }
-            fixDoubleEdge<NumberUse>(node->child1());
+            fixDoubleOrBooleanEdge(node->child1());
+
+            if (isInt32OrBooleanSpeculation(node->getHeapPrediction()) && m_graph.roundShouldSpeculateInt32(node, FixupPass)) {
+                node->setResult(NodeResultInt32);
+                if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
+                    node->setArithRoundingMode(Arith::RoundingMode::Int32);
+                else
+                    node->setArithRoundingMode(Arith::RoundingMode::Int32WithNegativeZeroCheck);
+            } else {
+                node->setResult(NodeResultDouble);
+                node->setArithRoundingMode(Arith::RoundingMode::Double);
+            }
             break;
         }
             
-        case ArithSqrt: {
-            fixDoubleEdge<NumberUse>(node->child1());
+        case ArithSqrt:
+        case ArithFRound:
+        case ArithSin:
+        case ArithCos:
+        case ArithLog: {
+            fixDoubleOrBooleanEdge(node->child1());
+            node->setResult(NodeResultDouble);
             break;
         }
             
         case LogicalNot: {
             if (node->child1()->shouldSpeculateBoolean())
-                setUseKindAndUnboxIfProfitable<BooleanUse>(node->child1());
+                fixEdge<BooleanUse>(node->child1());
             else if (node->child1()->shouldSpeculateObjectOrOther())
-                setUseKindAndUnboxIfProfitable<ObjectOrOtherUse>(node->child1());
-            else if (node->child1()->shouldSpeculateInteger())
-                setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
+                fixEdge<ObjectOrOtherUse>(node->child1());
+            else if (node->child1()->shouldSpeculateInt32OrBoolean())
+                fixIntOrBooleanEdge(node->child1());
             else if (node->child1()->shouldSpeculateNumber())
-                fixDoubleEdge<NumberUse>(node->child1());
-            break;
-        }
-            
-        case TypeOf: {
-            if (node->child1()->shouldSpeculateString())
-                setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
-            else if (node->child1()->shouldSpeculateCell())
-                setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
+                fixEdge<DoubleRepUse>(node->child1());
+            else if (node->child1()->shouldSpeculateString())
+                fixEdge<StringUse>(node->child1());
             break;
         }
             
@@ -295,81 +378,151 @@ private:
         case CompareLessEq:
         case CompareGreater:
         case CompareGreaterEq: {
-            if (Node::shouldSpeculateInteger(node->child1().node(), node->child2().node())) {
-                setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
-                setUseKindAndUnboxIfProfitable<Int32Use>(node->child2());
+            if (node->op() == CompareEq
+                && Node::shouldSpeculateBoolean(node->child1().node(), node->child2().node())) {
+                fixEdge<BooleanUse>(node->child1());
+                fixEdge<BooleanUse>(node->child2());
+                node->clearFlags(NodeMustGenerate);
                 break;
             }
-            if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node())) {
-                fixDoubleEdge<NumberUse>(node->child1());
-                fixDoubleEdge<NumberUse>(node->child2());
+            if (Node::shouldSpeculateInt32OrBoolean(node->child1().node(), node->child2().node())) {
+                fixIntOrBooleanEdge(node->child1());
+                fixIntOrBooleanEdge(node->child2());
+                node->clearFlags(NodeMustGenerate);
+                break;
+            }
+            if (enableInt52()
+                && Node::shouldSpeculateMachineInt(node->child1().node(), node->child2().node())) {
+                fixEdge<Int52RepUse>(node->child1());
+                fixEdge<Int52RepUse>(node->child2());
+                node->clearFlags(NodeMustGenerate);
+                break;
+            }
+            if (Node::shouldSpeculateNumberOrBoolean(node->child1().node(), node->child2().node())) {
+                fixDoubleOrBooleanEdge(node->child1());
+                fixDoubleOrBooleanEdge(node->child2());
+                node->clearFlags(NodeMustGenerate);
                 break;
             }
             if (node->op() != CompareEq)
                 break;
-            if (Node::shouldSpeculateBoolean(node->child1().node(), node->child2().node())) {
-                setUseKindAndUnboxIfProfitable<BooleanUse>(node->child1());
-                setUseKindAndUnboxIfProfitable<BooleanUse>(node->child2());
+            if (node->child1()->shouldSpeculateStringIdent() && node->child2()->shouldSpeculateStringIdent()) {
+                fixEdge<StringIdentUse>(node->child1());
+                fixEdge<StringIdentUse>(node->child2());
+                node->clearFlags(NodeMustGenerate);
                 break;
             }
             if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && GPRInfo::numberOfRegisters >= 7) {
-                setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
-                setUseKindAndUnboxIfProfitable<StringUse>(node->child2());
+                fixEdge<StringUse>(node->child1());
+                fixEdge<StringUse>(node->child2());
+                node->clearFlags(NodeMustGenerate);
                 break;
             }
             if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) {
-                setUseKindAndUnboxIfProfitable<ObjectUse>(node->child1());
-                setUseKindAndUnboxIfProfitable<ObjectUse>(node->child2());
+                fixEdge<ObjectUse>(node->child1());
+                fixEdge<ObjectUse>(node->child2());
+                node->clearFlags(NodeMustGenerate);
                 break;
             }
             if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObjectOrOther()) {
-                setUseKindAndUnboxIfProfitable<ObjectUse>(node->child1());
-                setUseKindAndUnboxIfProfitable<ObjectOrOtherUse>(node->child2());
+                fixEdge<ObjectUse>(node->child1());
+                fixEdge<ObjectOrOtherUse>(node->child2());
+                node->clearFlags(NodeMustGenerate);
                 break;
             }
             if (node->child1()->shouldSpeculateObjectOrOther() && node->child2()->shouldSpeculateObject()) {
-                setUseKindAndUnboxIfProfitable<ObjectOrOtherUse>(node->child1());
-                setUseKindAndUnboxIfProfitable<ObjectUse>(node->child2());
+                fixEdge<ObjectOrOtherUse>(node->child1());
+                fixEdge<ObjectUse>(node->child2());
+                node->clearFlags(NodeMustGenerate);
                 break;
             }
             break;
         }
             
-        case CompareStrictEqConstant: {
-            break;
-        }
-            
         case CompareStrictEq: {
             if (Node::shouldSpeculateBoolean(node->child1().node(), node->child2().node())) {
-                setUseKindAndUnboxIfProfitable<BooleanUse>(node->child1());
-                setUseKindAndUnboxIfProfitable<BooleanUse>(node->child2());
+                fixEdge<BooleanUse>(node->child1());
+                fixEdge<BooleanUse>(node->child2());
                 break;
             }
-            if (Node::shouldSpeculateInteger(node->child1().node(), node->child2().node())) {
-                setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
-                setUseKindAndUnboxIfProfitable<Int32Use>(node->child2());
+            if (Node::shouldSpeculateInt32(node->child1().node(), node->child2().node())) {
+                fixEdge<Int32Use>(node->child1());
+                fixEdge<Int32Use>(node->child2());
+                break;
+            }
+            if (enableInt52()
+                && Node::shouldSpeculateMachineInt(node->child1().node(), node->child2().node())) {
+                fixEdge<Int52RepUse>(node->child1());
+                fixEdge<Int52RepUse>(node->child2());
                 break;
             }
             if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node())) {
-                fixDoubleEdge<NumberUse>(node->child1());
-                fixDoubleEdge<NumberUse>(node->child2());
+                fixEdge<DoubleRepUse>(node->child1());
+                fixEdge<DoubleRepUse>(node->child2());
                 break;
             }
-            if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && GPRInfo::numberOfRegisters >= 7) {
-                setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
-                setUseKindAndUnboxIfProfitable<StringUse>(node->child2());
+            if (node->child1()->shouldSpeculateStringIdent() && node->child2()->shouldSpeculateStringIdent()) {
+                fixEdge<StringIdentUse>(node->child1());
+                fixEdge<StringIdentUse>(node->child2());
                 break;
             }
-            if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) {
-                setUseKindAndUnboxIfProfitable<ObjectUse>(node->child1());
-                setUseKindAndUnboxIfProfitable<ObjectUse>(node->child2());
+            if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 7) || isFTL(m_graph.m_plan.mode))) {
+                fixEdge<StringUse>(node->child1());
+                fixEdge<StringUse>(node->child2());
+                break;
+            }
+            WatchpointSet* masqueradesAsUndefinedWatchpoint = m_graph.globalObjectFor(node->origin.semantic)->masqueradesAsUndefinedWatchpoint();
+            if (masqueradesAsUndefinedWatchpoint->isStillValid()) {
+                
+                if (node->child1()->shouldSpeculateObject()) {
+                    m_graph.watchpoints().addLazily(masqueradesAsUndefinedWatchpoint);
+                    fixEdge<ObjectUse>(node->child1());
+                    break;
+                }
+                if (node->child2()->shouldSpeculateObject()) {
+                    m_graph.watchpoints().addLazily(masqueradesAsUndefinedWatchpoint);
+                    fixEdge<ObjectUse>(node->child2());
+                    break;
+                }
+                
+            } else if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) {
+                fixEdge<ObjectUse>(node->child1());
+                fixEdge<ObjectUse>(node->child2());
+                break;
+            }
+            if (node->child1()->shouldSpeculateMisc()) {
+                fixEdge<MiscUse>(node->child1());
+                break;
+            }
+            if (node->child2()->shouldSpeculateMisc()) {
+                fixEdge<MiscUse>(node->child2());
+                break;
+            }
+            if (node->child1()->shouldSpeculateStringIdent()
+                && node->child2()->shouldSpeculateNotStringVar()) {
+                fixEdge<StringIdentUse>(node->child1());
+                fixEdge<NotStringVarUse>(node->child2());
+                break;
+            }
+            if (node->child2()->shouldSpeculateStringIdent()
+                && node->child1()->shouldSpeculateNotStringVar()) {
+                fixEdge<StringIdentUse>(node->child2());
+                fixEdge<NotStringVarUse>(node->child1());
+                break;
+            }
+            if (node->child1()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 8) || isFTL(m_graph.m_plan.mode))) {
+                fixEdge<StringUse>(node->child1());
+                break;
+            }
+            if (node->child2()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 8) || isFTL(m_graph.m_plan.mode))) {
+                fixEdge<StringUse>(node->child2());
                 break;
             }
             break;
         }
 
         case StringFromCharCode:
-            setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
+            fixEdge<Int32Use>(node->child1());
             break;
 
         case StringCharAt:
@@ -377,30 +530,99 @@ private:
             // Currently we have no good way of refining these.
             ASSERT(node->arrayMode() == ArrayMode(Array::String));
             blessArrayOperation(node->child1(), node->child2(), node->child3());
-            setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child1());
-            setUseKindAndUnboxIfProfitable<Int32Use>(node->child2());
+            fixEdge<KnownCellUse>(node->child1());
+            fixEdge<Int32Use>(node->child2());
             break;
         }
 
         case GetByVal: {
+            if (!node->prediction()) {
+                m_insertionSet.insertNode(
+                    m_indexInBlock, SpecNone, ForceOSRExit, node->origin);
+            }
+            
             node->setArrayMode(
                 node->arrayMode().refine(
+                    m_graph, node,
                     node->child1()->prediction(),
                     node->child2()->prediction(),
-                    SpecNone, node->flags()));
+                    SpecNone));
             
             blessArrayOperation(node->child1(), node->child2(), node->child3());
             
             ArrayMode arrayMode = node->arrayMode();
-            if (arrayMode.type() == Array::Double
-                && arrayMode.arrayClass() == Array::OriginalArray
-                && arrayMode.speculation() == Array::InBounds
-                && arrayMode.conversion() == Array::AsIs
-                && m_graph.globalObjectFor(node->codeOrigin)->arrayPrototypeChainIsSane()
-                && !(node->flags() & NodeUsedAsOther))
-                node->setArrayMode(arrayMode.withSpeculation(Array::SaneChain));
+            switch (arrayMode.type()) {
+            case Array::Contiguous:
+            case Array::Double:
+                if (arrayMode.arrayClass() == Array::OriginalArray
+                    && arrayMode.speculation() == Array::InBounds) {
+                    JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
+                    if (globalObject->arrayPrototypeChainIsSane()) {
+                        // Check if SaneChain will work on a per-type basis. Note that:
+                        //
+                        // 1) We don't want double arrays to sometimes return undefined, since
+                        // that would require a change to the return type and it would pessimise
+                        // things a lot. So, we'd only want to do that if we actually had
+                        // evidence that we could read from a hole. That's pretty annoying.
+                        // Likely the best way to handle that case is with an equivalent of
+                        // SaneChain for OutOfBounds. For now we just detect when Undefined and
+                        // NaN are indistinguishable according to backwards propagation, and just
+                        // use SaneChain in that case. This happens to catch a lot of cases.
+                        //
+                        // 2) We don't want int32 array loads to have to do a hole check just to
+                        // coerce to Undefined, since that would mean twice the checks.
+                        //
+                        // This has two implications. First, we have to do more checks than we'd
+                        // like. It's unfortunate that we have to do the hole check. Second,
+                        // some accesses that hit a hole will now need to take the full-blown
+                        // out-of-bounds slow path. We can fix that with:
+                        // https://bugs.webkit.org/show_bug.cgi?id=144668
+                        
+                        bool canDoSaneChain = false;
+                        switch (arrayMode.type()) {
+                        case Array::Contiguous:
+                            // This is happens to be entirely natural. We already would have
+                            // returned any JSValue, and now we'll return Undefined. We still do
+                            // the check but it doesn't require taking any kind of slow path.
+                            canDoSaneChain = true;
+                            break;
+                            
+                        case Array::Double:
+                            if (!(node->flags() & NodeBytecodeUsesAsOther)) {
+                                // Holes look like NaN already, so if the user doesn't care
+                                // about the difference between Undefined and NaN then we can
+                                // do this.
+                                canDoSaneChain = true;
+                            }
+                            break;
+                            
+                        default:
+                            break;
+                        }
+                        
+                        if (canDoSaneChain) {
+                            m_graph.watchpoints().addLazily(
+                                globalObject->arrayPrototype()->structure()->transitionWatchpointSet());
+                            m_graph.watchpoints().addLazily(
+                                globalObject->objectPrototype()->structure()->transitionWatchpointSet());
+                            node->setArrayMode(arrayMode.withSpeculation(Array::SaneChain));
+                        }
+                    }
+                }
+                break;
+                
+            case Array::String:
+                if ((node->prediction() & ~SpecString)
+                    || m_graph.hasExitSite(node->origin.semantic, OutOfBounds))
+                    node->setArrayMode(arrayMode.withSpeculation(Array::OutOfBounds));
+                break;
+                
+            default:
+                break;
+            }
             
-            switch (node->arrayMode().type()) {
+            arrayMode = node->arrayMode();
+            switch (arrayMode.type()) {
             case Array::SelectUsingPredictions:
             case Array::Unprofiled:
             case Array::Undecided:
@@ -408,20 +630,45 @@ private:
                 break;
             case Array::Generic:
 #if USE(JSVALUE32_64)
-                setUseKindAndUnboxIfProfitable<CellUse>(node->child1()); // Speculating cell due to register pressure on 32-bit.
+                fixEdge<CellUse>(node->child1()); // Speculating cell due to register pressure on 32-bit.
 #endif
                 break;
             case Array::ForceExit:
                 break;
             default:
-                setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child1());
-                setUseKindAndUnboxIfProfitable<Int32Use>(node->child2());
+                fixEdge<KnownCellUse>(node->child1());
+                fixEdge<Int32Use>(node->child2());
+                break;
+            }
+            
+            switch (arrayMode.type()) {
+            case Array::Double:
+                if (!arrayMode.isOutOfBounds())
+                    node->setResult(NodeResultDouble);
+                break;
+                
+            case Array::Float32Array:
+            case Array::Float64Array:
+                node->setResult(NodeResultDouble);
+                break;
+                
+            case Array::Uint32Array:
+                if (node->shouldSpeculateInt32())
+                    break;
+                if (node->shouldSpeculateMachineInt() && enableInt52())
+                    node->setResult(NodeResultInt52);
+                else
+                    node->setResult(NodeResultDouble);
+                break;
+                
+            default:
                 break;
             }
             
             break;
         }
-            
+
+        case PutByValDirect:
         case PutByVal:
         case PutByValAlias: {
             Edge& child1 = m_graph.varArgChild(node, 0);
@@ -430,6 +677,7 @@ private:
 
             node->setArrayMode(
                 node->arrayMode().refine(
+                    m_graph, node,
                     child1->prediction(),
                     child2->prediction(),
                     child3->prediction()));
@@ -448,18 +696,18 @@ private:
                 // Due to register pressure on 32-bit, we speculate cell and
                 // ignore the base-is-not-cell case entirely by letting the
                 // baseline JIT handle it.
-                setUseKindAndUnboxIfProfitable<CellUse>(child1);
+                fixEdge<CellUse>(child1);
 #endif
                 break;
             case Array::Int32:
-                setUseKindAndUnboxIfProfitable<KnownCellUse>(child1);
-                setUseKindAndUnboxIfProfitable<Int32Use>(child2);
-                setUseKindAndUnboxIfProfitable<Int32Use>(child3);
+                fixEdge<KnownCellUse>(child1);
+                fixEdge<Int32Use>(child2);
+                fixEdge<Int32Use>(child3);
                 break;
             case Array::Double:
-                setUseKindAndUnboxIfProfitable<KnownCellUse>(child1);
-                setUseKindAndUnboxIfProfitable<Int32Use>(child2);
-                fixDoubleEdge<RealNumberUse>(child3);
+                fixEdge<KnownCellUse>(child1);
+                fixEdge<Int32Use>(child2);
+                fixEdge<DoubleRepRealUse>(child3);
                 break;
             case Array::Int8Array:
             case Array::Int16Array:
@@ -468,22 +716,31 @@ private:
             case Array::Uint8ClampedArray:
             case Array::Uint16Array:
             case Array::Uint32Array:
-                setUseKindAndUnboxIfProfitable<KnownCellUse>(child1);
-                setUseKindAndUnboxIfProfitable<Int32Use>(child2);
-                if (child3->shouldSpeculateInteger())
-                    setUseKindAndUnboxIfProfitable<Int32Use>(child3);
+                fixEdge<KnownCellUse>(child1);
+                fixEdge<Int32Use>(child2);
+                if (child3->shouldSpeculateInt32())
+                    fixIntOrBooleanEdge(child3);
+                else if (child3->shouldSpeculateMachineInt())
+                    fixEdge<Int52RepUse>(child3);
                 else
-                    fixDoubleEdge<NumberUse>(child3);
+                    fixDoubleOrBooleanEdge(child3);
                 break;
             case Array::Float32Array:
             case Array::Float64Array:
-                setUseKindAndUnboxIfProfitable<KnownCellUse>(child1);
-                setUseKindAndUnboxIfProfitable<Int32Use>(child2);
-                fixDoubleEdge<NumberUse>(child3);
+                fixEdge<KnownCellUse>(child1);
+                fixEdge<Int32Use>(child2);
+                fixDoubleOrBooleanEdge(child3);
+                break;
+            case Array::Contiguous:
+            case Array::ArrayStorage:
+            case Array::SlowPutArrayStorage:
+                fixEdge<KnownCellUse>(child1);
+                fixEdge<Int32Use>(child2);
+                speculateForBarrier(child3);
                 break;
             default:
-                setUseKindAndUnboxIfProfitable<KnownCellUse>(child1);
-                setUseKindAndUnboxIfProfitable<Int32Use>(child2);
+                fixEdge<KnownCellUse>(child1);
+                fixEdge<Int32Use>(child2);
                 break;
             }
             break;
@@ -501,18 +758,23 @@ private:
             // that would break things.
             node->setArrayMode(
                 node->arrayMode().refine(
+                    m_graph, node,
                     node->child1()->prediction() & SpecCell,
                     SpecInt32,
                     node->child2()->prediction()));
             blessArrayOperation(node->child1(), Edge(), node->child3());
-            setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child1());
+            fixEdge<KnownCellUse>(node->child1());
             
             switch (node->arrayMode().type()) {
             case Array::Int32:
-                setUseKindAndUnboxIfProfitable<Int32Use>(node->child2());
+                fixEdge<Int32Use>(node->child2());
                 break;
             case Array::Double:
-                fixDoubleEdge<RealNumberUse>(node->child2());
+                fixEdge<DoubleRepRealUse>(node->child2());
+                break;
+            case Array::Contiguous:
+            case Array::ArrayStorage:
+                speculateForBarrier(node->child2());
                 break;
             default:
                 break;
@@ -522,59 +784,54 @@ private:
             
         case ArrayPop: {
             blessArrayOperation(node->child1(), Edge(), node->child2());
-            setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child1());
+            fixEdge<KnownCellUse>(node->child1());
             break;
         }
             
         case RegExpExec:
         case RegExpTest: {
-            setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
-            setUseKindAndUnboxIfProfitable<CellUse>(node->child2());
+            fixEdge<CellUse>(node->child1());
+            fixEdge<CellUse>(node->child2());
             break;
         }
             
         case Branch: {
             if (node->child1()->shouldSpeculateBoolean())
-                setUseKindAndUnboxIfProfitable<BooleanUse>(node->child1());
+                fixEdge<BooleanUse>(node->child1());
             else if (node->child1()->shouldSpeculateObjectOrOther())
-                setUseKindAndUnboxIfProfitable<ObjectOrOtherUse>(node->child1());
-            else if (node->child1()->shouldSpeculateInteger())
-                setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
+                fixEdge<ObjectOrOtherUse>(node->child1());
+            else if (node->child1()->shouldSpeculateInt32OrBoolean())
+                fixIntOrBooleanEdge(node->child1());
             else if (node->child1()->shouldSpeculateNumber())
-                fixDoubleEdge<NumberUse>(node->child1());
-
-            Node* logicalNot = node->child1().node();
-            if (logicalNot->op() == LogicalNot) {
-                
-                // Make sure that OSR exit can't observe the LogicalNot. If it can,
-                // then we must compute it and cannot peephole around it.
-                bool found = false;
-                bool ok = true;
-                for (unsigned i = m_indexInBlock; i--;) {
-                    Node* candidate = m_block->at(i);
-                    if (candidate == logicalNot) {
-                        found = true;
-                        break;
-                    }
-                    if (candidate->canExit()) {
-                        ok = false;
-                        found = true;
-                        break;
-                    }
-                }
-                ASSERT_UNUSED(found, found);
-                
-                if (ok) {
-                    Edge newChildEdge = logicalNot->child1();
-                    if (newChildEdge->hasBooleanResult()) {
-                        node->children.setChild1(newChildEdge);
-                        
-                        BlockIndex toBeTaken = node->notTakenBlockIndex();
-                        BlockIndex toBeNotTaken = node->takenBlockIndex();
-                        node->setTakenBlockIndex(toBeTaken);
-                        node->setNotTakenBlockIndex(toBeNotTaken);
-                    }
-                }
+                fixEdge<DoubleRepUse>(node->child1());
+            else if (node->child1()->shouldSpeculateString())
+                fixEdge<StringUse>(node->child1());
+            break;
+        }
+            
+        case Switch: {
+            SwitchData* data = node->switchData();
+            switch (data->kind) {
+            case SwitchImm:
+                if (node->child1()->shouldSpeculateInt32())
+                    fixEdge<Int32Use>(node->child1());
+                break;
+            case SwitchChar:
+                if (node->child1()->shouldSpeculateString())
+                    fixEdge<StringUse>(node->child1());
+                break;
+            case SwitchString:
+                if (node->child1()->shouldSpeculateStringIdent())
+                    fixEdge<StringIdentUse>(node->child1());
+                else if (node->child1()->shouldSpeculateString())
+                    fixEdge<StringUse>(node->child1());
+                break;
+            case SwitchCell:
+                if (node->child1()->shouldSpeculateCell())
+                    fixEdge<CellUse>(node->child1());
+                // else it's fine for this to have UntypedUse; we will handle this by just making
+                // non-cells take the default case.
+                break;
             }
             break;
         }
@@ -584,13 +841,14 @@ private:
             break;
         }
             
-        case ToString: {
-            fixupToString(node);
+        case ToString:
+        case CallStringConstructor: {
+            fixupToStringOrCallStringConstructor(node);
             break;
         }
             
         case NewStringObject: {
-            setUseKindAndUnboxIfProfitable<KnownStringUse>(node->child1());
+            fixEdge<KnownStringUse>(node->child1());
             break;
         }
             
@@ -610,16 +868,16 @@ private:
                     // would have already exited by now, but insert a forced exit just to
                     // be safe.
                     m_insertionSet.insertNode(
-                        m_indexInBlock, SpecNone, ForceOSRExit, node->codeOrigin);
+                        m_indexInBlock, SpecNone, ForceOSRExit, node->origin);
                 }
                 break;
             case ALL_INT32_INDEXING_TYPES:
                 for (unsigned operandIndex = 0; operandIndex < node->numChildren(); ++operandIndex)
-                    setUseKindAndUnboxIfProfitable<Int32Use>(m_graph.m_varArgChildren[node->firstChild() + operandIndex]);
+                    fixEdge<Int32Use>(m_graph.m_varArgChildren[node->firstChild() + operandIndex]);
                 break;
             case ALL_DOUBLE_INDEXING_TYPES:
                 for (unsigned operandIndex = 0; operandIndex < node->numChildren(); ++operandIndex)
-                    setUseKindAndUnboxIfProfitable<RealNumberUse>(m_graph.m_varArgChildren[node->firstChild() + operandIndex]);
+                    fixEdge<DoubleRepRealUse>(m_graph.m_varArgChildren[node->firstChild() + operandIndex]);
                 break;
             case ALL_CONTIGUOUS_INDEXING_TYPES:
             case ALL_ARRAY_STORAGE_INDEXING_TYPES:
@@ -631,23 +889,41 @@ private:
             break;
         }
             
+        case NewTypedArray: {
+            if (node->child1()->shouldSpeculateInt32()) {
+                fixEdge<Int32Use>(node->child1());
+                node->clearFlags(NodeMustGenerate);
+                break;
+            }
+            break;
+        }
+            
         case NewArrayWithSize: {
-            setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
+            fixEdge<Int32Use>(node->child1());
             break;
         }
             
-        case ConvertThis: {
-            if (isOtherSpeculation(node->child1()->prediction())) {
+        case ToThis: {
+            ECMAMode ecmaMode = m_graph.executableFor(node->origin.semantic)->isStrictMode() ? StrictMode : NotStrictMode;
+
+            if (node->child1()->shouldSpeculateOther()) {
+                if (ecmaMode == StrictMode) {
+                    fixEdge<OtherUse>(node->child1());
+                    node->convertToIdentity();
+                    break;
+                }
+
                 m_insertionSet.insertNode(
-                    m_indexInBlock, SpecNone, Phantom, node->codeOrigin,
+                    m_indexInBlock, SpecNone, Check, node->origin,
                     Edge(node->child1().node(), OtherUse));
                 observeUseKindOnNode<OtherUse>(node->child1().node());
-                node->convertToWeakConstant(m_graph.globalThisObjectFor(node->codeOrigin));
+                m_graph.convertToConstant(
+                    node, m_graph.globalThisObjectFor(node->origin.semantic));
                 break;
             }
             
-            if (isObjectSpeculation(node->child1()->prediction())) {
-                setUseKindAndUnboxIfProfitable<ObjectUse>(node->child1());
+            if (isFinalObjectSpeculation(node->child1()->prediction())) {
+                fixEdge<FinalObjectUse>(node->child1());
                 node->convertToIdentity();
                 break;
             }
@@ -655,247 +931,404 @@ private:
             break;
         }
             
-        case CreateThis: {
-            setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
+        case PutStructure: {
+            fixEdge<KnownCellUse>(node->child1());
             break;
         }
             
-        case GetMyArgumentByVal:
-        case GetMyArgumentByValSafe: {
-            setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
+        case GetClosureVar:
+        case GetFromArguments: {
+            fixEdge<KnownCellUse>(node->child1());
+            break;
+        }
+
+        case PutClosureVar:
+        case PutToArguments: {
+            fixEdge<KnownCellUse>(node->child1());
+            speculateForBarrier(node->child2());
             break;
         }
             
-        case GetScopeRegisters:
-        case PutScopedVar:
-        case SkipTopScope:
         case SkipScope:
-        case SetCallee:
-        case SetMyScope:
-        case PutStructure:
-        case AllocatePropertyStorage:
-        case ReallocatePropertyStorage:
         case GetScope:
-        case GetButterfly: {
-            setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child1());
+        case GetGetter:
+        case GetSetter: {
+            fixEdge<KnownCellUse>(node->child1());
             break;
         }
             
-        case GetById: {
+        case AllocatePropertyStorage:
+        case ReallocatePropertyStorage: {
+            fixEdge<KnownCellUse>(node->child1());
+            break;
+        }
+
+        case GetById:
+        case GetByIdFlush: {
             if (!node->child1()->shouldSpeculateCell())
                 break;
-            setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
-            if (!isInt32Speculation(node->prediction()))
-                break;
-            if (codeBlock()->identifier(node->identifierNumber()) != vm().propertyNames->length)
-                break;
-            ArrayProfile* arrayProfile = 
-                m_graph.baselineCodeBlockFor(node->codeOrigin)->getArrayProfile(
-                    node->codeOrigin.bytecodeIndex);
-            ArrayMode arrayMode = ArrayMode(Array::SelectUsingPredictions);
-            if (arrayProfile) {
-                arrayProfile->computeUpdatedPrediction(m_graph.baselineCodeBlockFor(node->codeOrigin));
-                arrayMode = ArrayMode::fromObserved(arrayProfile, Array::Read, false);
-                arrayMode = arrayMode.refine(
-                    node->child1()->prediction(), node->prediction());
-                if (arrayMode.supportsLength() && arrayProfile->hasDefiniteStructure()) {
-                    m_insertionSet.insertNode(
-                        m_indexInBlock, SpecNone, CheckStructure, node->codeOrigin,
-                        OpInfo(m_graph.addStructureSet(arrayProfile->expectedStructure())),
-                        node->child1());
+
+            // If we hadn't exited because of BadCache, BadIndexingType, or ExoticObjectMode, then
+            // leave this as a GetById.
+            if (!m_graph.hasExitSite(node->origin.semantic, BadCache)
+                && !m_graph.hasExitSite(node->origin.semantic, BadIndexingType)
+                && !m_graph.hasExitSite(node->origin.semantic, ExoticObjectMode)) {
+                auto uid = m_graph.identifiers()[node->identifierNumber()];
+                if (uid == vm().propertyNames->length.impl()) {
+                    attemptToMakeGetArrayLength(node);
+                    break;
+                }
+                if (uid == vm().propertyNames->byteLength.impl()) {
+                    attemptToMakeGetTypedArrayByteLength(node);
+                    break;
+                }
+                if (uid == vm().propertyNames->byteOffset.impl()) {
+                    attemptToMakeGetTypedArrayByteOffset(node);
+                    break;
                 }
-            } else
-                arrayMode = arrayMode.refine(node->child1()->prediction(), node->prediction());
-            
-            if (arrayMode.type() == Array::Generic) {
-                // Check if the input is something that we can't get array length for, but for which we
-                // could insert some conversions in order to transform it into something that we can do it
-                // for.
-                if (node->child1()->shouldSpeculateStringObject())
-                    attemptToForceStringArrayModeByToStringConversion<StringObjectUse>(arrayMode, node);
-                else if (node->child1()->shouldSpeculateStringOrStringObject())
-                    attemptToForceStringArrayModeByToStringConversion<StringOrStringObjectUse>(arrayMode, node);
             }
-            
-            if (!arrayMode.supportsLength())
-                break;
-            node->setOp(GetArrayLength);
-            ASSERT(node->flags() & NodeMustGenerate);
-            node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
-            setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child1());
-            node->setArrayMode(arrayMode);
-            
-            Node* storage = checkArray(arrayMode, node->codeOrigin, node->child1().node(), 0, lengthNeedsStorage);
-            if (!storage)
-                break;
-            
-            node->child2() = Edge(storage);
+            fixEdge<CellUse>(node->child1());
             break;
         }
             
-        case GetByIdFlush: {
-            if (node->child1()->shouldSpeculateCell())
-                setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
+        case PutById:
+        case PutByIdFlush:
+        case PutByIdDirect: {
+            fixEdge<CellUse>(node->child1());
+            speculateForBarrier(node->child2());
             break;
         }
-            
-        case CheckExecutable:
-        case CheckStructure:
-        case ForwardCheckStructure:
-        case StructureTransitionWatchpoint:
-        case ForwardStructureTransitionWatchpoint:
-        case CheckFunction:
-        case PutById:
-        case PutByIdDirect:
-        case CheckHasInstance: {
-            setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
+
+        case GetExecutable: {
+            fixEdge<FunctionUse>(node->child1());
             break;
         }
             
-        case CheckArray: {
-            switch (node->arrayMode().type()) {
-            case Array::String:
-                setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
-                break;
-            default:
-                setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
-                break;
-            }
+        case CheckStructure:
+        case CheckCell:
+        case CheckHasInstance:
+        case CreateThis:
+        case GetButterfly: {
+            fixEdge<CellUse>(node->child1());
             break;
         }
             
         case Arrayify:
         case ArrayifyToStructure: {
-            setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
+            fixEdge<CellUse>(node->child1());
             if (node->child2())
-                setUseKindAndUnboxIfProfitable<Int32Use>(node->child2());
+                fixEdge<Int32Use>(node->child2());
             break;
         }
             
-        case GetByOffset: {
+        case GetByOffset:
+        case GetGetterSetterByOffset: {
             if (!node->child1()->hasStorageResult())
-                setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child1());
+                fixEdge<KnownCellUse>(node->child1());
+            fixEdge<KnownCellUse>(node->child2());
+            break;
+        }
+            
+        case MultiGetByOffset: {
+            fixEdge<CellUse>(node->child1());
             break;
         }
             
         case PutByOffset: {
             if (!node->child1()->hasStorageResult())
-                setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child1());
-            setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child2());
+                fixEdge<KnownCellUse>(node->child1());
+            fixEdge<KnownCellUse>(node->child2());
+            speculateForBarrier(node->child3());
+            break;
+        }
+            
+        case MultiPutByOffset: {
+            fixEdge<CellUse>(node->child1());
+            speculateForBarrier(node->child2());
             break;
         }
             
         case InstanceOf: {
-            // FIXME: This appears broken: CheckHasInstance already does an unconditional cell
-            // check. https://bugs.webkit.org/show_bug.cgi?id=107479
             if (!(node->child1()->prediction() & ~SpecCell))
-                setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
-            setUseKindAndUnboxIfProfitable<CellUse>(node->child2());
+                fixEdge<CellUse>(node->child1());
+            fixEdge<CellUse>(node->child2());
+            break;
+        }
+            
+        case In: {
+            // FIXME: We should at some point have array profiling on op_in, in which
+            // case we would be able to turn this into a kind of GetByVal.
+            
+            fixEdge<CellUse>(node->child2());
+            break;
+        }
+
+        case Check: {
+            m_graph.doToChildren(
+                node,
+                [&] (Edge& edge) {
+                    switch (edge.useKind()) {
+                    case NumberUse:
+                        if (edge->shouldSpeculateInt32ForArithmetic())
+                            edge.setUseKind(Int32Use);
+                        break;
+                    default:
+                        break;
+                    }
+                    observeUseKindOnEdge(edge);
+                });
             break;
         }
 
         case Phantom:
-        case Identity: {
-            switch (node->child1().useKind()) {
-            case NumberUse:
-                if (node->child1()->shouldSpeculateIntegerForArithmetic())
-                    node->child1().setUseKind(Int32Use);
-                break;
-            default:
-                break;
-            }
-            observeUseKindOnEdge(node->child1());
+            // Phantoms are meaningless past Fixup. We recreate them on-demand in the backend.
+            node->remove();
+            break;
+
+        case FiatInt52: {
+            RELEASE_ASSERT(enableInt52());
+            node->convertToIdentity();
+            fixEdge<Int52RepUse>(node->child1());
+            node->setResult(NodeResultInt52);
             break;
         }
 
         case GetArrayLength:
-        case Nop:
         case Phi:
-        case ForwardInt32ToDouble:
-        case PhantomPutStructure:
+        case Upsilon:
         case GetIndexedPropertyStorage:
+        case GetTypedArrayByteOffset:
         case LastNodeType:
-        case MovHint:
-        case MovHintAndCheck:
-        case ZombieHint:
-            RELEASE_ASSERT_NOT_REACHED();
+        case CheckTierUpInLoop:
+        case CheckTierUpAtReturn:
+        case CheckTierUpAndOSREnter:
+        case CheckTierUpWithNestedTriggerAndOSREnter:
+        case InvalidationPoint:
+        case CheckArray:
+        case CheckInBounds:
+        case ConstantStoragePointer:
+        case DoubleAsInt32:
+        case ValueToInt32:
+        case DoubleRep:
+        case ValueRep:
+        case Int52Rep:
+        case Int52Constant:
+        case Identity: // This should have been cleaned up.
+        case BooleanToNumber:
+        case PhantomNewObject:
+        case PhantomNewFunction:
+        case PhantomCreateActivation:
+        case PhantomDirectArguments:
+        case PhantomClonedArguments:
+        case ForwardVarargs:
+        case GetMyArgumentByVal:
+        case PutHint:
+        case CheckStructureImmediate:
+        case MaterializeNewObject:
+        case MaterializeCreateActivation:
+        case PutStack:
+        case KillStack:
+        case GetStack:
+        case StoreBarrier:
+            // These are just nodes that we don't currently expect to see during fixup.
+            // If we ever wanted to insert them prior to fixup, then we just have to create
+            // fixup rules for them.
+            DFG_CRASH(m_graph, node, "Unexpected node during fixup");
             break;
         
-#if !ASSERT_DISABLED    
+        case PutGlobalVar: {
+            fixEdge<CellUse>(node->child1());
+            speculateForBarrier(node->child2());
+            break;
+        }
+
+        case IsString:
+            if (node->child1()->shouldSpeculateString()) {
+                m_insertionSet.insertNode(
+                    m_indexInBlock, SpecNone, Check, node->origin,
+                    Edge(node->child1().node(), StringUse));
+                m_graph.convertToConstant(node, jsBoolean(true));
+                observeUseKindOnNode<StringUse>(node);
+            }
+            break;
+
+        case IsObject:
+            if (node->child1()->shouldSpeculateObject()) {
+                m_insertionSet.insertNode(
+                    m_indexInBlock, SpecNone, Check, node->origin,
+                    Edge(node->child1().node(), ObjectUse));
+                m_graph.convertToConstant(node, jsBoolean(true));
+                observeUseKindOnNode<ObjectUse>(node);
+            }
+            break;
+
+        case GetEnumerableLength: {
+            fixEdge<CellUse>(node->child1());
+            break;
+        }
+        case HasGenericProperty: {
+            fixEdge<CellUse>(node->child2());
+            break;
+        }
+        case HasStructureProperty: {
+            fixEdge<StringUse>(node->child2());
+            fixEdge<KnownCellUse>(node->child3());
+            break;
+        }
+        case HasIndexedProperty: {
+            node->setArrayMode(
+                node->arrayMode().refine(
+                    m_graph, node,
+                    node->child1()->prediction(),
+                    node->child2()->prediction(),
+                    SpecNone));
+            
+            blessArrayOperation(node->child1(), node->child2(), node->child3());
+            fixEdge<CellUse>(node->child1());
+            fixEdge<KnownInt32Use>(node->child2());
+            break;
+        }
+        case GetDirectPname: {
+            Edge& base = m_graph.varArgChild(node, 0);
+            Edge& property = m_graph.varArgChild(node, 1);
+            Edge& index = m_graph.varArgChild(node, 2);
+            Edge& enumerator = m_graph.varArgChild(node, 3);
+            fixEdge<CellUse>(base);
+            fixEdge<KnownCellUse>(property);
+            fixEdge<KnownInt32Use>(index);
+            fixEdge<KnownCellUse>(enumerator);
+            break;
+        }
+        case GetPropertyEnumerator: {
+            fixEdge<CellUse>(node->child1());
+            break;
+        }
+        case GetEnumeratorStructurePname: {
+            fixEdge<KnownCellUse>(node->child1());
+            fixEdge<KnownInt32Use>(node->child2());
+            break;
+        }
+        case GetEnumeratorGenericPname: {
+            fixEdge<KnownCellUse>(node->child1());
+            fixEdge<KnownInt32Use>(node->child2());
+            break;
+        }
+        case ToIndexString: {
+            fixEdge<KnownInt32Use>(node->child1());
+            break;
+        }
+        case ProfileType: {
+            // We want to insert type checks based on the instructionTypeSet of the TypeLocation, not the globalTypeSet.
+            // Because the instructionTypeSet is contained in globalTypeSet, if we produce a type check for
+            // type T for the instructionTypeSet, the global type set must also have information for type T.
+            // So if it the type check succeeds for type T in the instructionTypeSet, a type check for type T 
+            // in the globalTypeSet would've also succeeded.
+            // (The other direction does not hold in general).
+
+            RefPtr<TypeSet> typeSet = node->typeLocation()->m_instructionTypeSet;
+            RuntimeTypeMask seenTypes = typeSet->seenTypes();
+            if (typeSet->doesTypeConformTo(TypeMachineInt)) {
+                if (node->child1()->shouldSpeculateInt32())
+                    fixEdge<Int32Use>(node->child1());
+                else
+                    fixEdge<MachineIntUse>(node->child1());
+                node->remove();
+            } else if (typeSet->doesTypeConformTo(TypeNumber | TypeMachineInt)) {
+                fixEdge<NumberUse>(node->child1());
+                node->remove();
+            } else if (typeSet->doesTypeConformTo(TypeString)) {
+                fixEdge<StringUse>(node->child1());
+                node->remove();
+            } else if (typeSet->doesTypeConformTo(TypeBoolean)) {
+                fixEdge<BooleanUse>(node->child1());
+                node->remove();
+            } else if (typeSet->doesTypeConformTo(TypeUndefined | TypeNull) && (seenTypes & TypeUndefined) && (seenTypes & TypeNull)) {
+                fixEdge<OtherUse>(node->child1());
+                node->remove();
+            } else if (typeSet->doesTypeConformTo(TypeObject)) {
+                StructureSet set = typeSet->structureSet();
+                if (!set.isEmpty()) {
+                    fixEdge<CellUse>(node->child1());
+                    node->convertToCheckStructure(m_graph.addStructureSet(set));
+                }
+            }
+
+            break;
+        }
+
+        case CreateScopedArguments:
+        case CreateActivation:
+        case NewFunction: {
+            fixEdge<CellUse>(node->child1());
+            break;
+        }
+            
+#if !ASSERT_DISABLED
         // Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes.
         case SetArgument:
         case JSConstant:
-        case WeakJSConstant:
+        case DoubleConstant:
         case GetLocal:
         case GetCallee:
+        case GetArgumentCount:
         case Flush:
         case PhantomLocal:
         case GetLocalUnlinked:
-        case InlineStart:
-        case GetMyScope:
-        case GetScopedVar:
         case GetGlobalVar:
-        case PutGlobalVar:
-        case GlobalVarWatchpoint:
-        case PutGlobalVarCheck:
-        case AllocationProfileWatchpoint:
+        case NotifyWrite:
+        case VarInjectionWatchpoint:
         case Call:
         case Construct:
+        case CallVarargs:
+        case ConstructVarargs:
+        case CallForwardVarargs:
+        case ConstructForwardVarargs:
+        case LoadVarargs:
+        case ProfileControlFlow:
+        case NativeCall:
+        case NativeConstruct:
         case NewObject:
         case NewArrayBuffer:
         case NewRegexp:
-        case Resolve:
-        case ResolveBase:
-        case ResolveBaseStrictPut:
-        case ResolveGlobal:
         case Breakpoint:
+        case ProfileWillCall:
+        case ProfileDidCall:
         case IsUndefined:
         case IsBoolean:
         case IsNumber:
-        case IsString:
-        case IsObject:
+        case IsObjectOrNull:
         case IsFunction:
-        case CreateActivation:
-        case TearOffActivation:
-        case CreateArguments:
-        case PhantomArguments:
-        case TearOffArguments:
-        case GetMyArgumentsLength:
-        case GetMyArgumentsLengthSafe:
-        case CheckArgumentsNotCreated:
-        case NewFunction:
-        case NewFunctionNoCheck:
-        case NewFunctionExpression:
+        case CreateDirectArguments:
+        case CreateClonedArguments:
         case Jump:
         case Return:
         case Throw:
         case ThrowReferenceError:
-        case GarbageValue:
         case CountExecution:
         case ForceOSRExit:
+        case CheckBadCell:
+        case CheckNotEmpty:
         case CheckWatchdogTimer:
         case Unreachable:
+        case ExtractOSREntryLocal:
+        case LoopHint:
+        case MovHint:
+        case ZombieHint:
+        case BottomValue:
+        case TypeOf:
             break;
 #else
         default:
             break;
 #endif
         }
-
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-        if (!(node->flags() & NodeHasVarArgs)) {
-            dataLogF("new children: ");
-            node->dumpChildren(WTF::dataFile());
-        }
-        dataLogF("\n");
-#endif
     }
     
     template<UseKind useKind>
     void createToString(Node* node, Edge& edge)
     {
         edge.setNode(m_insertionSet.insertNode(
-            m_indexInBlock, SpecString, ToString, node->codeOrigin,
+            m_indexInBlock, SpecString, ToString, node->origin,
             Edge(edge.node(), useKind)));
     }
     
@@ -904,7 +1337,7 @@ private:
     {
         ASSERT(arrayMode == ArrayMode(Array::Generic));
         
-        if (!canOptimizeStringObjectAccess(node->codeOrigin))
+        if (!canOptimizeStringObjectAccess(node->origin.semantic))
             return;
         
         createToString<useKind>(node, node->child1());
@@ -932,7 +1365,7 @@ private:
             // decision process much easier.
             observeUseKindOnNode<StringUse>(edge.node());
             m_insertionSet.insertNode(
-                m_indexInBlock, SpecNone, Phantom, node->codeOrigin,
+                m_indexInBlock, SpecNone, Check, node->origin,
                 Edge(edge.node(), StringUse));
             edge.setUseKind(KnownStringUse);
             return;
@@ -957,9 +1390,9 @@ private:
             if (!edge)
                 break;
             edge.setUseKind(KnownStringUse);
-            if (!m_graph.isConstant(edge.node()))
+            JSString* string = edge->dynamicCastConstant<JSString*>();
+            if (!string)
                 continue;
-            JSString* string = jsCast<JSString*>(m_graph.valueOfJSConstant(edge.node()).asCell());
             if (string->length())
                 continue;
             
@@ -978,55 +1411,55 @@ private:
     
     void fixupToPrimitive(Node* node)
     {
-        if (node->child1()->shouldSpeculateInteger()) {
-            setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
+        if (node->child1()->shouldSpeculateInt32()) {
+            fixEdge<Int32Use>(node->child1());
             node->convertToIdentity();
             return;
         }
         
         if (node->child1()->shouldSpeculateString()) {
-            setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
+            fixEdge<StringUse>(node->child1());
             node->convertToIdentity();
             return;
         }
         
         if (node->child1()->shouldSpeculateStringObject()
-            && canOptimizeStringObjectAccess(node->codeOrigin)) {
-            setUseKindAndUnboxIfProfitable<StringObjectUse>(node->child1());
+            && canOptimizeStringObjectAccess(node->origin.semantic)) {
+            fixEdge<StringObjectUse>(node->child1());
             node->convertToToString();
             return;
         }
         
         if (node->child1()->shouldSpeculateStringOrStringObject()
-            && canOptimizeStringObjectAccess(node->codeOrigin)) {
-            setUseKindAndUnboxIfProfitable<StringOrStringObjectUse>(node->child1());
+            && canOptimizeStringObjectAccess(node->origin.semantic)) {
+            fixEdge<StringOrStringObjectUse>(node->child1());
             node->convertToToString();
             return;
         }
     }
     
-    void fixupToString(Node* node)
+    void fixupToStringOrCallStringConstructor(Node* node)
     {
         if (node->child1()->shouldSpeculateString()) {
-            setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
+            fixEdge<StringUse>(node->child1());
             node->convertToIdentity();
             return;
         }
         
         if (node->child1()->shouldSpeculateStringObject()
-            && canOptimizeStringObjectAccess(node->codeOrigin)) {
-            setUseKindAndUnboxIfProfitable<StringObjectUse>(node->child1());
+            && canOptimizeStringObjectAccess(node->origin.semantic)) {
+            fixEdge<StringObjectUse>(node->child1());
             return;
         }
         
         if (node->child1()->shouldSpeculateStringOrStringObject()
-            && canOptimizeStringObjectAccess(node->codeOrigin)) {
-            setUseKindAndUnboxIfProfitable<StringOrStringObjectUse>(node->child1());
+            && canOptimizeStringObjectAccess(node->origin.semantic)) {
+            fixEdge<StringOrStringObjectUse>(node->child1());
             return;
         }
         
         if (node->child1()->shouldSpeculateCell()) {
-            setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
+            fixEdge<CellUse>(node->child1());
             return;
         }
     }
@@ -1034,21 +1467,18 @@ private:
     template<UseKind leftUseKind>
     bool attemptToMakeFastStringAdd(Node* node, Edge& left, Edge& right)
     {
-        Node* originalLeft = left.node();
-        Node* originalRight = right.node();
-        
         ASSERT(leftUseKind == StringUse || leftUseKind == StringObjectUse || leftUseKind == StringOrStringObjectUse);
         
-        if (isStringObjectUse<leftUseKind>() && !canOptimizeStringObjectAccess(node->codeOrigin))
+        if (isStringObjectUse<leftUseKind>() && !canOptimizeStringObjectAccess(node->origin.semantic))
             return false;
         
         convertStringAddUse<leftUseKind>(node, left);
         
         if (right->shouldSpeculateString())
             convertStringAddUse<StringUse>(node, right);
-        else if (right->shouldSpeculateStringObject() && canOptimizeStringObjectAccess(node->codeOrigin))
+        else if (right->shouldSpeculateStringObject() && canOptimizeStringObjectAccess(node->origin.semantic))
             convertStringAddUse<StringObjectUse>(node, right);
-        else if (right->shouldSpeculateStringOrStringObject() && canOptimizeStringObjectAccess(node->codeOrigin))
+        else if (right->shouldSpeculateStringOrStringObject() && canOptimizeStringObjectAccess(node->origin.semantic))
             convertStringAddUse<StringOrStringObjectUse>(node, right);
         else {
             // At this point we know that the other operand is something weird. The semantically correct
@@ -1060,43 +1490,43 @@ private:
             // anything to @right, since ToPrimitive may be effectful.
             
             Node* toPrimitive = m_insertionSet.insertNode(
-                m_indexInBlock, resultOfToPrimitive(right->prediction()), ToPrimitive, node->codeOrigin,
-                Edge(right.node()));
+                m_indexInBlock, resultOfToPrimitive(right->prediction()), ToPrimitive,
+                node->origin, Edge(right.node()));
             Node* toString = m_insertionSet.insertNode(
-                m_indexInBlock, SpecString, ToString, node->codeOrigin, Edge(toPrimitive));
+                m_indexInBlock, SpecString, ToString, node->origin, Edge(toPrimitive));
             
             fixupToPrimitive(toPrimitive);
-            fixupToString(toString);
-            
+
+            // Don't fix up ToString. ToString and ToPrimitive are originated from the same bytecode and
+            // ToPrimitive may have an observable side effect. ToString should not be converted into Check
+            // with speculative type check because OSR exit reproduce an observable side effect done in
+            // ToPrimitive.
+
             right.setNode(toString);
         }
         
-        // We're doing checks up there, so we need to make sure that the
-        // *original* inputs to the addition are live up to here.
-        m_insertionSet.insertNode(
-            m_indexInBlock, SpecNone, Phantom, node->codeOrigin,
-            Edge(originalLeft), Edge(originalRight));
-        
         convertToMakeRope(node);
         return true;
     }
     
-    bool isStringPrototypeMethodSane(Structure* stringPrototypeStructure, const Identifier& ident)
+    bool isStringPrototypeMethodSane(
+        JSObject* stringPrototype, Structure* stringPrototypeStructure, UniquedStringImpl* uid)
     {
         unsigned attributesUnused;
-        JSCell* specificValue;
-        PropertyOffset offset = stringPrototypeStructure->get(
-            vm(), ident, attributesUnused, specificValue);
+        PropertyOffset offset =
+            stringPrototypeStructure->getConcurrently(uid, attributesUnused);
         if (!isValidOffset(offset))
             return false;
         
-        if (!specificValue)
+        JSValue value = m_graph.tryGetConstantProperty(
+            stringPrototype, stringPrototypeStructure, offset);
+        if (!value)
             return false;
         
-        if (!specificValue->inherits(&JSFunction::s_info))
+        JSFunction* function = jsDynamicCast<JSFunction*>(value);
+        if (!function)
             return false;
         
-        JSFunction* function = jsCast<JSFunction*>(specificValue);
         if (function->executable()->intrinsicFor(CodeForCall) != StringPrototypeValueOfIntrinsic)
             return false;
         
@@ -1110,11 +1540,11 @@ private:
         
         Structure* stringObjectStructure = m_graph.globalObjectFor(codeOrigin)->stringObjectStructure();
         ASSERT(stringObjectStructure->storedPrototype().isObject());
-        ASSERT(stringObjectStructure->storedPrototype().asCell()->classInfo() == &StringPrototype::s_info);
+        ASSERT(stringObjectStructure->storedPrototype().asCell()->classInfo() == StringPrototype::info());
         
         JSObject* stringPrototypeObject = asObject(stringObjectStructure->storedPrototype());
         Structure* stringPrototypeStructure = stringPrototypeObject->structure();
-        if (stringPrototypeStructure->transitionWatchpointSetHasBeenInvalidated())
+        if (m_graph.registerStructure(stringPrototypeStructure) != StructureRegisteredAndWatched)
             return false;
         
         if (stringPrototypeStructure->isDictionary())
@@ -1125,15 +1555,15 @@ private:
         // (that would call toString()). We don't want the DFG to have to distinguish
         // between the two, just because that seems like it would get confusing. So we
         // just require both methods to be sane.
-        if (!isStringPrototypeMethodSane(stringPrototypeStructure, vm().propertyNames->valueOf))
+        if (!isStringPrototypeMethodSane(stringPrototypeObject, stringPrototypeStructure, vm().propertyNames->valueOf.impl()))
             return false;
-        if (!isStringPrototypeMethodSane(stringPrototypeStructure, vm().propertyNames->toString))
+        if (!isStringPrototypeMethodSane(stringPrototypeObject, stringPrototypeStructure, vm().propertyNames->toString.impl()))
             return false;
         
         return true;
     }
     
-    void fixupSetLocalsInBlock(BasicBlock* block)
+    void fixupGetAndSetLocalsInBlock(BasicBlock* block)
     {
         if (!block)
             return;
@@ -1141,83 +1571,91 @@ private:
         m_block = block;
         for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) {
             Node* node = m_currentNode = block->at(m_indexInBlock);
-            if (node->op() != SetLocal)
+            if (node->op() != SetLocal && node->op() != GetLocal)
                 continue;
             
             VariableAccessData* variable = node->variableAccessData();
-            
-            if (!variable->shouldUnboxIfPossible())
-                continue;
-            
-            if (variable->shouldUseDoubleFormat()) {
-                fixDoubleEdge<NumberUse>(node->child1(), ForwardSpeculation);
-                continue;
+            switch (node->op()) {
+            case GetLocal:
+                switch (variable->flushFormat()) {
+                case FlushedDouble:
+                    node->setResult(NodeResultDouble);
+                    break;
+                case FlushedInt52:
+                    node->setResult(NodeResultInt52);
+                    break;
+                default:
+                    break;
+                }
+                break;
+                
+            case SetLocal:
+                switch (variable->flushFormat()) {
+                case FlushedJSValue:
+                    break;
+                case FlushedDouble:
+                    fixEdge<DoubleRepUse>(node->child1());
+                    break;
+                case FlushedInt32:
+                    fixEdge<Int32Use>(node->child1());
+                    break;
+                case FlushedInt52:
+                    fixEdge<Int52RepUse>(node->child1());
+                    break;
+                case FlushedCell:
+                    fixEdge<CellUse>(node->child1());
+                    break;
+                case FlushedBoolean:
+                    fixEdge<BooleanUse>(node->child1());
+                    break;
+                default:
+                    RELEASE_ASSERT_NOT_REACHED();
+                    break;
+                }
+                break;
+                
+            default:
+                RELEASE_ASSERT_NOT_REACHED();
+                break;
             }
-            
-            SpeculatedType predictedType = variable->argumentAwarePrediction();
-            if (isInt32Speculation(predictedType))
-                setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
-            else if (isCellSpeculation(predictedType))
-                setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
-            else if (isBooleanSpeculation(predictedType))
-                setUseKindAndUnboxIfProfitable<BooleanUse>(node->child1());
         }
         m_insertionSet.execute(block);
     }
     
-    void findAndRemoveUnnecessaryStructureCheck(Node* array, const CodeOrigin& codeOrigin)
-    {
-        for (unsigned index = m_indexInBlock; index--;) {
-            Node* previousNode = m_block->at(index);
-            if (previousNode->codeOrigin != codeOrigin)
-                return;
-            
-            if (previousNode->op() != CheckStructure)
-                continue;
-            
-            if (previousNode->child1() != array)
-                continue;
-            
-            previousNode->child1() = Edge();
-            previousNode->convertToPhantom();
-            return; // Assume we were smart enough to only insert one CheckStructure on the array.
-        }
-    }
-    
-    Node* checkArray(ArrayMode arrayMode, const CodeOrigin& codeOrigin, Node* array, Node* index, bool (*storageCheck)(const ArrayMode&) = canCSEStorage)
+    Node* checkArray(ArrayMode arrayMode, const NodeOrigin& origin, Node* array, Node* index, bool (*storageCheck)(const ArrayMode&) = canCSEStorage)
     {
         ASSERT(arrayMode.isSpecific());
         
-        Structure* structure = arrayMode.originalArrayStructure(m_graph, codeOrigin);
-        
-        Edge indexEdge = index ? Edge(index, Int32Use) : Edge();
+        if (arrayMode.type() == Array::String) {
+            m_insertionSet.insertNode(
+                m_indexInBlock, SpecNone, Check, origin, Edge(array, StringUse));
+        } else {
+            // Note that we only need to be using a structure check if we opt for SaneChain, since
+            // that needs to protect against JSArray's __proto__ being changed.
+            Structure* structure = arrayMode.originalArrayStructure(m_graph, origin.semantic);
         
-        if (arrayMode.doesConversion()) {
-            if (structure) {
-                if (m_indexInBlock > 0) {
-                    // If the previous node was a CheckStructure inserted because of stuff
-                    // that the array profile told us, then remove it, since we're going to be
-                    // doing arrayification instead.
-                    findAndRemoveUnnecessaryStructureCheck(array, codeOrigin);
+            Edge indexEdge = index ? Edge(index, Int32Use) : Edge();
+            
+            if (arrayMode.doesConversion()) {
+                if (structure) {
+                    m_insertionSet.insertNode(
+                        m_indexInBlock, SpecNone, ArrayifyToStructure, origin,
+                        OpInfo(structure), OpInfo(arrayMode.asWord()), Edge(array, CellUse), indexEdge);
+                } else {
+                    m_insertionSet.insertNode(
+                        m_indexInBlock, SpecNone, Arrayify, origin,
+                        OpInfo(arrayMode.asWord()), Edge(array, CellUse), indexEdge);
                 }
-                
-                m_insertionSet.insertNode(
-                    m_indexInBlock, SpecNone, ArrayifyToStructure, codeOrigin,
-                    OpInfo(structure), OpInfo(arrayMode.asWord()), Edge(array, CellUse), indexEdge);
-            } else {
-                m_insertionSet.insertNode(
-                    m_indexInBlock, SpecNone, Arrayify, codeOrigin,
-                    OpInfo(arrayMode.asWord()), Edge(array, CellUse), indexEdge);
-            }
-        } else {
-            if (structure) {
-                m_insertionSet.insertNode(
-                    m_indexInBlock, SpecNone, CheckStructure, codeOrigin,
-                    OpInfo(m_graph.addStructureSet(structure)), Edge(array, CellUse));
             } else {
-                m_insertionSet.insertNode(
-                    m_indexInBlock, SpecNone, CheckArray, codeOrigin,
-                    OpInfo(arrayMode.asWord()), Edge(array, CellUse));
+                if (structure) {
+                    m_insertionSet.insertNode(
+                        m_indexInBlock, SpecNone, CheckStructure, origin,
+                        OpInfo(m_graph.addStructureSet(structure)), Edge(array, CellUse));
+                } else {
+                    m_insertionSet.insertNode(
+                        m_indexInBlock, SpecNone, CheckArray, origin,
+                        OpInfo(arrayMode.asWord()), Edge(array, CellUse));
+                }
             }
         }
         
@@ -1226,11 +1664,11 @@ private:
         
         if (arrayMode.usesButterfly()) {
             return m_insertionSet.insertNode(
-                m_indexInBlock, SpecNone, GetButterfly, codeOrigin, Edge(array, KnownCellUse));
+                m_indexInBlock, SpecNone, GetButterfly, origin, Edge(array, CellUse));
         }
         
         return m_insertionSet.insertNode(
-            m_indexInBlock, SpecNone, GetIndexedPropertyStorage, codeOrigin,
+            m_indexInBlock, SpecNone, GetIndexedPropertyStorage, origin,
             OpInfo(arrayMode.asWord()), Edge(array, KnownCellUse));
     }
     
@@ -1241,7 +1679,7 @@ private:
         switch (node->arrayMode().type()) {
         case Array::ForceExit: {
             m_insertionSet.insertNode(
-                m_indexInBlock, SpecNone, ForceOSRExit, node->codeOrigin);
+                m_indexInBlock, SpecNone, ForceOSRExit, node->origin);
             return;
         }
             
@@ -1251,11 +1689,10 @@ private:
             return;
             
         case Array::Generic:
-            findAndRemoveUnnecessaryStructureCheck(base.node(), node->codeOrigin);
             return;
             
         default: {
-            Node* storage = checkArray(node->arrayMode(), node->codeOrigin, base.node(), index.node());
+            Node* storage = checkArray(node->arrayMode(), node->origin, base.node(), index.node());
             if (!storage)
                 return;
             
@@ -1278,6 +1715,8 @@ private:
     template<UseKind useKind>
     void observeUseKindOnNode(Node* node)
     {
+        if (useKind == UntypedUse)
+            return;
         observeUseKindOnNode(node, useKind);
     }
 
@@ -1291,6 +1730,9 @@ private:
         if (node->op() != GetLocal)
             return;
         
+        // FIXME: The way this uses alwaysUnboxSimplePrimitives() is suspicious.
+        // https://bugs.webkit.org/show_bug.cgi?id=121518
+        
         VariableAccessData* variable = node->variableAccessData();
         switch (useKind) {
         case Int32Use:
@@ -1300,6 +1742,8 @@ private:
             break;
         case NumberUse:
         case RealNumberUse:
+        case DoubleRepUse:
+        case DoubleRepRealUse:
             if (variable->doubleFormatState() == UsingDoubleFormat)
                 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
             break;
@@ -1308,8 +1752,14 @@ private:
                 || isBooleanSpeculation(variable->prediction()))
                 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
             break;
+        case Int52RepUse:
+            if (isMachineIntSpeculation(variable->prediction()))
+                m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
+            break;
         case CellUse:
+        case KnownCellUse:
         case ObjectUse:
+        case FunctionUse:
         case StringUse:
         case KnownStringUse:
         case StringObjectUse:
@@ -1323,82 +1773,136 @@ private:
         }
     }
     
-    // Set the use kind of the edge. In the future (https://bugs.webkit.org/show_bug.cgi?id=110433),
-    // this can be used to notify the GetLocal that the variable is profitable to unbox.
     template<UseKind useKind>
-    void setUseKindAndUnboxIfProfitable(Edge& edge)
+    void fixEdge(Edge& edge)
     {
         observeUseKindOnNode<useKind>(edge.node());
         edge.setUseKind(useKind);
     }
     
-    void fixIntEdge(Edge& edge)
+    void speculateForBarrier(Edge value)
     {
-        Node* node = edge.node();
-        if (node->op() != ValueToInt32) {
-            setUseKindAndUnboxIfProfitable<KnownInt32Use>(edge);
+        // Currently, the DFG won't take advantage of this speculation. But, we want to do it in
+        // the DFG anyway because if such a speculation would be wrong, we want to know before
+        // we do an expensive compile.
+        
+        if (value->shouldSpeculateInt32()) {
+            insertCheck<Int32Use>(m_indexInBlock, value.node());
             return;
         }
-        
-        Edge newEdge = node->child1();
-        
-        if (newEdge.useKind() != Int32Use) {
-            edge.setUseKind(KnownInt32Use);
+            
+        if (value->shouldSpeculateBoolean()) {
+            insertCheck<BooleanUse>(m_indexInBlock, value.node());
+            return;
+        }
+            
+        if (value->shouldSpeculateOther()) {
+            insertCheck<OtherUse>(m_indexInBlock, value.node());
+            return;
+        }
+            
+        if (value->shouldSpeculateNumber()) {
+            insertCheck<NumberUse>(m_indexInBlock, value.node());
+            return;
+        }
+            
+        if (value->shouldSpeculateNotCell()) {
+            insertCheck<NotCellUse>(m_indexInBlock, value.node());
             return;
         }
-        
-        ASSERT(newEdge->shouldSpeculateInteger());
-        edge = newEdge;
     }
     
     template<UseKind useKind>
-    void fixDoubleEdge(Edge& edge, SpeculationDirection direction = BackwardSpeculation)
+    void insertCheck(unsigned indexInBlock, Node* node)
     {
-        ASSERT(useKind == NumberUse || useKind == KnownNumberUse || useKind == RealNumberUse);
+        observeUseKindOnNode<useKind>(node);
+        m_insertionSet.insertNode(
+            indexInBlock, SpecNone, Check, m_currentNode->origin, Edge(node, useKind));
+    }
+
+    void fixIntConvertingEdge(Edge& edge)
+    {
+        Node* node = edge.node();
+        if (node->shouldSpeculateInt32OrBoolean()) {
+            fixIntOrBooleanEdge(edge);
+            return;
+        }
         
-        if (edge->prediction() & SpecDouble) {
-            setUseKindAndUnboxIfProfitable<useKind>(edge);
+        UseKind useKind;
+        if (node->shouldSpeculateMachineInt())
+            useKind = Int52RepUse;
+        else if (node->shouldSpeculateNumber())
+            useKind = DoubleRepUse;
+        else
+            useKind = NotCellUse;
+        Node* newNode = m_insertionSet.insertNode(
+            m_indexInBlock, SpecInt32, ValueToInt32, m_currentNode->origin,
+            Edge(node, useKind));
+        observeUseKindOnNode(node, useKind);
+        
+        edge = Edge(newNode, KnownInt32Use);
+    }
+    
+    void fixIntOrBooleanEdge(Edge& edge)
+    {
+        Node* node = edge.node();
+        if (!node->sawBooleans()) {
+            fixEdge<Int32Use>(edge);
             return;
         }
         
-        injectInt32ToDoubleNode(edge, useKind, direction);
+        UseKind useKind;
+        if (node->shouldSpeculateBoolean())
+            useKind = BooleanUse;
+        else
+            useKind = UntypedUse;
+        Node* newNode = m_insertionSet.insertNode(
+            m_indexInBlock, SpecInt32, BooleanToNumber, m_currentNode->origin,
+            Edge(node, useKind));
+        observeUseKindOnNode(node, useKind);
+        
+        edge = Edge(newNode, Int32Use);
     }
-
-    void injectInt32ToDoubleNode(Edge& edge, UseKind useKind = NumberUse, SpeculationDirection direction = BackwardSpeculation)
+    
+    void fixDoubleOrBooleanEdge(Edge& edge)
     {
-        Node* result = m_insertionSet.insertNode(
-            m_indexInBlock, SpecDouble, 
-            direction == BackwardSpeculation ? Int32ToDouble : ForwardInt32ToDouble,
-            m_currentNode->codeOrigin, Edge(edge.node(), NumberUse));
+        Node* node = edge.node();
+        if (!node->sawBooleans()) {
+            fixEdge<DoubleRepUse>(edge);
+            return;
+        }
         
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-        dataLogF(
-            "(replacing @%u->@%u with @%u->@%u) ",
-            m_currentNode->index(), edge->index(), m_currentNode->index(), result->index());
-#endif
-
-        edge = Edge(result, useKind);
+        UseKind useKind;
+        if (node->shouldSpeculateBoolean())
+            useKind = BooleanUse;
+        else
+            useKind = UntypedUse;
+        Node* newNode = m_insertionSet.insertNode(
+            m_indexInBlock, SpecInt32, BooleanToNumber, m_currentNode->origin,
+            Edge(node, useKind));
+        observeUseKindOnNode(node, useKind);
+        
+        edge = Edge(newNode, DoubleRepUse);
     }
     
     void truncateConstantToInt32(Edge& edge)
     {
         Node* oldNode = edge.node();
         
-        ASSERT(oldNode->hasConstant());
-        JSValue value = m_graph.valueOfJSConstant(oldNode);
+        JSValue value = oldNode->asJSValue();
         if (value.isInt32())
             return;
         
         value = jsNumber(JSC::toInt32(value.asNumber()));
         ASSERT(value.isInt32());
         edge.setNode(m_insertionSet.insertNode(
-            m_indexInBlock, SpecInt32, JSConstant, m_currentNode->codeOrigin,
-            OpInfo(codeBlock()->addOrFindConstant(value))));
+            m_indexInBlock, SpecInt32, JSConstant, m_currentNode->origin,
+            OpInfo(m_graph.freeze(value))));
     }
     
     void truncateConstantsIfNecessary(Node* node, AddSpeculationMode mode)
     {
-        if (mode != SpeculateIntegerAndTruncateConstants)
+        if (mode != SpeculateInt32AndTruncateConstants)
             return;
         
         ASSERT(node->child1()->hasConstant() || node->child2()->hasConstant());
@@ -1410,16 +1914,308 @@ private:
     
     bool attemptToMakeIntegerAdd(Node* node)
     {
-        AddSpeculationMode mode = m_graph.addSpeculationMode(node);
-        if (mode == DontSpeculateInteger)
+        AddSpeculationMode mode = m_graph.addSpeculationMode(node, FixupPass);
+        if (mode != DontSpeculateInt32) {
+            truncateConstantsIfNecessary(node, mode);
+            fixIntOrBooleanEdge(node->child1());
+            fixIntOrBooleanEdge(node->child2());
+            if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
+                node->setArithMode(Arith::Unchecked);
+            else
+                node->setArithMode(Arith::CheckOverflow);
+            return true;
+        }
+        
+        if (m_graph.addShouldSpeculateMachineInt(node)) {
+            fixEdge<Int52RepUse>(node->child1());
+            fixEdge<Int52RepUse>(node->child2());
+            node->setArithMode(Arith::CheckOverflow);
+            node->setResult(NodeResultInt52);
+            return true;
+        }
+        
+        return false;
+    }
+    
+    bool attemptToMakeGetArrayLength(Node* node)
+    {
+        if (!isInt32Speculation(node->prediction()))
+            return false;
+        CodeBlock* profiledBlock = m_graph.baselineCodeBlockFor(node->origin.semantic);
+        ArrayProfile* arrayProfile = 
+            profiledBlock->getArrayProfile(node->origin.semantic.bytecodeIndex);
+        ArrayMode arrayMode = ArrayMode(Array::SelectUsingPredictions);
+        if (arrayProfile) {
+            ConcurrentJITLocker locker(profiledBlock->m_lock);
+            arrayProfile->computeUpdatedPrediction(locker, profiledBlock);
+            arrayMode = ArrayMode::fromObserved(locker, arrayProfile, Array::Read, false);
+            if (arrayMode.type() == Array::Unprofiled) {
+                // For normal array operations, it makes sense to treat Unprofiled
+                // accesses as ForceExit and get more data rather than using
+                // predictions and then possibly ending up with a Generic. But here,
+                // we treat anything that is Unprofiled as Generic and keep the
+                // GetById. I.e. ForceExit = Generic. So, there is no harm - and only
+                // profit - from treating the Unprofiled case as
+                // SelectUsingPredictions.
+                arrayMode = ArrayMode(Array::SelectUsingPredictions);
+            }
+        }
+            
+        arrayMode = arrayMode.refine(
+            m_graph, node, node->child1()->prediction(), node->prediction());
+            
+        if (arrayMode.type() == Array::Generic) {
+            // Check if the input is something that we can't get array length for, but for which we
+            // could insert some conversions in order to transform it into something that we can do it
+            // for.
+            if (node->child1()->shouldSpeculateStringObject())
+                attemptToForceStringArrayModeByToStringConversion<StringObjectUse>(arrayMode, node);
+            else if (node->child1()->shouldSpeculateStringOrStringObject())
+                attemptToForceStringArrayModeByToStringConversion<StringOrStringObjectUse>(arrayMode, node);
+        }
+            
+        if (!arrayMode.supportsLength())
             return false;
         
-        truncateConstantsIfNecessary(node, mode);
-        setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
-        setUseKindAndUnboxIfProfitable<Int32Use>(node->child2());
+        convertToGetArrayLength(node, arrayMode);
         return true;
     }
+    
+    bool attemptToMakeGetTypedArrayByteLength(Node* node)
+    {
+        if (!isInt32Speculation(node->prediction()))
+            return false;
+        
+        TypedArrayType type = typedArrayTypeFromSpeculation(node->child1()->prediction());
+        if (!isTypedView(type))
+            return false;
+        
+        if (elementSize(type) == 1) {
+            convertToGetArrayLength(node, ArrayMode(toArrayType(type)));
+            return true;
+        }
+        
+        Node* length = prependGetArrayLength(
+            node->origin, node->child1().node(), ArrayMode(toArrayType(type)));
+        
+        Node* shiftAmount = m_insertionSet.insertNode(
+            m_indexInBlock, SpecInt32, JSConstant, node->origin,
+            OpInfo(m_graph.freeze(jsNumber(logElementSize(type)))));
+        
+        // We can use a BitLShift here because typed arrays will never have a byteLength
+        // that overflows int32.
+        node->setOp(BitLShift);
+        node->clearFlags(NodeMustGenerate);
+        observeUseKindOnNode(length, Int32Use);
+        observeUseKindOnNode(shiftAmount, Int32Use);
+        node->child1() = Edge(length, Int32Use);
+        node->child2() = Edge(shiftAmount, Int32Use);
+        return true;
+    }
+    
+    void convertToGetArrayLength(Node* node, ArrayMode arrayMode)
+    {
+        node->setOp(GetArrayLength);
+        node->clearFlags(NodeMustGenerate);
+        fixEdge<KnownCellUse>(node->child1());
+        node->setArrayMode(arrayMode);
+            
+        Node* storage = checkArray(arrayMode, node->origin, node->child1().node(), 0, lengthNeedsStorage);
+        if (!storage)
+            return;
+            
+        node->child2() = Edge(storage);
+    }
+    
+    Node* prependGetArrayLength(NodeOrigin origin, Node* child, ArrayMode arrayMode)
+    {
+        Node* storage = checkArray(arrayMode, origin, child, 0, lengthNeedsStorage);
+        return m_insertionSet.insertNode(
+            m_indexInBlock, SpecInt32, GetArrayLength, origin,
+            OpInfo(arrayMode.asWord()), Edge(child, KnownCellUse), Edge(storage));
+    }
+    
+    bool attemptToMakeGetTypedArrayByteOffset(Node* node)
+    {
+        if (!isInt32Speculation(node->prediction()))
+            return false;
+        
+        TypedArrayType type = typedArrayTypeFromSpeculation(node->child1()->prediction());
+        if (!isTypedView(type))
+            return false;
+        
+        checkArray(
+            ArrayMode(toArrayType(type)), node->origin, node->child1().node(),
+            0, neverNeedsStorage);
+        
+        node->setOp(GetTypedArrayByteOffset);
+        node->clearFlags(NodeMustGenerate);
+        fixEdge<KnownCellUse>(node->child1());
+        return true;
+    }
+    
+    void injectTypeConversionsInBlock(BasicBlock* block)
+    {
+        if (!block)
+            return;
+        ASSERT(block->isReachable);
+        m_block = block;
+        for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) {
+            m_currentNode = block->at(m_indexInBlock);
+            tryToRelaxRepresentation(m_currentNode);
+            DFG_NODE_DO_TO_CHILDREN(m_graph, m_currentNode, injectTypeConversionsForEdge);
+        }
+        m_insertionSet.execute(block);
+    }
+    
+    void tryToRelaxRepresentation(Node* node)
+    {
+        // Some operations may be able to operate more efficiently over looser representations.
+        // Identify those here. This avoids inserting a redundant representation conversion.
+        // Also, for some operations, like MovHint, this is a necessary optimization: inserting
+        // an otherwise-dead conversion just for a MovHint would break OSR's understanding of
+        // the IR.
+        
+        switch (node->op()) {
+        case MovHint:
+        case Check:
+            DFG_NODE_DO_TO_CHILDREN(m_graph, m_currentNode, fixEdgeRepresentation);
+            break;
+            
+        case ValueToInt32:
+            if (node->child1().useKind() == DoubleRepUse
+                && !node->child1()->hasDoubleResult()) {
+                node->child1().setUseKind(NumberUse);
+                break;
+            }
+            break;
+            
+        default:
+            break;
+        }
+    }
+    
+    void fixEdgeRepresentation(Node*, Edge& edge)
+    {
+        switch (edge.useKind()) {
+        case DoubleRepUse:
+        case DoubleRepRealUse:
+            if (edge->hasDoubleResult())
+                break;
+            
+            if (edge->hasInt52Result())
+                edge.setUseKind(Int52RepUse);
+            else if (edge.useKind() == DoubleRepUse)
+                edge.setUseKind(NumberUse);
+            break;
+            
+        case Int52RepUse:
+            // Nothing we can really do.
+            break;
+            
+        case UntypedUse:
+        case NumberUse:
+            if (edge->hasDoubleResult())
+                edge.setUseKind(DoubleRepUse);
+            else if (edge->hasInt52Result())
+                edge.setUseKind(Int52RepUse);
+            break;
+            
+        case RealNumberUse:
+            if (edge->hasDoubleResult())
+                edge.setUseKind(DoubleRepRealUse);
+            else if (edge->hasInt52Result())
+                edge.setUseKind(Int52RepUse);
+            break;
+            
+        default:
+            break;
+        }
+    }
+    
+    void injectTypeConversionsForEdge(Node* node, Edge& edge)
+    {
+        ASSERT(node == m_currentNode);
+        Node* result = nullptr;
+        
+        switch (edge.useKind()) {
+        case DoubleRepUse:
+        case DoubleRepRealUse:
+        case DoubleRepMachineIntUse: {
+            if (edge->hasDoubleResult())
+                break;
+            
+            if (edge->isNumberConstant()) {
+                result = m_insertionSet.insertNode(
+                    m_indexInBlock, SpecBytecodeDouble, DoubleConstant, node->origin,
+                    OpInfo(m_graph.freeze(jsDoubleNumber(edge->asNumber()))));
+            } else if (edge->hasInt52Result()) {
+                result = m_insertionSet.insertNode(
+                    m_indexInBlock, SpecInt52AsDouble, DoubleRep, node->origin,
+                    Edge(edge.node(), Int52RepUse));
+            } else {
+                UseKind useKind;
+                if (edge->shouldSpeculateDoubleReal())
+                    useKind = RealNumberUse;
+                else if (edge->shouldSpeculateNumber())
+                    useKind = NumberUse;
+                else
+                    useKind = NotCellUse;
 
+                result = m_insertionSet.insertNode(
+                    m_indexInBlock, SpecBytecodeDouble, DoubleRep, node->origin,
+                    Edge(edge.node(), useKind));
+            }
+
+            edge.setNode(result);
+            break;
+        }
+            
+        case Int52RepUse: {
+            if (edge->hasInt52Result())
+                break;
+            
+            if (edge->isMachineIntConstant()) {
+                result = m_insertionSet.insertNode(
+                    m_indexInBlock, SpecMachineInt, Int52Constant, node->origin,
+                    OpInfo(edge->constant()));
+            } else if (edge->hasDoubleResult()) {
+                result = m_insertionSet.insertNode(
+                    m_indexInBlock, SpecMachineInt, Int52Rep, node->origin,
+                    Edge(edge.node(), DoubleRepMachineIntUse));
+            } else if (edge->shouldSpeculateInt32ForArithmetic()) {
+                result = m_insertionSet.insertNode(
+                    m_indexInBlock, SpecInt32, Int52Rep, node->origin,
+                    Edge(edge.node(), Int32Use));
+            } else {
+                result = m_insertionSet.insertNode(
+                    m_indexInBlock, SpecMachineInt, Int52Rep, node->origin,
+                    Edge(edge.node(), MachineIntUse));
+            }
+
+            edge.setNode(result);
+            break;
+        }
+            
+        default: {
+            if (!edge->hasDoubleResult() && !edge->hasInt52Result())
+                break;
+            
+            if (edge->hasDoubleResult()) {
+                result = m_insertionSet.insertNode(
+                    m_indexInBlock, SpecBytecodeDouble, ValueRep, node->origin,
+                    Edge(edge.node(), DoubleRepUse));
+            } else {
+                result = m_insertionSet.insertNode(
+                    m_indexInBlock, SpecInt32 | SpecInt52AsDouble, ValueRep, node->origin,
+                    Edge(edge.node(), Int52RepUse));
+            }
+            
+            edge.setNode(result);
+            break;
+        } }
+    }
+    
     BasicBlock* m_block;
     unsigned m_indexInBlock;
     Node* m_currentNode;