DFG Arrayify slow path should be out-of-line
https://bugs.webkit.org/show_bug.cgi?id=105400

Reviewed by Gavin Barraclough.
        
The interesting bit of this change is allowing out-of-line slow path generators
to emit speculation checks. This is accomplished by having a version of
speculationCheck() that returns a jump placeholder instead of taking a jump (or
jump list) as an argument. You can then fill in that jump placeholder at a
later time, so long as you do it before OSR exit linking. Slow path generators
run before linking, so that just naturally ends up working.
        
This isn't really a big win, but we know that out-of-lining slow paths is
generally a good thing to do, so it's fair to assume that this is a move in the
right direction.

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* dfg/DFGArrayifySlowPathGenerator.h: Added.
(DFG):
(ArrayifySlowPathGenerator):
(JSC::DFG::ArrayifySlowPathGenerator::ArrayifySlowPathGenerator):
(JSC::DFG::ArrayifySlowPathGenerator::generateInternal):
* dfg/DFGOSRExitJumpPlaceholder.cpp: Added.
(DFG):
(JSC::DFG::OSRExitJumpPlaceholder::fill):
* dfg/DFGOSRExitJumpPlaceholder.h: Added.
(DFG):
(OSRExitJumpPlaceholder):
(JSC::DFG::OSRExitJumpPlaceholder::OSRExitJumpPlaceholder):
(JSC::DFG::OSRExitJumpPlaceholder::operator!):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::speculationCheck):
(DFG):
(JSC::DFG::SpeculativeJIT::arrayify):
* dfg/DFGSpeculativeJIT.h:
(SpeculativeJIT):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@138399 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt
index 8a12d17..f89d5ab 100644
--- a/Source/JavaScriptCore/CMakeLists.txt
+++ b/Source/JavaScriptCore/CMakeLists.txt
@@ -95,6 +95,7 @@
     dfg/DFGOSRExitCompiler.cpp
     dfg/DFGOSRExitCompiler32_64.cpp
     dfg/DFGOSRExitCompiler64.cpp
+    dfg/DFGOSRExitJumpPlaceholder.cpp
     dfg/DFGOperations.cpp
     dfg/DFGPhase.cpp
     dfg/DFGPredictionPropagationPhase.cpp
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 0fa5383..fbde4ee 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,45 @@
+2012-12-21  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG Arrayify slow path should be out-of-line
+        https://bugs.webkit.org/show_bug.cgi?id=105400
+
+        Reviewed by Gavin Barraclough.
+        
+        The interesting bit of this change is allowing out-of-line slow path generators
+        to emit speculation checks. This is accomplished by having a version of
+        speculationCheck() that returns a jump placeholder instead of taking a jump (or
+        jump list) as an argument. You can then fill in that jump placeholder at a
+        later time, so long as you do it before OSR exit linking. Slow path generators
+        run before linking, so that just naturally ends up working.
+        
+        This isn't really a big win, but we know that out-of-lining slow paths is
+        generally a good thing to do, so it's fair to assume that this is a move in the
+        right direction.
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Target.pri:
+        * dfg/DFGArrayifySlowPathGenerator.h: Added.
+        (DFG):
+        (ArrayifySlowPathGenerator):
+        (JSC::DFG::ArrayifySlowPathGenerator::ArrayifySlowPathGenerator):
+        (JSC::DFG::ArrayifySlowPathGenerator::generateInternal):
+        * dfg/DFGOSRExitJumpPlaceholder.cpp: Added.
+        (DFG):
+        (JSC::DFG::OSRExitJumpPlaceholder::fill):
+        * dfg/DFGOSRExitJumpPlaceholder.h: Added.
+        (DFG):
+        (OSRExitJumpPlaceholder):
+        (JSC::DFG::OSRExitJumpPlaceholder::OSRExitJumpPlaceholder):
+        (JSC::DFG::OSRExitJumpPlaceholder::operator!):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::speculationCheck):
+        (DFG):
+        (JSC::DFG::SpeculativeJIT::arrayify):
+        * dfg/DFGSpeculativeJIT.h:
+        (SpeculativeJIT):
+
 2012-12-20  Oliver Hunt  <oliver@apple.com>
 
         Finally found the problem.  Using the wrong JSContextGroup.
diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am
index 14c419b..437b2ae 100644
--- a/Source/JavaScriptCore/GNUmakefile.list.am
+++ b/Source/JavaScriptCore/GNUmakefile.list.am
@@ -172,6 +172,7 @@
 	Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.h \
 	Source/JavaScriptCore/dfg/DFGArrayMode.cpp \
 	Source/JavaScriptCore/dfg/DFGArrayMode.h \
+	Source/JavaScriptCore/dfg/DFGArrayifySlowPathGenerator.h \
 	Source/JavaScriptCore/dfg/DFGAssemblyHelpers.cpp \
 	Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h \
 	Source/JavaScriptCore/dfg/DFGBasicBlock.h \
@@ -229,6 +230,8 @@
 	Source/JavaScriptCore/dfg/DFGOSRExit.h \
 	Source/JavaScriptCore/dfg/DFGOSRExit.cpp \
 	Source/JavaScriptCore/dfg/DFGOSRExitCompilationInfo.h \
+	Source/JavaScriptCore/dfg/DFGOSRExitJumpPlaceholder.cpp \
+	Source/JavaScriptCore/dfg/DFGOSRExitJumpPlaceholder.h \
 	Source/JavaScriptCore/dfg/DFGPhase.cpp \
 	Source/JavaScriptCore/dfg/DFGPhase.h \
 	Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp \
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index c37e9a3..4c90cbd 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -58,6 +58,7 @@
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
+		0F05C3B41683CF9200BAF45B /* DFGArrayifySlowPathGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F05C3B21683CF8F00BAF45B /* DFGArrayifySlowPathGenerator.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0F0776BF14FF002B00102332 /* JITCompilationEffort.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0776BD14FF002800102332 /* JITCompilationEffort.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0F0B839A14BCF45D00885B4F /* LLIntEntrypoints.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F0B839514BCF45A00885B4F /* LLIntEntrypoints.cpp */; };
 		0F0B839B14BCF46000885B4F /* LLIntEntrypoints.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0B839614BCF45A00885B4F /* LLIntEntrypoints.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -258,6 +259,8 @@
 		0FE228EE1436AB2C00196C48 /* Options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE228EA1436AB2300196C48 /* Options.cpp */; };
 		0FEB3ECD16237F4D00AB67AD /* TypedArrayDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEB3ECB16237F4700AB67AD /* TypedArrayDescriptor.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0FEB3ECF16237F6C00AB67AD /* MacroAssembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FEB3ECE16237F6700AB67AD /* MacroAssembler.cpp */; };
+		0FEFC9AA1681A3B300567F53 /* DFGOSRExitJumpPlaceholder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FEFC9A71681A3B000567F53 /* DFGOSRExitJumpPlaceholder.cpp */; };
+		0FEFC9AB1681A3B600567F53 /* DFGOSRExitJumpPlaceholder.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEFC9A81681A3B000567F53 /* DFGOSRExitJumpPlaceholder.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0FF42731158EBD54004CB9FF /* Disassembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF4272F158EBD44004CB9FF /* Disassembler.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0FF42732158EBD58004CB9FF /* UDis86Disassembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FF42730158EBD44004CB9FF /* UDis86Disassembler.cpp */; };
 		0FF42740158EBE8B004CB9FF /* udis86_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = 0FF42734158EBD94004CB9FF /* udis86_decode.c */; };
@@ -891,6 +894,7 @@
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
+		0F05C3B21683CF8F00BAF45B /* DFGArrayifySlowPathGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGArrayifySlowPathGenerator.h; path = dfg/DFGArrayifySlowPathGenerator.h; sourceTree = "<group>"; };
 		0F0776BD14FF002800102332 /* JITCompilationEffort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITCompilationEffort.h; sourceTree = "<group>"; };
 		0F0B839514BCF45A00885B4F /* LLIntEntrypoints.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LLIntEntrypoints.cpp; path = llint/LLIntEntrypoints.cpp; sourceTree = "<group>"; };
 		0F0B839614BCF45A00885B4F /* LLIntEntrypoints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntEntrypoints.h; path = llint/LLIntEntrypoints.h; sourceTree = "<group>"; };
@@ -1095,6 +1099,8 @@
 		0FE228EB1436AB2300196C48 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Options.h; sourceTree = "<group>"; };
 		0FEB3ECB16237F4700AB67AD /* TypedArrayDescriptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypedArrayDescriptor.h; sourceTree = "<group>"; };
 		0FEB3ECE16237F6700AB67AD /* MacroAssembler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MacroAssembler.cpp; sourceTree = "<group>"; };
+		0FEFC9A71681A3B000567F53 /* DFGOSRExitJumpPlaceholder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGOSRExitJumpPlaceholder.cpp; path = dfg/DFGOSRExitJumpPlaceholder.cpp; sourceTree = "<group>"; };
+		0FEFC9A81681A3B000567F53 /* DFGOSRExitJumpPlaceholder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGOSRExitJumpPlaceholder.h; path = dfg/DFGOSRExitJumpPlaceholder.h; sourceTree = "<group>"; };
 		0FF4272F158EBD44004CB9FF /* Disassembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Disassembler.h; path = disassembler/Disassembler.h; sourceTree = "<group>"; };
 		0FF42730158EBD44004CB9FF /* UDis86Disassembler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UDis86Disassembler.cpp; path = disassembler/UDis86Disassembler.cpp; sourceTree = "<group>"; };
 		0FF42734158EBD94004CB9FF /* udis86_decode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = udis86_decode.c; path = disassembler/udis86/udis86_decode.c; sourceTree = "<group>"; };
@@ -2460,7 +2466,6 @@
 		86EC9DB31328DF44002B2AD7 /* dfg */ = {
 			isa = PBXGroup;
 			children = (
-				65987F2C167FE84B003C2F8D /* DFGOSRExitCompilationInfo.h */,
 				0F62016D143FCD2F0068B77C /* DFGAbstractState.cpp */,
 				0F62016E143FCD2F0068B77C /* DFGAbstractState.h */,
 				0F62016F143FCD2F0068B77C /* DFGAbstractValue.h */,
@@ -2468,6 +2473,7 @@
 				0F1E3A431534CBAD000F9456 /* DFGArgumentPosition.h */,
 				0F16015A156198BF00C2587C /* DFGArgumentsSimplificationPhase.cpp */,
 				0F16015B156198BF00C2587C /* DFGArgumentsSimplificationPhase.h */,
+				0F05C3B21683CF8F00BAF45B /* DFGArrayifySlowPathGenerator.h */,
 				0F63948115E48114006A597C /* DFGArrayMode.cpp */,
 				0F63948215E48114006A597C /* DFGArrayMode.h */,
 				0FC0976B1468AB4A00CF2442 /* DFGAssemblyHelpers.cpp */,
@@ -2521,10 +2527,13 @@
 				0FD82E53141DAEDE00179C94 /* DFGOSREntry.h */,
 				0FC0978E146A6F6300CF2442 /* DFGOSRExit.cpp */,
 				0FC097681468A6EF00CF2442 /* DFGOSRExit.h */,
+				65987F2C167FE84B003C2F8D /* DFGOSRExitCompilationInfo.h */,
 				0FC0978F146A6F6300CF2442 /* DFGOSRExitCompiler.cpp */,
 				0FC0976F14693AEF00CF2442 /* DFGOSRExitCompiler.h */,
 				0FC09775146943AD00CF2442 /* DFGOSRExitCompiler32_64.cpp */,
 				0FC0977014693AEF00CF2442 /* DFGOSRExitCompiler64.cpp */,
+				0FEFC9A71681A3B000567F53 /* DFGOSRExitJumpPlaceholder.cpp */,
+				0FEFC9A81681A3B000567F53 /* DFGOSRExitJumpPlaceholder.h */,
 				0FFFC94F14EF909500C72532 /* DFGPhase.cpp */,
 				0FFFC95014EF909500C72532 /* DFGPhase.h */,
 				0FFFC95114EF909500C72532 /* DFGPredictionPropagationPhase.cpp */,
@@ -3183,6 +3192,8 @@
 				0F13912A16771C36009CCB07 /* ProfilerBytecodeSequence.h in Headers */,
 				0F13912C16771C3D009CCB07 /* ProfilerProfiledBytecodes.h in Headers */,
 				A7C0C4AC168103020017011D /* JSScriptRefPrivate.h in Headers */,
+				0FEFC9AB1681A3B600567F53 /* DFGOSRExitJumpPlaceholder.h in Headers */,
+				0F05C3B41683CF9200BAF45B /* DFGArrayifySlowPathGenerator.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -3801,6 +3812,7 @@
 				0F13912916771C33009CCB07 /* ProfilerBytecodeSequence.cpp in Sources */,
 				0F13912B16771C3A009CCB07 /* ProfilerProfiledBytecodes.cpp in Sources */,
 				A7C0C4AD1681067E0017011D /* JSScriptRef.cpp in Sources */,
+				0FEFC9AA1681A3B300567F53 /* DFGOSRExitJumpPlaceholder.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri
index 788d909..666aa56 100644
--- a/Source/JavaScriptCore/Target.pri
+++ b/Source/JavaScriptCore/Target.pri
@@ -132,6 +132,7 @@
     dfg/DFGOSRExitCompiler.cpp \
     dfg/DFGOSRExitCompiler64.cpp \
     dfg/DFGOSRExitCompiler32_64.cpp \
+    dfg/DFGOSRExitJumpPlaceholder.cpp \
     dfg/DFGPhase.cpp \
     dfg/DFGPredictionPropagationPhase.cpp \
     dfg/DFGRepatch.cpp \
diff --git a/Source/JavaScriptCore/dfg/DFGArrayifySlowPathGenerator.h b/Source/JavaScriptCore/dfg/DFGArrayifySlowPathGenerator.h
new file mode 100644
index 0000000..cd40836
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGArrayifySlowPathGenerator.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef DFGArrayifySlowPathGenerator_h
+#define DFGArrayifySlowPathGenerator_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGArrayMode.h"
+#include "DFGCommon.h"
+#include "DFGOSRExitJumpPlaceholder.h"
+#include "DFGOperations.h"
+#include "DFGSlowPathGenerator.h"
+#include "DFGSpeculativeJIT.h"
+#include <wtf/Vector.h>
+
+namespace JSC { namespace DFG {
+
+class ArrayifySlowPathGenerator : public JumpingSlowPathGenerator<MacroAssembler::JumpList> {
+public:
+    ArrayifySlowPathGenerator(
+        const MacroAssembler::JumpList& from, SpeculativeJIT* jit, Node& node, GPRReg baseGPR,
+        GPRReg propertyGPR, GPRReg tempGPR, GPRReg structureGPR)
+        : JumpingSlowPathGenerator<MacroAssembler::JumpList>(from, jit)
+        , m_op(node.op())
+        , m_arrayMode(node.arrayMode())
+        , m_structure(node.op() == ArrayifyToStructure ? node.structure() : 0)
+        , m_baseGPR(baseGPR)
+        , m_propertyGPR(propertyGPR)
+        , m_tempGPR(tempGPR)
+        , m_structureGPR(structureGPR)
+    {
+        ASSERT(m_op == Arrayify || m_op == ArrayifyToStructure);
+        
+        jit->silentSpillAllRegistersImpl(false, m_plans, InvalidGPRReg);
+        
+        if (m_propertyGPR != InvalidGPRReg) {
+            switch (m_arrayMode.type()) {
+            case Array::Int32:
+            case Array::Double:
+            case Array::Contiguous:
+                m_badPropertyJump = jit->speculationCheck(Uncountable, JSValueRegs(), NoNode);
+                break;
+            default:
+                break;
+            }
+        }
+        m_badIndexingTypeJump = jit->speculationCheck(BadIndexingType, JSValueSource::unboxedCell(m_baseGPR), NoNode);
+    }
+    
+protected:
+    void generateInternal(SpeculativeJIT* jit)
+    {
+        linkFrom(jit);
+        
+        ASSERT(m_op == Arrayify || m_op == ArrayifyToStructure);
+        
+        if (m_propertyGPR != InvalidGPRReg) {
+            switch (m_arrayMode.type()) {
+            case Array::Int32:
+            case Array::Double:
+            case Array::Contiguous:
+                m_badPropertyJump.fill(jit, jit->m_jit.branch32(
+                    MacroAssembler::AboveOrEqual, m_propertyGPR,
+                    MacroAssembler::TrustedImm32(MIN_SPARSE_ARRAY_INDEX)));
+                break;
+            default:
+                break;
+            }
+        }
+        
+        for (unsigned i = 0; i < m_plans.size(); ++i)
+            jit->silentSpill(m_plans[i]);
+        switch (m_arrayMode.type()) {
+        case Array::Int32:
+            jit->callOperation(operationEnsureInt32, m_tempGPR, m_baseGPR);
+            break;
+        case Array::Double:
+            jit->callOperation(operationEnsureDouble, m_tempGPR, m_baseGPR);
+            break;
+        case Array::Contiguous:
+            if (m_arrayMode.conversion() == Array::RageConvert)
+                jit->callOperation(operationRageEnsureContiguous, m_tempGPR, m_baseGPR);
+            else
+                jit->callOperation(operationEnsureContiguous, m_tempGPR, m_baseGPR);
+            break;
+        case Array::ArrayStorage:
+        case Array::SlowPutArrayStorage:
+            jit->callOperation(operationEnsureArrayStorage, m_tempGPR, m_baseGPR);
+            break;
+        default:
+            CRASH();
+            break;
+        }
+        for (unsigned i = m_plans.size(); i--;)
+            jit->silentFill(m_plans[i], GPRInfo::regT0);
+        
+        if (m_op == ArrayifyToStructure) {
+            ASSERT(m_structure);
+            m_badIndexingTypeJump.fill(
+                jit, jit->m_jit.branchWeakPtr(
+                    MacroAssembler::NotEqual,
+                    MacroAssembler::Address(m_baseGPR, JSCell::structureOffset()),
+                    m_structure));
+        } else {
+            // Alas, we need to reload the structure because silent spilling does not save
+            // temporaries. Nor would it be useful for it to do so. Either way we're talking
+            // about a load.
+            jit->m_jit.loadPtr(
+                MacroAssembler::Address(m_baseGPR, JSCell::structureOffset()), m_structureGPR);
+            
+            // Finally, check that we have the kind of array storage that we wanted to get.
+            // Note that this is a backwards speculation check, which will result in the 
+            // bytecode operation corresponding to this arrayification being reexecuted.
+            // That's fine, since arrayification is not user-visible.
+            jit->m_jit.load8(
+                MacroAssembler::Address(m_structureGPR, Structure::indexingTypeOffset()), m_structureGPR);
+            m_badIndexingTypeJump.fill(
+                jit, jit->jumpSlowForUnwantedArrayMode(m_structureGPR, m_arrayMode));
+        }
+        
+        jumpTo(jit);
+    }
+    
+private:
+    NodeType m_op;
+    ArrayMode m_arrayMode;
+    Structure* m_structure;
+    GPRReg m_baseGPR;
+    GPRReg m_propertyGPR;
+    GPRReg m_tempGPR;
+    GPRReg m_structureGPR;
+    OSRExitJumpPlaceholder m_badPropertyJump;
+    OSRExitJumpPlaceholder m_badIndexingTypeJump;
+    Vector<SilentRegisterSavePlan, 2> m_plans;
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGArrayifySlowPathGenerator_h
+
diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitJumpPlaceholder.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitJumpPlaceholder.cpp
new file mode 100644
index 0000000..fec99ec
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGOSRExitJumpPlaceholder.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "DFGOSRExitJumpPlaceholder.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGJITCompiler.h"
+#include "DFGSpeculativeJIT.h"
+
+namespace JSC { namespace DFG {
+
+void OSRExitJumpPlaceholder::fill(JITCompiler& jit, const MacroAssembler::JumpList& jumps)
+{
+    if (!*this)
+        return;
+    jit.m_exitCompilationInfo[m_index].m_failureJumps = jumps;
+}
+
+void OSRExitJumpPlaceholder::fill(SpeculativeJIT* jit, const MacroAssembler::JumpList& jumps)
+{
+    fill(jit->m_jit, jumps);
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitJumpPlaceholder.h b/Source/JavaScriptCore/dfg/DFGOSRExitJumpPlaceholder.h
new file mode 100644
index 0000000..4e016a4
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGOSRExitJumpPlaceholder.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef DFGOSRExitJumpPlaceholder_h
+#define DFGOSRExitJumpPlaceholder_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGCommon.h"
+#include "MacroAssembler.h"
+
+namespace JSC { namespace DFG {
+
+class JITCompiler;
+class SpeculativeJIT;
+
+class OSRExitJumpPlaceholder {
+public:
+    OSRExitJumpPlaceholder()
+        : m_index(std::numeric_limits<unsigned>::max())
+    {
+    }
+
+private:
+    friend class SpeculativeJIT;
+    
+    OSRExitJumpPlaceholder(unsigned index)
+        : m_index(index)
+    {
+    }
+
+public:
+    bool operator!() const { return m_index == std::numeric_limits<unsigned>::max(); }
+    
+    void fill(JITCompiler&, const MacroAssembler::JumpList&);
+    void fill(SpeculativeJIT*, const MacroAssembler::JumpList&);
+    
+private:
+    unsigned m_index;
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGOSRExitJumpPlaceholder_h
+
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 8549142..bd3fda2 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -29,6 +29,7 @@
 #if ENABLE(DFG_JIT)
 
 #include "Arguments.h"
+#include "DFGArrayifySlowPathGenerator.h"
 #include "DFGCallArrayAllocatorSlowPathGenerator.h"
 #include "DFGSlowPathGenerator.h"
 #include "LinkBuffer.h"
@@ -119,6 +120,23 @@
     speculationCheck(kind, jsValueSource, nodeUse.index(), jumpToFail);
 }
 
+OSRExitJumpPlaceholder SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex)
+{
+    if (!m_compileOkay)
+        return OSRExitJumpPlaceholder();
+    ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes);
+    unsigned index = m_jit.codeBlock()->numberOfOSRExits();
+    m_jit.appendExitInfo();
+    m_jit.codeBlock()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(nodeIndex), this, m_stream->size()));
+    return OSRExitJumpPlaceholder(index);
+}
+
+OSRExitJumpPlaceholder SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse)
+{
+    ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes);
+    return speculationCheck(kind, jsValueSource, nodeUse.index());
+}
+
 void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, const MacroAssembler::JumpList& jumpsToFail)
 {
     if (!m_compileOkay)
@@ -548,11 +566,11 @@
     }
         
     // We can skip all that comes next if we already have array storage.
-    MacroAssembler::JumpList done;
+    MacroAssembler::JumpList slowPath;
     
     if (node.op() == ArrayifyToStructure) {
-        done.append(m_jit.branchWeakPtr(
-            JITCompiler::Equal,
+        slowPath.append(m_jit.branchWeakPtr(
+            JITCompiler::NotEqual,
             JITCompiler::Address(baseReg, JSCell::structureOffset()),
             node.structure()));
     } else {
@@ -562,77 +580,12 @@
         m_jit.load8(
             MacroAssembler::Address(structureGPR, Structure::indexingTypeOffset()), tempGPR);
         
-        done = jumpSlowForUnwantedArrayMode(tempGPR, node.arrayMode(), true);
-    }
-        
-    // If we're allegedly creating contiguous storage and the index is bogus, then
-    // just don't.
-    if (propertyReg != InvalidGPRReg) {
-        switch (node.arrayMode().type()) {
-        case Array::Int32:
-        case Array::Double:
-        case Array::Contiguous:
-            speculationCheck(
-                Uncountable, JSValueRegs(), NoNode,
-                m_jit.branch32(
-                    MacroAssembler::AboveOrEqual, propertyReg, TrustedImm32(MIN_SPARSE_ARRAY_INDEX)));
-            break;
-        default:
-            break;
-        }
+        slowPath.append(jumpSlowForUnwantedArrayMode(tempGPR, node.arrayMode()));
     }
     
-    // Now call out to create the array storage.
-    silentSpillAllRegisters(tempGPR);
-    switch (node.arrayMode().type()) {
-    case Array::Int32:
-        callOperation(operationEnsureInt32, tempGPR, baseReg);
-        break;
-    case Array::Double:
-        callOperation(operationEnsureDouble, tempGPR, baseReg);
-        break;
-    case Array::Contiguous:
-        if (node.arrayMode().conversion() == Array::RageConvert)
-            callOperation(operationRageEnsureContiguous, tempGPR, baseReg);
-        else
-            callOperation(operationEnsureContiguous, tempGPR, baseReg);
-        break;
-    case Array::ArrayStorage:
-    case Array::SlowPutArrayStorage:
-        callOperation(operationEnsureArrayStorage, tempGPR, baseReg);
-        break;
-    default:
-        CRASH();
-        break;
-    }
-    silentFillAllRegisters(tempGPR);
+    addSlowPathGenerator(adoptPtr(new ArrayifySlowPathGenerator(
+        slowPath, this, node, baseReg, propertyReg, tempGPR, structureGPR)));
     
-    if (node.op() == ArrayifyToStructure) {
-        speculationCheck(
-            BadIndexingType, JSValueSource::unboxedCell(baseReg), NoNode,
-            m_jit.branchWeakPtr(
-                JITCompiler::NotEqual,
-                JITCompiler::Address(baseReg, JSCell::structureOffset()),
-                node.structure()));
-    } else {
-        // Alas, we need to reload the structure because silent spilling does not save
-        // temporaries. Nor would it be useful for it to do so. Either way we're talking
-        // about a load.
-        m_jit.loadPtr(
-            MacroAssembler::Address(baseReg, JSCell::structureOffset()), structureGPR);
-    
-        // Finally, check that we have the kind of array storage that we wanted to get.
-        // Note that this is a backwards speculation check, which will result in the 
-        // bytecode operation corresponding to this arrayification being reexecuted.
-        // That's fine, since arrayification is not user-visible.
-        m_jit.load8(
-            MacroAssembler::Address(structureGPR, Structure::indexingTypeOffset()), structureGPR);
-        speculationCheck(
-            BadIndexingType, JSValueSource::unboxedCell(baseReg), NoNode,
-            jumpSlowForUnwantedArrayMode(structureGPR, node.arrayMode()));
-    }
-    
-    done.link(&m_jit);
     noResult(m_compileIndex);
 }
 
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index b684282..5ea1076 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -34,6 +34,7 @@
 #include "DFGGenerationInfo.h"
 #include "DFGJITCompiler.h"
 #include "DFGOSRExit.h"
+#include "DFGOSRExitJumpPlaceholder.h"
 #include "DFGOperations.h"
 #include "DFGSilentRegisterSavePlan.h"
 #include "DFGValueSource.h"
@@ -2445,6 +2446,9 @@
     // Add a speculation check without additional recovery.
     void speculationCheck(ExitKind, JSValueSource, NodeIndex, MacroAssembler::Jump jumpToFail);
     void speculationCheck(ExitKind, JSValueSource, Edge, MacroAssembler::Jump jumpToFail);
+    // Add a speculation check without additional recovery, and with a promise to supply a jump later.
+    OSRExitJumpPlaceholder speculationCheck(ExitKind, JSValueSource, NodeIndex);
+    OSRExitJumpPlaceholder speculationCheck(ExitKind, JSValueSource, Edge);
     // Add a set of speculation checks without additional recovery.
     void speculationCheck(ExitKind, JSValueSource, NodeIndex, const MacroAssembler::JumpList& jumpsToFail);
     void speculationCheck(ExitKind, JSValueSource, Edge, const MacroAssembler::JumpList& jumpsToFail);