Merge the jsCStack branch
https://bugs.webkit.org/show_bug.cgi?id=127763

Reviewed by Mark Hahnenberg.

Source/JavaScriptCore: 

Changes from http://svn.webkit.org/repository/webkit/branches/jsCStack
up to changeset 162958.

Source/WebCore: 

Changes from http://svn.webkit.org/repository/webkit/branches/jsCStack
up to changeset 162958.

Source/WTF: 

Changes from http://svn.webkit.org/repository/webkit/branches/jsCStack
up to changeset 162958.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@163027 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
index be2a40c..198a0bb 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,6 +32,7 @@
 #include "DFGAbstractInterpreterInlines.h"
 #include "DFGInPlaceAbstractState.h"
 #include "FTLAbstractHeapRepository.h"
+#include "FTLAvailableRecovery.h"
 #include "FTLForOSREntryJITCode.h"
 #include "FTLFormattedValue.h"
 #include "FTLInlineCacheSize.h"
@@ -51,6 +52,10 @@
 
 static std::atomic<int> compileCounter;
 
+// FIXME: Get rid of this and introduce a real stack check.
+// https://bugs.webkit.org/show_bug.cgi?id=125650
+static uintptr_t stackLimit;
+
 // Using this instead of typeCheck() helps to reduce the load on LLVM, by creating
 // significantly less dead code.
 #define FTL_TYPE_CHECK(lowValue, highValue, typesPassedThrough, failCondition) do { \
@@ -92,19 +97,20 @@
             llvm->ModuleCreateWithNameInContext(name.data(), m_ftlState.context);
         
         m_ftlState.function = addFunction(
-            m_ftlState.module, name.data(), functionType(m_out.int64, m_out.intPtr));
+            m_ftlState.module, name.data(), functionType(m_out.int64));
         setFunctionCallingConv(m_ftlState.function, LLVMCCallConv);
+        if (isX86() && Options::llvmDisallowAVX()) {
+            // AVX makes V8/raytrace 80% slower. It makes Kraken/audio-oscillator 4.5x
+            // slower. It should be disabled.
+            addTargetDependentFunctionAttr(m_ftlState.function, "target-features", "-avx");
+        }
         
         m_out.initialize(m_ftlState.module, m_ftlState.function, m_heaps);
         
-        m_prologue = appendBasicBlock(m_ftlState.context, m_ftlState.function);
-        m_out.appendTo(m_prologue);
-        createPhiVariables();
-        
-        m_callFrame = m_out.param(0);
-        m_tagTypeNumber = m_out.constInt64(TagTypeNumber);
-        m_tagMask = m_out.constInt64(TagMask);
-        
+        m_prologue = FTL_NEW_BLOCK(m_out, ("Prologue"));
+        LBasicBlock stackOverflow = FTL_NEW_BLOCK(m_out, ("Stack overflow"));
+        m_handleExceptions = FTL_NEW_BLOCK(m_out, ("Handle Exceptions"));
+
         for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
             m_highBlock = m_graph.block(blockIndex);
             if (!m_highBlock)
@@ -112,8 +118,42 @@
             m_blocks.add(m_highBlock, FTL_NEW_BLOCK(m_out, ("Block ", *m_highBlock)));
         }
         
-        m_out.appendTo(m_prologue);
-        m_out.jump(lowBlock(m_graph.block(0)));
+        m_out.appendTo(m_prologue, stackOverflow);
+        createPhiVariables();
+        LValue capturedAlloca = m_out.alloca(arrayType(m_out.int64, m_graph.m_nextMachineLocal));
+        m_captured = m_out.add(
+            m_out.ptrToInt(capturedAlloca, m_out.intPtr),
+            m_out.constIntPtr(m_graph.m_nextMachineLocal * sizeof(Register)));
+        
+        // We should not create any alloca's after this point, since they will cease to
+        // be mem2reg candidates.
+        
+        m_ftlState.capturedStackmapID = m_stackmapIDs++;
+        m_out.call(
+            m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.capturedStackmapID),
+            m_out.int32Zero, capturedAlloca);
+        
+        m_callFrame = m_out.ptrToInt(
+            m_out.call(m_out.frameAddressIntrinsic(), m_out.int32Zero), m_out.intPtr);
+        m_tagTypeNumber = m_out.constInt64(TagTypeNumber);
+        m_tagMask = m_out.constInt64(TagMask);
+        
+        m_out.storePtr(m_out.constIntPtr(codeBlock()), addressFor(JSStack::CodeBlock));
+        m_out.branch(
+            m_out.below(m_callFrame, m_out.loadPtr(m_out.absolute(&stackLimit))),
+            stackOverflow, lowBlock(m_graph.block(0)));
+        
+        m_out.appendTo(stackOverflow, m_handleExceptions);
+        // FIXME: Do a real stack check and throw the exception appropriately.
+        // https://bugs.webkit.org/show_bug.cgi?id=125650
+        m_out.crash();
+        
+        m_out.appendTo(m_handleExceptions, lowBlock(m_graph.block(0)));
+        m_ftlState.handleExceptionStackmapID = m_stackmapIDs++;
+        m_out.call(
+            m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.handleExceptionStackmapID),
+            m_out.constInt32(MacroAssembler::maxJumpReplacementSize()));
+        m_out.unreachable();
         
         Vector<BasicBlock*> depthFirst;
         m_graph.getBlocksInDepthFirstOrder(depthFirst);
@@ -226,6 +266,8 @@
         if (verboseCompilationEnabled())
             dataLog("Lowering ", m_node, "\n");
         
+        m_availableRecoveries.resize(0);
+        
         bool shouldExecuteEffects = m_interpreter.startExecuting(m_node);
         
         switch (m_node->op()) {
@@ -265,19 +307,17 @@
             compileValueAdd();
             break;
         case ArithAdd:
-            compileAddSub();
-            break;
         case ArithSub:
-            compileAddSub();
+            compileArithAddOrSub();
             break;
         case ArithMul:
             compileArithMul();
             break;
         case ArithDiv:
-            compileArithDivMod();
+            compileArithDiv();
             break;
         case ArithMod:
-            compileArithDivMod();
+            compileArithMod();
             break;
         case ArithMin:
         case ArithMax:
@@ -286,6 +326,15 @@
         case ArithAbs:
             compileArithAbs();
             break;
+        case ArithSin:
+            compileArithSin();
+            break;
+        case ArithCos:
+            compileArithCos();
+            break;
+        case ArithSqrt:
+            compileArithSqrt();
+            break;
         case ArithNegate:
             compileArithNegate();
             break;
@@ -322,6 +371,9 @@
         case CheckFunction:
             compileCheckFunction();
             break;
+        case CheckExecutable:
+            compileCheckExecutable();
+            break;
         case ArrayifyToStructure:
             compileArrayifyToStructure();
             break;
@@ -334,6 +386,7 @@
         case GetById:
             compileGetById();
             break;
+        case PutByIdDirect:
         case PutById:
             compilePutById();
             break;
@@ -372,9 +425,18 @@
         case NewArrayBuffer:
             compileNewArrayBuffer();
             break;
+        case NewArrayWithSize:
+            compileNewArrayWithSize();
+            break;
         case AllocatePropertyStorage:
             compileAllocatePropertyStorage();
             break;
+        case ToString:
+            compileToString();
+            break;
+        case MakeRope:
+            compileMakeRope();
+            break;
         case StringCharAt:
             compileStringCharAt();
             break;
@@ -396,6 +458,12 @@
         case NotifyWrite:
             compileNotifyWrite();
             break;
+        case GetCallee:
+            compileGetCallee();
+            break;
+        case GetScope:
+            compileGetScope();
+            break;
         case GetMyScope:
             compileGetMyScope();
             break;
@@ -466,6 +534,12 @@
         case Int52ToValue:
             compileInt52ToValue();
             break;
+        case CheckArgumentsNotCreated:
+            compileCheckArgumentsNotCreated();
+            break;
+        case CountExecution:
+            compileCountExecution();
+            break;
         case StoreBarrier:
             compileStoreBarrier();
             break;
@@ -482,6 +556,7 @@
         case VariableWatchpoint:
         case FunctionReentryWatchpoint:
         case TypedArrayWatchpoint:
+        case AllocationProfileWatchpoint:
             break;
         default:
             RELEASE_ASSERT_NOT_REACHED();
@@ -815,24 +890,53 @@
             lowJSValue(m_node->child1()), lowJSValue(m_node->child2())));
     }
     
-    void compileAddSub()
+    void compileArithAddOrSub()
     {
         bool isSub =  m_node->op() == ArithSub;
         switch (m_node->binaryUseKind()) {
         case Int32Use: {
             LValue left = lowInt32(m_node->child1());
             LValue right = lowInt32(m_node->child2());
-            LValue result = isSub ? m_out.sub(left, right) : m_out.add(left, right);
 
             if (!shouldCheckOverflow(m_node->arithMode())) {
-                setInt32(result);
+                setInt32(isSub ? m_out.sub(left, right) : m_out.add(left, right));
                 break;
             }
 
-            LValue overflow = isSub ? m_out.subWithOverflow32(left, right) : m_out.addWithOverflow32(left, right);
+            LValue result;
+            if (!isSub) {
+                result = m_out.addWithOverflow32(left, right);
+                
+                if (doesKill(m_node->child2())) {
+                    addAvailableRecovery(
+                        m_node->child2(), SubRecovery,
+                        m_out.extractValue(result, 0), left, ValueFormatInt32);
+                } else if (doesKill(m_node->child1())) {
+                    addAvailableRecovery(
+                        m_node->child1(), SubRecovery,
+                        m_out.extractValue(result, 0), right, ValueFormatInt32);
+                }
+            } else {
+                result = m_out.subWithOverflow32(left, right);
+                
+                if (doesKill(m_node->child2())) {
+                    // result = left - right
+                    // result - left = -right
+                    // right = left - result
+                    addAvailableRecovery(
+                        m_node->child2(), SubRecovery,
+                        left, m_out.extractValue(result, 0), ValueFormatInt32);
+                } else if (doesKill(m_node->child1())) {
+                    // result = left - right
+                    // result + right = left
+                    addAvailableRecovery(
+                        m_node->child1(), AddRecovery,
+                        m_out.extractValue(result, 0), right, ValueFormatInt32);
+                }
+            }
 
-            speculate(Overflow, noValue(), 0, m_out.extractValue(overflow, 1));
-            setInt32(result);
+            speculate(Overflow, noValue(), 0, m_out.extractValue(result, 1));
+            setInt32(m_out.extractValue(result, 0));
             break;
         }
             
@@ -848,11 +952,41 @@
             
             LValue left = lowInt52(m_node->child1());
             LValue right = lowInt52(m_node->child2());
-            LValue result = isSub ? m_out.sub(left, right) : m_out.add(left, right);
 
-            LValue overflow = isSub ? m_out.subWithOverflow64(left, right) : m_out.addWithOverflow64(left, right);
-            speculate(Int52Overflow, noValue(), 0, m_out.extractValue(overflow, 1));
-            setInt52(result);
+            LValue result;
+            if (!isSub) {
+                result = m_out.addWithOverflow64(left, right);
+                
+                if (doesKill(m_node->child2())) {
+                    addAvailableRecovery(
+                        m_node->child2(), SubRecovery,
+                        m_out.extractValue(result, 0), left, ValueFormatInt52);
+                } else if (doesKill(m_node->child1())) {
+                    addAvailableRecovery(
+                        m_node->child1(), SubRecovery,
+                        m_out.extractValue(result, 0), right, ValueFormatInt52);
+                }
+            } else {
+                result = m_out.subWithOverflow64(left, right);
+                
+                if (doesKill(m_node->child2())) {
+                    // result = left - right
+                    // result - left = -right
+                    // right = left - result
+                    addAvailableRecovery(
+                        m_node->child2(), SubRecovery,
+                        left, m_out.extractValue(result, 0), ValueFormatInt52);
+                } else if (doesKill(m_node->child1())) {
+                    // result = left - right
+                    // result + right = left
+                    addAvailableRecovery(
+                        m_node->child1(), AddRecovery,
+                        m_out.extractValue(result, 0), right, ValueFormatInt52);
+                }
+            }
+
+            speculate(Int52Overflow, noValue(), 0, m_out.extractValue(result, 1));
+            setInt52(m_out.extractValue(result, 0));
             break;
         }
             
@@ -876,11 +1010,15 @@
         case Int32Use: {
             LValue left = lowInt32(m_node->child1());
             LValue right = lowInt32(m_node->child2());
-            LValue result = m_out.mul(left, right);
+            
+            LValue result;
 
-            if (shouldCheckOverflow(m_node->arithMode())) {
+            if (!shouldCheckOverflow(m_node->arithMode()))
+                result = m_out.mul(left, right);
+            else {
                 LValue overflowResult = m_out.mulWithOverflow32(left, right);
                 speculate(Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
+                result = m_out.extractValue(overflowResult, 0);
             }
             
             if (shouldCheckNegativeZero(m_node->arithMode())) {
@@ -904,11 +1042,10 @@
             Int52Kind kind;
             LValue left = lowWhicheverInt52(m_node->child1(), kind);
             LValue right = lowInt52(m_node->child2(), opposite(kind));
-            LValue result = m_out.mul(left, right);
-
 
             LValue overflowResult = m_out.mulWithOverflow64(left, right);
             speculate(Int52Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
+            LValue result = m_out.extractValue(overflowResult, 0);
 
             if (shouldCheckNegativeZero(m_node->arithMode())) {
                 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ArithMul slow case"));
@@ -939,16 +1076,16 @@
         }
     }
 
-    void compileArithDivMod()
+    void compileArithDiv()
     {
         switch (m_node->binaryUseKind()) {
         case Int32Use: {
             LValue numerator = lowInt32(m_node->child1());
             LValue denominator = lowInt32(m_node->child2());
             
-            LBasicBlock unsafeDenominator = FTL_NEW_BLOCK(m_out, ("ArithDivMod unsafe denominator"));
-            LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithDivMod continuation"));
-            LBasicBlock done = FTL_NEW_BLOCK(m_out, ("ArithDivMod done"));
+            LBasicBlock unsafeDenominator = FTL_NEW_BLOCK(m_out, ("ArithDiv unsafe denominator"));
+            LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithDiv continuation"));
+            LBasicBlock done = FTL_NEW_BLOCK(m_out, ("ArithDiv done"));
             
             Vector<ValueFromBlock, 3> results;
             
@@ -991,8 +1128,8 @@
             m_out.appendTo(continuation, done);
             
             if (shouldCheckNegativeZero(m_node->arithMode())) {
-                LBasicBlock zeroNumerator = FTL_NEW_BLOCK(m_out, ("ArithDivMod zero numerator"));
-                LBasicBlock numeratorContinuation = FTL_NEW_BLOCK(m_out, ("ArithDivMod numerator continuation"));
+                LBasicBlock zeroNumerator = FTL_NEW_BLOCK(m_out, ("ArithDiv zero numerator"));
+                LBasicBlock numeratorContinuation = FTL_NEW_BLOCK(m_out, ("ArithDiv numerator continuation"));
                 
                 m_out.branch(m_out.isZero32(numerator), zeroNumerator, numeratorContinuation);
                 
@@ -1006,17 +1143,15 @@
                 m_out.appendTo(numeratorContinuation, innerLastNext);
             }
             
-            LValue divModResult = m_node->op() == ArithDiv
-                ? m_out.div(numerator, denominator)
-                : m_out.rem(numerator, denominator);
+            LValue result = m_out.div(numerator, denominator);
             
             if (shouldCheckOverflow(m_node->arithMode())) {
                 speculate(
                     Overflow, noValue(), 0,
-                    m_out.notEqual(m_out.mul(divModResult, denominator), numerator));
+                    m_out.notEqual(m_out.mul(result, denominator), numerator));
             }
             
-            results.append(m_out.anchor(divModResult));
+            results.append(m_out.anchor(result));
             m_out.jump(done);
             
             m_out.appendTo(done, lastNext);
@@ -1026,9 +1161,8 @@
         }
             
         case NumberUse: {
-            LValue C1 = lowDouble(m_node->child1());
-            LValue C2 = lowDouble(m_node->child2());
-            setDouble(m_node->op() == ArithDiv ? m_out.doubleDiv(C1, C2) : m_out.doubleRem(C1, C2));
+            setDouble(m_out.doubleDiv(
+                lowDouble(m_node->child1()), lowDouble(m_node->child2())));
             break;
         }
             
@@ -1038,6 +1172,99 @@
         }
     }
     
+    void compileArithMod()
+    {
+        switch (m_node->binaryUseKind()) {
+        case Int32Use: {
+            LValue numerator = lowInt32(m_node->child1());
+            LValue denominator = lowInt32(m_node->child2());
+            
+            LBasicBlock unsafeDenominator = FTL_NEW_BLOCK(m_out, ("ArithMod unsafe denominator"));
+            LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMod continuation"));
+            LBasicBlock done = FTL_NEW_BLOCK(m_out, ("ArithMod done"));
+            
+            Vector<ValueFromBlock, 3> results;
+            
+            LValue adjustedDenominator = m_out.add(denominator, m_out.int32One);
+            
+            m_out.branch(m_out.above(adjustedDenominator, m_out.int32One), continuation, unsafeDenominator);
+            
+            LBasicBlock lastNext = m_out.appendTo(unsafeDenominator, continuation);
+            
+            LValue neg2ToThe31 = m_out.constInt32(-2147483647-1);
+            
+            // FIXME: -2^31 / -1 will actually yield negative zero, so we could have a
+            // separate case for that. But it probably doesn't matter so much.
+            if (shouldCheckOverflow(m_node->arithMode())) {
+                LValue cond = m_out.bitOr(m_out.isZero32(denominator), m_out.equal(numerator, neg2ToThe31));
+                speculate(Overflow, noValue(), 0, cond);
+                m_out.jump(continuation);
+            } else {
+                // This is the case where we convert the result to an int after we're done. So,
+                // if the denominator is zero, then the result should be result should be zero.
+                // If the denominator is not zero (i.e. it's -1 because we're guarded by the
+                // check above) and the numerator is -2^31 then the result should be -2^31.
+                
+                LBasicBlock modByZero = FTL_NEW_BLOCK(m_out, ("ArithMod modulo by zero"));
+                LBasicBlock notModByZero = FTL_NEW_BLOCK(m_out, ("ArithMod not modulo by zero"));
+                LBasicBlock neg2ToThe31ByNeg1 = FTL_NEW_BLOCK(m_out, ("ArithMod -2^31/-1"));
+                
+                m_out.branch(m_out.isZero32(denominator), modByZero, notModByZero);
+                
+                m_out.appendTo(modByZero, notModByZero);
+                results.append(m_out.anchor(m_out.int32Zero));
+                m_out.jump(done);
+                
+                m_out.appendTo(notModByZero, neg2ToThe31ByNeg1);
+                m_out.branch(m_out.equal(numerator, neg2ToThe31), neg2ToThe31ByNeg1, continuation);
+                
+                m_out.appendTo(neg2ToThe31ByNeg1, continuation);
+                results.append(m_out.anchor(m_out.int32Zero));
+                m_out.jump(done);
+            }
+            
+            m_out.appendTo(continuation, done);
+            
+            LValue remainder = m_out.rem(numerator, denominator);
+            
+            if (shouldCheckNegativeZero(m_node->arithMode())) {
+                LBasicBlock negativeNumerator = FTL_NEW_BLOCK(m_out, ("ArithMod negative numerator"));
+                LBasicBlock numeratorContinuation = FTL_NEW_BLOCK(m_out, ("ArithMod numerator continuation"));
+                
+                m_out.branch(
+                    m_out.lessThan(numerator, m_out.int32Zero),
+                    negativeNumerator, numeratorContinuation);
+                
+                LBasicBlock innerLastNext = m_out.appendTo(negativeNumerator, numeratorContinuation);
+                
+                speculate(NegativeZero, noValue(), 0, m_out.isZero32(remainder));
+                
+                m_out.jump(numeratorContinuation);
+                
+                m_out.appendTo(numeratorContinuation, innerLastNext);
+            }
+            
+            results.append(m_out.anchor(remainder));
+            m_out.jump(done);
+            
+            m_out.appendTo(done, lastNext);
+            
+            setInt32(m_out.phi(m_out.int32, results));
+            break;
+        }
+            
+        case NumberUse: {
+            setDouble(
+                m_out.doubleRem(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
+            break;
+        }
+            
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+        }
+    }
+
     void compileArithMinOrMax()
     {
         switch (m_node->binaryUseKind()) {
@@ -1114,6 +1341,12 @@
             break;
         }
     }
+
+    void compileArithSin() { setDouble(m_out.doubleSin(lowDouble(m_node->child1()))); }
+
+    void compileArithCos() { setDouble(m_out.doubleCos(lowDouble(m_node->child1()))); }
+
+    void compileArithSqrt() { setDouble(m_out.doubleSqrt(lowDouble(m_node->child1()))); }
     
     void compileArithNegate()
     {
@@ -1121,16 +1354,18 @@
         case Int32Use: {
             LValue value = lowInt32(m_node->child1());
             
-            LValue result = m_out.neg(value);
-            if (shouldCheckOverflow(m_node->arithMode())) {
-                if (!shouldCheckNegativeZero(m_node->arithMode())) {
-                    // We don't have a negate-with-overflow intrinsic. Hopefully this
-                    // does the trick, though.
-                    LValue overflowResult = m_out.subWithOverflow32(m_out.int32Zero, value);
-                    speculate(Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
-                } else
-                    speculate(Overflow, noValue(), 0, m_out.testIsZero32(value, m_out.constInt32(0x7fffffff)));
-
+            LValue result;
+            if (!shouldCheckOverflow(m_node->arithMode()))
+                result = m_out.neg(value);
+            else if (!shouldCheckNegativeZero(m_node->arithMode())) {
+                // We don't have a negate-with-overflow intrinsic. Hopefully this
+                // does the trick, though.
+                LValue overflowResult = m_out.subWithOverflow32(m_out.int32Zero, value);
+                speculate(Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
+                result = m_out.extractValue(overflowResult, 0);
+            } else {
+                speculate(Overflow, noValue(), 0, m_out.testIsZero32(value, m_out.constInt32(0x7fffffff)));
+                result = m_out.neg(value);
             }
 
             setInt32(result);
@@ -1151,7 +1386,7 @@
             LValue value = lowInt52(m_node->child1());
             LValue overflowResult = m_out.subWithOverflow64(m_out.int64Zero, value);
             speculate(Int52Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
-            LValue result = m_out.neg(value);
+            LValue result = m_out.extractValue(overflowResult, 0);
             speculate(NegativeZero, noValue(), 0, m_out.isZero64(result));
             setInt52(result);
             break;
@@ -1275,6 +1510,17 @@
             m_out.notEqual(cell, weakPointer(m_node->function())));
     }
     
+    void compileCheckExecutable()
+    {
+        LValue cell = lowCell(m_node->child1());
+        
+        speculate(
+            BadExecutable, jsValueValue(cell), m_node->child1().node(),
+            m_out.notEqual(
+                m_out.loadPtr(cell, m_heaps.JSFunction_executable),
+                weakPointer(m_node->executable())));
+    }
+    
     void compileArrayifyToStructure()
     {
         LValue cell = lowCell(m_node->child1());
@@ -1370,8 +1616,8 @@
         
         LValue call = m_out.call(
             m_out.patchpointInt64Intrinsic(),
-            m_out.constInt32(stackmapID), m_out.constInt32(sizeOfGetById()),
-            constNull(m_out.ref8), m_out.constInt32(2), m_callFrame, base);
+            m_out.constInt64(stackmapID), m_out.constInt32(sizeOfGetById()),
+            constNull(m_out.ref8), m_out.constInt32(1), base);
         setInstructionCallingConvention(call, LLVMAnyRegCallConv);
         setJSValue(call);
         
@@ -1395,8 +1641,8 @@
         
         LValue call = m_out.call(
             m_out.patchpointVoidIntrinsic(),
-            m_out.constInt32(stackmapID), m_out.constInt32(sizeOfPutById()),
-            constNull(m_out.ref8), m_out.constInt32(3), m_callFrame, base, value);
+            m_out.constInt64(stackmapID), m_out.constInt32(sizeOfPutById()),
+            constNull(m_out.ref8), m_out.constInt32(2), base, value);
         setInstructionCallingConvention(call, LLVMAnyRegCallConv);
         
         m_ftlState.putByIds.append(PutByIdDescriptor(
@@ -1463,20 +1709,20 @@
         case Array::Int32:
         case Array::Double:
         case Array::Contiguous: {
-            setInt32(m_out.load32(lowStorage(m_node->child2()), m_heaps.Butterfly_publicLength));
+            setInt32(m_out.load32NonNegative(lowStorage(m_node->child2()), m_heaps.Butterfly_publicLength));
             return;
         }
             
         case Array::String: {
             LValue string = lowCell(m_node->child1());
-            setInt32(m_out.load32(string, m_heaps.JSString_length));
+            setInt32(m_out.load32NonNegative(string, m_heaps.JSString_length));
             return;
         }
             
         default:
             if (isTypedView(m_node->arrayMode().typedArrayType())) {
                 setInt32(
-                    m_out.load32(lowCell(m_node->child1()), m_heaps.JSArrayBufferView_length));
+                    m_out.load32NonNegative(lowCell(m_node->child1()), m_heaps.JSArrayBufferView_length));
                 return;
             }
             
@@ -1518,7 +1764,7 @@
             
             m_out.branch(
                 m_out.aboveOrEqual(
-                    index, m_out.load32(storage, m_heaps.Butterfly_publicLength)),
+                    index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
                 slowCase, fastCase);
             
             LBasicBlock lastNext = m_out.appendTo(fastCase, slowCase);
@@ -1565,7 +1811,7 @@
             
             m_out.branch(
                 m_out.aboveOrEqual(
-                    index, m_out.load32(storage, m_heaps.Butterfly_publicLength)),
+                    index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
                 slowCase, inBounds);
             
             LBasicBlock lastNext = m_out.appendTo(inBounds, boxPath);
@@ -1687,6 +1933,7 @@
         Edge child2 = m_graph.varArgChild(m_node, 1);
         Edge child3 = m_graph.varArgChild(m_node, 2);
         Edge child4 = m_graph.varArgChild(m_node, 3);
+        Edge child5 = m_graph.varArgChild(m_node, 4);
         
         switch (m_node->arrayMode().type()) {
         case Array::Generic: {
@@ -1801,6 +2048,9 @@
                             m_out.zeroExt(index, m_out.intPtr),
                             m_out.constIntPtr(logElementSize(type)))));
                 
+                LType refType;
+                LValue valueToStore;
+                
                 if (isInt(type)) {
                     LValue intValue;
                     switch (child3.useKind()) {
@@ -1876,34 +2126,53 @@
                     
                     switch (elementSize(type)) {
                     case 1:
-                        m_out.store8(m_out.intCast(intValue, m_out.int8), pointer);
+                        valueToStore = m_out.intCast(intValue, m_out.int8);
+                        refType = m_out.ref8;
                         break;
                     case 2:
-                        m_out.store16(m_out.intCast(intValue, m_out.int16), pointer);
+                        valueToStore = m_out.intCast(intValue, m_out.int16);
+                        refType = m_out.ref16;
                         break;
                     case 4:
-                        m_out.store32(intValue, pointer);
+                        valueToStore = intValue;
+                        refType = m_out.ref32;
                         break;
                     default:
                         RELEASE_ASSERT_NOT_REACHED();
                     }
+                } else /* !isInt(type) */ {
+                    LValue value = lowDouble(child3);
+                    switch (type) {
+                    case TypeFloat32:
+                        valueToStore = m_out.fpCast(value, m_out.floatType);
+                        refType = m_out.refFloat;
+                        break;
+                    case TypeFloat64:
+                        valueToStore = value;
+                        refType = m_out.refDouble;
+                        break;
+                    default:
+                        RELEASE_ASSERT_NOT_REACHED();
+                    }
+                }
+                
+                if (m_node->arrayMode().isInBounds())
+                    m_out.store(valueToStore, pointer, refType);
+                else {
+                    LBasicBlock isInBounds = FTL_NEW_BLOCK(m_out, ("PutByVal typed array in bounds case"));
+                    LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal typed array continuation"));
                     
-                    return;
+                    m_out.branch(
+                        m_out.aboveOrEqual(index, lowInt32(child5)),
+                        continuation, isInBounds);
+                    
+                    LBasicBlock lastNext = m_out.appendTo(isInBounds, continuation);
+                    m_out.store(valueToStore, pointer, refType);
+                    m_out.jump(continuation);
+                    
+                    m_out.appendTo(continuation, lastNext);
                 }
                 
-                ASSERT(isFloat(type));
-                
-                LValue value = lowDouble(child3);
-                switch (type) {
-                case TypeFloat32:
-                    m_out.storeFloat(m_out.fpCast(value, m_out.floatType), pointer);
-                    break;
-                case TypeFloat64:
-                    m_out.storeDouble(value, pointer);
-                    break;
-                default:
-                    RELEASE_ASSERT_NOT_REACHED();
-                }
                 return;
             }
             
@@ -2060,6 +2329,109 @@
             m_out.constIntPtr(m_node->numConstants())));
     }
     
+    void compileNewArrayWithSize()
+    {
+        LValue publicLength = lowInt32(m_node->child1());
+        
+        JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->codeOrigin);
+        Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(
+            m_node->indexingType());
+        
+        if (!globalObject->isHavingABadTime() && !hasArrayStorage(m_node->indexingType())) {
+            ASSERT(
+                hasUndecided(structure->indexingType())
+                || hasInt32(structure->indexingType())
+                || hasDouble(structure->indexingType())
+                || hasContiguous(structure->indexingType()));
+
+            LBasicBlock fastCase = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize fast case"));
+            LBasicBlock largeCase = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize large case"));
+            LBasicBlock failCase = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize fail case"));
+            LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize slow case"));
+            LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize continuation"));
+            
+            m_out.branch(
+                m_out.aboveOrEqual(publicLength, m_out.constInt32(MIN_SPARSE_ARRAY_INDEX)),
+                largeCase, fastCase);
+
+            LBasicBlock lastNext = m_out.appendTo(fastCase, largeCase);
+            
+            // We don't round up to BASE_VECTOR_LEN for new Array(blah).
+            LValue vectorLength = publicLength;
+            
+            LValue payloadSize =
+                m_out.shl(m_out.zeroExt(vectorLength, m_out.intPtr), m_out.constIntPtr(3));
+            
+            LValue butterflySize = m_out.add(
+                payloadSize, m_out.constIntPtr(sizeof(IndexingHeader)));
+            
+            LValue endOfStorage = allocateBasicStorageAndGetEnd(butterflySize, failCase);
+            
+            LValue butterfly = m_out.sub(endOfStorage, payloadSize);
+            
+            LValue object = allocateObject<JSArray>(
+                m_out.constIntPtr(structure), butterfly, failCase);
+            
+            m_out.store32(publicLength, butterfly, m_heaps.Butterfly_publicLength);
+            m_out.store32(vectorLength, butterfly, m_heaps.Butterfly_vectorLength);
+            
+            if (hasDouble(m_node->indexingType())) {
+                LBasicBlock initLoop = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize double init loop"));
+                LBasicBlock initDone = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize double init done"));
+                
+                ValueFromBlock originalIndex = m_out.anchor(vectorLength);
+                ValueFromBlock originalPointer = m_out.anchor(butterfly);
+                m_out.branch(m_out.notZero32(vectorLength), initLoop, initDone);
+                
+                LBasicBlock initLastNext = m_out.appendTo(initLoop, initDone);
+                LValue index = m_out.phi(m_out.int32, originalIndex);
+                LValue pointer = m_out.phi(m_out.intPtr, originalPointer);
+                
+                m_out.store64(
+                    m_out.constInt64(bitwise_cast<int64_t>(QNaN)),
+                    TypedPointer(m_heaps.indexedDoubleProperties.atAnyIndex(), pointer));
+                
+                LValue nextIndex = m_out.sub(index, m_out.int32One);
+                addIncoming(index, m_out.anchor(nextIndex));
+                addIncoming(pointer, m_out.anchor(m_out.add(pointer, m_out.intPtrEight)));
+                m_out.branch(m_out.notZero32(nextIndex), initLoop, initDone);
+                
+                m_out.appendTo(initDone, initLastNext);
+            }
+            
+            ValueFromBlock fastResult = m_out.anchor(object);
+            m_out.jump(continuation);
+            
+            m_out.appendTo(largeCase, failCase);
+            ValueFromBlock largeStructure = m_out.anchor(m_out.constIntPtr(
+                globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage)));
+            m_out.jump(slowCase);
+            
+            m_out.appendTo(failCase, slowCase);
+            ValueFromBlock failStructure = m_out.anchor(m_out.constIntPtr(structure));
+            m_out.jump(slowCase);
+            
+            m_out.appendTo(slowCase, continuation);
+            LValue structureValue = m_out.phi(
+                m_out.intPtr, largeStructure, failStructure);
+            ValueFromBlock slowResult = m_out.anchor(vmCall(
+                m_out.operation(operationNewArrayWithSize),
+                m_callFrame, structureValue, publicLength));
+            m_out.jump(continuation);
+            
+            m_out.appendTo(continuation, lastNext);
+            setJSValue(m_out.phi(m_out.intPtr, fastResult, slowResult));
+            return;
+        }
+        
+        LValue structureValue = m_out.select(
+            m_out.aboveOrEqual(publicLength, m_out.constInt32(MIN_SPARSE_ARRAY_INDEX)),
+            m_out.constIntPtr(
+                globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage)),
+            m_out.constIntPtr(structure));
+        setJSValue(vmCall(m_out.operation(operationNewArrayWithSize), m_callFrame, structureValue, publicLength));
+    }
+    
     void compileAllocatePropertyStorage()
     {
         StructureTransitionData& data = m_node->structureTransitionData();
@@ -2102,6 +2474,160 @@
         setStorage(result);
     }
     
+    void compileToString()
+    {
+        switch (m_node->child1().useKind()) {
+        case StringObjectUse: {
+            LValue cell = lowCell(m_node->child1());
+            speculateStringObjectForCell(m_node->child1(), cell);
+            m_interpreter.filter(m_node->child1(), SpecStringObject);
+            
+            setJSValue(m_out.loadPtr(cell, m_heaps.JSWrapperObject_internalValue));
+            return;
+        }
+            
+        case StringOrStringObjectUse: {
+            LValue cell = lowCell(m_node->child1());
+            LValue structure = m_out.loadPtr(cell, m_heaps.JSCell_structure);
+            
+            LBasicBlock notString = FTL_NEW_BLOCK(m_out, ("ToString StringOrStringObject not string case"));
+            LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ToString StringOrStringObject continuation"));
+            
+            ValueFromBlock simpleResult = m_out.anchor(cell);
+            m_out.branch(
+                m_out.equal(structure, m_out.constIntPtr(vm().stringStructure.get())),
+                continuation, notString);
+            
+            LBasicBlock lastNext = m_out.appendTo(notString, continuation);
+            speculateStringObjectForStructure(m_node->child1(), structure);
+            ValueFromBlock unboxedResult = m_out.anchor(
+                m_out.loadPtr(cell, m_heaps.JSWrapperObject_internalValue));
+            m_out.jump(continuation);
+            
+            m_out.appendTo(continuation, lastNext);
+            setJSValue(m_out.phi(m_out.int64, simpleResult, unboxedResult));
+            
+            m_interpreter.filter(m_node->child1(), SpecString | SpecStringObject);
+            return;
+        }
+            
+        case CellUse:
+        case UntypedUse: {
+            LValue value;
+            if (m_node->child1().useKind() == CellUse)
+                value = lowCell(m_node->child1());
+            else
+                value = lowJSValue(m_node->child1());
+            
+            LBasicBlock isCell = FTL_NEW_BLOCK(m_out, ("ToString CellUse/UntypedUse is cell"));
+            LBasicBlock notString = FTL_NEW_BLOCK(m_out, ("ToString CellUse/UntypedUse not string"));
+            LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ToString CellUse/UntypedUse continuation"));
+            
+            LValue isCellPredicate;
+            if (m_node->child1().useKind() == CellUse)
+                isCellPredicate = m_out.booleanTrue;
+            else
+                isCellPredicate = this->isCell(value);
+            m_out.branch(isCellPredicate, isCell, notString);
+            
+            LBasicBlock lastNext = m_out.appendTo(isCell, notString);
+            ValueFromBlock simpleResult = m_out.anchor(value);
+            LValue isStringPredicate;
+            if (m_node->child1()->prediction() & SpecString) {
+                isStringPredicate = m_out.equal(
+                    m_out.loadPtr(value, m_heaps.JSCell_structure),
+                    m_out.constIntPtr(vm().stringStructure.get()));
+            } else
+                isStringPredicate = m_out.booleanFalse;
+            m_out.branch(isStringPredicate, continuation, notString);
+            
+            m_out.appendTo(notString, continuation);
+            LValue operation;
+            if (m_node->child1().useKind() == CellUse)
+                operation = m_out.operation(operationToStringOnCell);
+            else
+                operation = m_out.operation(operationToString);
+            ValueFromBlock convertedResult = m_out.anchor(vmCall(operation, m_callFrame, value));
+            m_out.jump(continuation);
+            
+            m_out.appendTo(continuation, lastNext);
+            setJSValue(m_out.phi(m_out.int64, simpleResult, convertedResult));
+            return;
+        }
+            
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+        }
+    }
+    
+    void compileMakeRope()
+    {
+        LValue kids[3];
+        unsigned numKids;
+        kids[0] = lowCell(m_node->child1());
+        kids[1] = lowCell(m_node->child2());
+        if (m_node->child3()) {
+            kids[2] = lowCell(m_node->child3());
+            numKids = 3;
+        } else {
+            kids[2] = 0;
+            numKids = 2;
+        }
+        
+        LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("MakeRope slow path"));
+        LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("MakeRope continuation"));
+        
+        LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
+        
+        MarkedAllocator& allocator =
+            vm().heap.allocatorForObjectWithImmortalStructureDestructor(sizeof(JSRopeString));
+        
+        LValue result = allocateCell(
+            m_out.constIntPtr(&allocator),
+            m_out.constIntPtr(vm().stringStructure.get()),
+            slowPath);
+        
+        m_out.storePtr(m_out.intPtrZero, result, m_heaps.JSString_value);
+        for (unsigned i = 0; i < numKids; ++i)
+            m_out.storePtr(kids[i], result, m_heaps.JSRopeString_fibers[i]);
+        for (unsigned i = numKids; i < JSRopeString::s_maxInternalRopeLength; ++i)
+            m_out.storePtr(m_out.intPtrZero, result, m_heaps.JSRopeString_fibers[i]);
+        LValue flags = m_out.load32(kids[0], m_heaps.JSString_flags);
+        LValue length = m_out.load32(kids[0], m_heaps.JSString_length);
+        for (unsigned i = 1; i < numKids; ++i) {
+            flags = m_out.bitAnd(flags, m_out.load32(kids[i], m_heaps.JSString_flags));
+            length = m_out.add(length, m_out.load32(kids[i], m_heaps.JSString_length));
+        }
+        m_out.store32(
+            m_out.bitAnd(m_out.constInt32(JSString::Is8Bit), flags),
+            result, m_heaps.JSString_flags);
+        m_out.store32(length, result, m_heaps.JSString_length);
+        
+        ValueFromBlock fastResult = m_out.anchor(result);
+        m_out.jump(continuation);
+        
+        m_out.appendTo(slowPath, continuation);
+        ValueFromBlock slowResult;
+        switch (numKids) {
+        case 2:
+            slowResult = m_out.anchor(vmCall(
+                m_out.operation(operationMakeRope2), m_callFrame, kids[0], kids[1]));
+            break;
+        case 3:
+            slowResult = m_out.anchor(vmCall(
+                m_out.operation(operationMakeRope3), m_callFrame, kids[0], kids[1], kids[2]));
+            break;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+        }
+        m_out.jump(continuation);
+        
+        m_out.appendTo(continuation, lastNext);
+        setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
+    }
+    
     void compileStringCharAt()
     {
         LValue base = lowCell(m_node->child1());
@@ -2114,7 +2640,7 @@
             
         m_out.branch(
             m_out.aboveOrEqual(
-                index, m_out.load32(base, m_heaps.JSString_length)),
+                index, m_out.load32NonNegative(base, m_heaps.JSString_length)),
             slowPath, fastPath);
             
         LBasicBlock lastNext = m_out.appendTo(fastPath, slowPath);
@@ -2210,7 +2736,8 @@
         
         speculate(
             Uncountable, noValue(), 0,
-            m_out.aboveOrEqual(index, m_out.load32(base, m_heaps.JSString_length)));
+            m_out.aboveOrEqual(
+                index, m_out.load32NonNegative(base, m_heaps.JSString_length)));
         
         LValue stringImpl = m_out.loadPtr(base, m_heaps.JSString_value);
         
@@ -2345,6 +2872,16 @@
         m_out.appendTo(continuation, lastNext);
     }
     
+    void compileGetCallee()
+    {
+        setJSValue(m_out.loadPtr(addressFor(JSStack::Callee)));
+    }
+    
+    void compileGetScope()
+    {
+        setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSFunction_scope));
+    }
+    
     void compileGetMyScope()
     {
         setJSValue(m_out.loadPtr(addressFor(
@@ -2488,35 +3025,37 @@
     
     void compileCallOrConstruct()
     {
-        // FIXME: This is unacceptably slow.
-        // https://bugs.webkit.org/show_bug.cgi?id=113621
-        
-        J_JITOperation_E function =
-            m_node->op() == Call ? operationFTLCall : operationFTLConstruct;
-        
         int dummyThisArgument = m_node->op() == Call ? 0 : 1;
-        
         int numPassedArgs = m_node->numChildren() - 1;
+        int numArgs = numPassedArgs + dummyThisArgument;
         
-        LValue calleeFrame = m_out.add(
-            m_callFrame,
-            m_out.constIntPtr(sizeof(Register) * virtualRegisterForLocal(m_graph.frameRegisterCount()).offset()));
+        LValue callee = lowJSValue(m_graph.varArgChild(m_node, 0));
         
-        m_out.store32(
-            m_out.constInt32(numPassedArgs + dummyThisArgument),
-            payloadFor(calleeFrame, JSStack::ArgumentCount));
-        m_out.store64(m_callFrame, calleeFrame, m_heaps.CallFrame_callerFrame);
-        m_out.store64(
-            lowJSValue(m_graph.varArgChild(m_node, 0)),
-            addressFor(calleeFrame, JSStack::Callee));
+        unsigned stackmapID = m_stackmapIDs++;
         
-        for (int i = 0; i < numPassedArgs; ++i) {
-            m_out.store64(
-                lowJSValue(m_graph.varArgChild(m_node, 1 + i)),
-                addressFor(calleeFrame, virtualRegisterForArgument(i + dummyThisArgument).offset()));
-        }
+        Vector<LValue> arguments;
+        arguments.append(m_out.constInt64(stackmapID));
+        arguments.append(m_out.constInt32(sizeOfCall()));
+        arguments.append(constNull(m_out.ref8));
+        arguments.append(m_out.constInt32(1 + JSStack::CallFrameHeaderSize - JSStack::CallerFrameAndPCSize + numArgs));
+        arguments.append(callee); // callee -> %rax
+        arguments.append(getUndef(m_out.int64)); // code block
+        arguments.append(getUndef(m_out.int64)); // scope chain
+        arguments.append(callee); // callee -> stack
+        arguments.append(m_out.constInt64(numArgs)); // argument count and zeros for the tag
+        if (dummyThisArgument)
+            arguments.append(getUndef(m_out.int64));
+        for (int i = 0; i < numPassedArgs; ++i)
+            arguments.append(lowJSValue(m_graph.varArgChild(m_node, 1 + i)));
         
-        setJSValue(vmCall(m_out.operation(function), calleeFrame));
+        callPreflight();
+        
+        LValue call = m_out.call(m_out.patchpointInt64Intrinsic(), arguments);
+        setInstructionCallingConvention(call, LLVMWebKitJSCallConv);
+        
+        m_ftlState.jsCalls.append(JSCall(stackmapID, m_node));
+        
+        setJSValue(call);
     }
     
     void compileJump()
@@ -2627,7 +3166,7 @@
             
             m_out.branch(
                 m_out.notEqual(
-                    m_out.load32(stringValue, m_heaps.JSString_length),
+                    m_out.load32NonNegative(stringValue, m_heaps.JSString_length),
                     m_out.int32One),
                 lowBlock(data->fallThrough), lengthIs1);
             
@@ -2708,6 +3247,22 @@
         info.m_isInvalidationPoint = true;
     }
     
+    void compileCheckArgumentsNotCreated()
+    {
+        ASSERT(!isEmptySpeculation(
+            m_state.variables().operand(
+                m_graph.argumentsRegisterFor(m_node->codeOrigin)).m_type));
+        
+        VirtualRegister reg = m_graph.machineArgumentsRegisterFor(m_node->codeOrigin);
+        speculate(ArgumentsEscaped, noValue(), 0, m_out.notZero64(m_out.load64(addressFor(reg))));
+    }
+    
+    void compileCountExecution()
+    {
+        TypedPointer counter = m_out.absolute(m_node->executionCounter()->address());
+        m_out.store64(m_out.add(m_out.load64(counter), m_out.constInt64(1)), counter);
+    }
+    
     TypedPointer baseIndex(IndexedAbstractHeap& heap, LValue storage, LValue index, Edge edge)
     {
         return m_out.baseIndex(
@@ -2924,7 +3479,7 @@
     {
         if (JSArrayBufferView* view = m_graph.tryGetFoldableView(baseEdge.node(), arrayMode))
             return m_out.constInt32(view->length());
-        return m_out.load32(base, m_heaps.JSArrayBufferView_length);
+        return m_out.load32NonNegative(base, m_heaps.JSArrayBufferView_length);
     }
     
     LValue typedArrayLength(Edge baseEdge, ArrayMode arrayMode)
@@ -2948,7 +3503,7 @@
                     ManualOperandSpeculation));
         case StringUse: {
             LValue stringValue = lowString(m_node->child1());
-            LValue length = m_out.load32(stringValue, m_heaps.JSString_length);
+            LValue length = m_out.load32NonNegative(stringValue, m_heaps.JSString_length);
             return m_out.notEqual(length, m_out.int32Zero);
         }
         case UntypedUse: {
@@ -3082,7 +3637,7 @@
         LBasicBlock continuation)
     {
         LValue isNotInBounds = m_out.aboveOrEqual(
-            index, m_out.load32(storage, m_heaps.Butterfly_publicLength));
+            index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength));
         if (!m_node->arrayMode().isInBounds()) {
             LBasicBlock notInBoundsCase =
                 FTL_NEW_BLOCK(m_out, ("PutByVal not in bounds"));
@@ -3094,7 +3649,7 @@
             LBasicBlock lastNext = m_out.appendTo(notInBoundsCase, performStore);
                 
             LValue isOutOfBounds = m_out.aboveOrEqual(
-                index, m_out.load32(storage, m_heaps.Butterfly_vectorLength));
+                index, m_out.load32NonNegative(storage, m_heaps.Butterfly_vectorLength));
                 
             if (!m_node->arrayMode().isOutOfBounds())
                 speculate(OutOfBounds, noValue(), 0, isOutOfBounds);
@@ -3718,6 +4273,7 @@
             break;
         case KnownInt32Use:
         case KnownNumberUse:
+        case KnownStringUse:
             ASSERT(!m_interpreter.needsTypeCheck(edge));
             break;
         case Int32Use:
@@ -3741,6 +4297,12 @@
         case StringUse:
             speculateString(edge);
             break;
+        case StringObjectUse:
+            speculateStringObject(edge);
+            break;
+        case StringOrStringObjectUse:
+            speculateStringOrStringObject(edge);
+            break;
         case RealNumberUse:
             speculateRealNumber(edge);
             break;
@@ -3753,6 +4315,9 @@
         case BooleanUse:
             speculateBoolean(edge);
             break;
+        case NotCellUse:
+            speculateNotCell(edge);
+            break;
         default:
             dataLog("Unsupported speculation use kind: ", edge.useKind(), "\n");
             RELEASE_ASSERT_NOT_REACHED();
@@ -3928,6 +4493,55 @@
         speculateString(edge, lowCell(edge));
     }
     
+    void speculateStringObject(Edge edge)
+    {
+        if (!m_interpreter.needsTypeCheck(edge, SpecStringObject))
+            return;
+        
+        speculateStringObjectForCell(edge, lowCell(edge));
+        m_interpreter.filter(edge, SpecStringObject);
+    }
+    
+    void speculateStringOrStringObject(Edge edge)
+    {
+        if (!m_interpreter.needsTypeCheck(edge, SpecString | SpecStringObject))
+            return;
+        
+        LBasicBlock notString = FTL_NEW_BLOCK(m_out, ("Speculate StringOrStringObject not string case"));
+        LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Speculate StringOrStringObject continuation"));
+        
+        LValue structure = m_out.loadPtr(lowCell(edge), m_heaps.JSCell_structure);
+        m_out.branch(
+            m_out.equal(structure, m_out.constIntPtr(vm().stringStructure.get())),
+            continuation, notString);
+        
+        LBasicBlock lastNext = m_out.appendTo(notString, continuation);
+        speculateStringObjectForStructure(edge, structure);
+        m_out.jump(continuation);
+        
+        m_out.appendTo(continuation, lastNext);
+        
+        m_interpreter.filter(edge, SpecString | SpecStringObject);
+    }
+    
+    void speculateStringObjectForCell(Edge edge, LValue cell)
+    {
+        speculateStringObjectForStructure(edge, m_out.loadPtr(cell, m_heaps.JSCell_structure));
+    }
+    
+    void speculateStringObjectForStructure(Edge edge, LValue structure)
+    {
+        Structure* stringObjectStructure =
+            m_graph.globalObjectFor(m_node->codeOrigin)->stringObjectStructure();
+        
+        if (m_state.forNode(edge).m_currentKnownStructure.isSubsetOf(StructureSet(stringObjectStructure)))
+            return;
+        
+        speculate(
+            NotStringObject, noValue(), 0,
+            m_out.notEqual(structure, weakPointer(stringObjectStructure)));
+    }
+    
     void speculateNonNullObject(Edge edge, LValue cell)
     {
         LValue structure = m_out.loadPtr(cell, m_heaps.JSCell_structure);
@@ -3979,6 +4593,15 @@
         lowBoolean(edge);
     }
     
+    void speculateNotCell(Edge edge)
+    {
+        if (!m_interpreter.needsTypeCheck(edge))
+            return;
+        
+        LValue value = lowJSValue(edge);
+        typeCheck(jsValueValue(value), edge, ~SpecCell, isCell(value));
+    }
+    
     bool masqueradesAsUndefinedWatchpointIsStillValid()
     {
         return m_graph.masqueradesAsUndefinedWatchpointIsStillValid(m_node->codeOrigin);
@@ -4106,18 +4729,13 @@
         if (mode == NoExceptions)
             return;
         
-        LBasicBlock didHaveException = FTL_NEW_BLOCK(m_out, ("Did have exception"));
         LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Exception check continuation"));
         
         m_out.branch(
             m_out.notZero64(m_out.load64(m_out.absolute(vm().addressOfException()))),
-            didHaveException, continuation);
+            m_handleExceptions, continuation);
         
-        LBasicBlock lastNext = m_out.appendTo(didHaveException, continuation);
-        // FIXME: Handle exceptions. https://bugs.webkit.org/show_bug.cgi?id=113622
-        m_out.crash();
-        
-        m_out.appendTo(continuation, lastNext);
+        m_out.appendTo(continuation);
     }
     
     LBasicBlock lowBlock(BasicBlock* block)
@@ -4133,8 +4751,11 @@
     void appendOSRExit(
         ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition)
     {
-        if (verboseCompilationEnabled())
+        if (verboseCompilationEnabled()) {
             dataLog("    OSR exit #", m_ftlState.jitCode->osrExit.size(), " with availability: ", m_availability, "\n");
+            if (!m_availableRecoveries.isEmpty())
+                dataLog("        Available recoveries: ", listDump(m_availableRecoveries), "\n");
+        }
 
         ASSERT(m_ftlState.jitCode->osrExit.size() == m_ftlState.finalizer->osrExit.size());
         
@@ -4178,7 +4799,6 @@
         OSRExit& exit, ExitArgumentList& arguments, FormattedValue lowValue,
         CodeOrigin codeOrigin)
     {
-        arguments.append(m_callFrame);
         if (!!lowValue)
             arguments.append(lowValue.value());
         
@@ -4246,7 +4866,7 @@
     {
         exit.m_stackmapID = m_stackmapIDs++;
         arguments.insert(0, m_out.constInt32(MacroAssembler::maxJumpReplacementSize()));
-        arguments.insert(0, m_out.constInt32(exit.m_stackmapID));
+        arguments.insert(0, m_out.constInt64(exit.m_stackmapID));
         
         m_out.call(m_out.stackmapIntrinsic(), arguments);
     }
@@ -4260,6 +4880,19 @@
         if (tryToSetConstantExitArgument(exit, index, node))
             return;
         
+        for (unsigned i = 0; i < m_availableRecoveries.size(); ++i) {
+            AvailableRecovery recovery = m_availableRecoveries[i];
+            if (recovery.node() != node)
+                continue;
+            
+            exit.m_values[index] = ExitValue::recovery(
+                recovery.opcode(), arguments.size(), arguments.size() + 1,
+                recovery.format());
+            arguments.append(recovery.left());
+            arguments.append(recovery.right());
+            return;
+        }
+        
         LoweredNodeValue value = m_int32Values.get(node);
         if (isValid(value)) {
             addExitArgument(exit, arguments, index, ValueFormatInt32, value.value());
@@ -4329,6 +4962,29 @@
         arguments.append(value);
     }
     
+    bool doesKill(Edge edge)
+    {
+        if (edge.doesNotKill())
+            return false;
+        
+        if (edge->hasConstant())
+            return false;
+        
+        return true;
+    }
+
+    void addAvailableRecovery(
+        Node* node, RecoveryOpcode opcode, LValue left, LValue right, ValueFormat format)
+    {
+        m_availableRecoveries.append(AvailableRecovery(node, opcode, left, right, format));
+    }
+    
+    void addAvailableRecovery(
+        Edge edge, RecoveryOpcode opcode, LValue left, LValue right, ValueFormat format)
+    {
+        addAvailableRecovery(edge.node(), opcode, left, right, format);
+    }
+    
     void setInt32(Node* node, LValue value)
     {
         m_int32Values.set(node, LoweredNodeValue(value, m_highBlock));
@@ -4431,35 +5087,37 @@
     }
     TypedPointer payloadFor(LValue base, int operand)
     {
-        return addressFor(base, operand, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
+        return addressFor(base, operand, PayloadOffset);
     }
     TypedPointer tagFor(LValue base, int operand)
     {
-        return addressFor(base, operand, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
+        return addressFor(base, operand, TagOffset);
     }
-    TypedPointer addressFor(int operand)
+    TypedPointer addressFor(int operand, ptrdiff_t offset = 0)
     {
-        return addressFor(m_callFrame, operand);
+        return addressFor(VirtualRegister(operand), offset);
     }
-    TypedPointer addressFor(VirtualRegister operand)
+    TypedPointer addressFor(VirtualRegister operand, ptrdiff_t offset = 0)
     {
-        return addressFor(m_callFrame, operand.offset());
+        if (operand.isLocal())
+            return addressFor(m_captured, operand.offset(), offset);
+        return addressFor(m_callFrame, operand.offset(), offset);
     }
     TypedPointer payloadFor(int operand)
     {
-        return payloadFor(m_callFrame, operand);
+        return payloadFor(VirtualRegister(operand));
     }
     TypedPointer payloadFor(VirtualRegister operand)
     {
-        return payloadFor(m_callFrame, operand.offset());
+        return addressFor(operand, PayloadOffset);
     }
     TypedPointer tagFor(int operand)
     {
-        return tagFor(m_callFrame, operand);
+        return tagFor(VirtualRegister(operand));
     }
     TypedPointer tagFor(VirtualRegister operand)
     {
-        return tagFor(m_callFrame, operand.offset());
+        return addressFor(operand, TagOffset);
     }
     
     VM& vm() { return m_graph.m_vm; }
@@ -4471,9 +5129,11 @@
     Output m_out;
     
     LBasicBlock m_prologue;
+    LBasicBlock m_handleExceptions;
     HashMap<BasicBlock*, LBasicBlock> m_blocks;
     
     LValue m_callFrame;
+    LValue m_captured;
     LValue m_tagTypeNumber;
     LValue m_tagMask;
     
@@ -4489,6 +5149,8 @@
     
     Operands<Availability> m_availability;
     
+    Vector<AvailableRecovery, 3> m_availableRecoveries;
+    
     InPlaceAbstractState m_state;
     AbstractInterpreter<InPlaceAbstractState> m_interpreter;
     BasicBlock* m_highBlock;