Array checks should use the structure, not the class info
https://bugs.webkit.org/show_bug.cgi?id=93150

Reviewed by Mark Hahnenberg.

This changes all array checks used in array accesses (get, put, get length,
push, pop) to use the structure, not the class info. Additionally, these
checks in the LLInt and baseline JIT record the structure in an ArrayProfile,
so that the DFG can know exactly what structure to check for.
        
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* bytecode/ArrayProfile.cpp: Added.
(JSC):
(JSC::ArrayProfile::computeUpdatedPrediction):
* bytecode/ArrayProfile.h: Added.
(JSC):
(JSC::arrayModeFromStructure):
(ArrayProfile):
(JSC::ArrayProfile::ArrayProfile):
(JSC::ArrayProfile::bytecodeOffset):
(JSC::ArrayProfile::addressOfLastSeenStructure):
(JSC::ArrayProfile::observeStructure):
(JSC::ArrayProfile::expectedStructure):
(JSC::ArrayProfile::structureIsPolymorphic):
(JSC::ArrayProfile::hasDefiniteStructure):
(JSC::ArrayProfile::observedArrayModes):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dump):
(JSC::CodeBlock::getArrayProfile):
(JSC):
(JSC::CodeBlock::getOrAddArrayProfile):
(JSC::CodeBlock::updateAllPredictionsAndCountLiveness):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::executionEntryCount):
(JSC::CodeBlock::numberOfArrayProfiles):
(JSC::CodeBlock::arrayProfiles):
(JSC::CodeBlock::addArrayProfile):
(CodeBlock):
* bytecode/Instruction.h:
(JSC):
(JSC::Instruction::Instruction):
* bytecode/Opcode.h:
(JSC):
(JSC::padOpcodeName):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitGetArgumentByVal):
(JSC::BytecodeGenerator::emitGetByVal):
(JSC::BytecodeGenerator::emitPutByVal):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::initialize):
(JSC::DFG::AbstractState::execute):
* dfg/DFGAbstractValue.h:
(JSC::DFG::StructureAbstractValue::hasSingleton):
(StructureAbstractValue):
(JSC::DFG::StructureAbstractValue::singleton):
* dfg/DFGArgumentsSimplificationPhase.cpp:
(JSC::DFG::ArgumentsSimplificationPhase::run):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::speculateArray):
(DFG):
(JSC::DFG::SpeculativeJIT::compile):
(JSC::DFG::SpeculativeJIT::checkArgumentTypes):
(JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage):
* dfg/DFGSpeculativeJIT.h:
(SpeculativeJIT):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStructureCheckHoistingPhase.cpp:
(JSC::DFG::StructureCheckHoistingPhase::run):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::privateCompilePatchGetArrayLength):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::privateCompilePatchGetArrayLength):
* llint/LLIntOffsetsExtractor.cpp:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/Structure.h:
(Structure):
(JSC::Structure::classInfoOffset):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@125637 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt
index 146a119..317814a 100644
--- a/Source/JavaScriptCore/CMakeLists.txt
+++ b/Source/JavaScriptCore/CMakeLists.txt
@@ -39,6 +39,7 @@
     
     assembler/LinkBuffer.cpp
 
+    bytecode/ArrayProfile.cpp
     bytecode/CallLinkInfo.cpp
     bytecode/CallLinkStatus.cpp
     bytecode/CodeBlock.cpp
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index bf11c81..a2b7851 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,99 @@
+2012-08-13  Filip Pizlo  <fpizlo@apple.com>
+
+        Array checks should use the structure, not the class info
+        https://bugs.webkit.org/show_bug.cgi?id=93150
+
+        Reviewed by Mark Hahnenberg.
+
+        This changes all array checks used in array accesses (get, put, get length,
+        push, pop) to use the structure, not the class info. Additionally, these
+        checks in the LLInt and baseline JIT record the structure in an ArrayProfile,
+        so that the DFG can know exactly what structure to check for.
+        
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Target.pri:
+        * bytecode/ArrayProfile.cpp: Added.
+        (JSC):
+        (JSC::ArrayProfile::computeUpdatedPrediction):
+        * bytecode/ArrayProfile.h: Added.
+        (JSC):
+        (JSC::arrayModeFromStructure):
+        (ArrayProfile):
+        (JSC::ArrayProfile::ArrayProfile):
+        (JSC::ArrayProfile::bytecodeOffset):
+        (JSC::ArrayProfile::addressOfLastSeenStructure):
+        (JSC::ArrayProfile::observeStructure):
+        (JSC::ArrayProfile::expectedStructure):
+        (JSC::ArrayProfile::structureIsPolymorphic):
+        (JSC::ArrayProfile::hasDefiniteStructure):
+        (JSC::ArrayProfile::observedArrayModes):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dump):
+        (JSC::CodeBlock::getArrayProfile):
+        (JSC):
+        (JSC::CodeBlock::getOrAddArrayProfile):
+        (JSC::CodeBlock::updateAllPredictionsAndCountLiveness):
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::executionEntryCount):
+        (JSC::CodeBlock::numberOfArrayProfiles):
+        (JSC::CodeBlock::arrayProfiles):
+        (JSC::CodeBlock::addArrayProfile):
+        (CodeBlock):
+        * bytecode/Instruction.h:
+        (JSC):
+        (JSC::Instruction::Instruction):
+        * bytecode/Opcode.h:
+        (JSC):
+        (JSC::padOpcodeName):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitGetArgumentByVal):
+        (JSC::BytecodeGenerator::emitGetByVal):
+        (JSC::BytecodeGenerator::emitPutByVal):
+        * dfg/DFGAbstractState.cpp:
+        (JSC::DFG::AbstractState::initialize):
+        (JSC::DFG::AbstractState::execute):
+        * dfg/DFGAbstractValue.h:
+        (JSC::DFG::StructureAbstractValue::hasSingleton):
+        (StructureAbstractValue):
+        (JSC::DFG::StructureAbstractValue::singleton):
+        * dfg/DFGArgumentsSimplificationPhase.cpp:
+        (JSC::DFG::ArgumentsSimplificationPhase::run):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::speculateArray):
+        (DFG):
+        (JSC::DFG::SpeculativeJIT::compile):
+        (JSC::DFG::SpeculativeJIT::checkArgumentTypes):
+        (JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage):
+        * dfg/DFGSpeculativeJIT.h:
+        (SpeculativeJIT):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGStructureCheckHoistingPhase.cpp:
+        (JSC::DFG::StructureCheckHoistingPhase::run):
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emit_op_get_by_val):
+        (JSC::JIT::emit_op_put_by_val):
+        (JSC::JIT::privateCompilePatchGetArrayLength):
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::emit_op_get_by_val):
+        (JSC::JIT::emit_op_put_by_val):
+        (JSC::JIT::privateCompilePatchGetArrayLength):
+        * llint/LLIntOffsetsExtractor.cpp:
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * runtime/Structure.h:
+        (Structure):
+        (JSC::Structure::classInfoOffset):
+
 2012-08-14  Gabor Ballabas  <gaborb@inf.u-szeged.hu>
 
         Rename functions in the ARM port of DFG-JIT for better code readability.
diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am
index ab8b110..0be3ef8 100644
--- a/Source/JavaScriptCore/GNUmakefile.list.am
+++ b/Source/JavaScriptCore/GNUmakefile.list.am
@@ -82,6 +82,8 @@
 	Source/JavaScriptCore/assembler/RepatchBuffer.h \
 	Source/JavaScriptCore/assembler/SH4Assembler.h \
 	Source/JavaScriptCore/assembler/X86Assembler.h \
+	Source/JavaScriptCore/bytecode/ArrayProfile.cpp \
+	Source/JavaScriptCore/bytecode/ArrayProfile.h \
 	Source/JavaScriptCore/bytecode/BytecodeConventions.h \
 	Source/JavaScriptCore/bytecode/CallLinkInfo.cpp \
 	Source/JavaScriptCore/bytecode/CallLinkInfo.h \
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
index 2efa840..e91baa4 100644
--- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
+++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
@@ -1530,6 +1530,14 @@
 			Name="bytecode"
 			>
 			<File
+				RelativePath="..\..\bytecode\ArrayProfile.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\bytecode\ArrayProfile.h"
+				>
+			</File>
+			<File
 				RelativePath="..\..\bytecode\CallLinkInfo.cpp"
 				>
 			</File>
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index add3119..e324521 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -140,6 +140,8 @@
 		0F620179143FCD480068B77C /* DFGAbstractState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F62016D143FCD2F0068B77C /* DFGAbstractState.cpp */; };
 		0F63943F15C75F19006A597C /* DFGStructureCheckHoistingPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F63943D15C75F14006A597C /* DFGStructureCheckHoistingPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0F63944015C75F1D006A597C /* DFGStructureCheckHoistingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F63943C15C75F14006A597C /* DFGStructureCheckHoistingPhase.cpp */; };
+		0F63945415D07055006A597C /* ArrayProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F63945115D07051006A597C /* ArrayProfile.cpp */; };
+		0F63945515D07057006A597C /* ArrayProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F63945215D07051006A597C /* ArrayProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0F66E16B14DF3F1600B7B2E4 /* DFGAdjacencyList.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F66E16814DF3F1300B7B2E4 /* DFGAdjacencyList.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0F66E16C14DF3F1600B7B2E4 /* DFGEdge.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F66E16914DF3F1300B7B2E4 /* DFGEdge.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0F766D2815A8CC1E008F363E /* JITStubRoutine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F766D2615A8CC1B008F363E /* JITStubRoutine.cpp */; };
@@ -889,6 +891,8 @@
 		0F620172143FCD2F0068B77C /* DFGVariableAccessData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVariableAccessData.h; path = dfg/DFGVariableAccessData.h; sourceTree = "<group>"; };
 		0F63943C15C75F14006A597C /* DFGStructureCheckHoistingPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGStructureCheckHoistingPhase.cpp; path = dfg/DFGStructureCheckHoistingPhase.cpp; sourceTree = "<group>"; };
 		0F63943D15C75F14006A597C /* DFGStructureCheckHoistingPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStructureCheckHoistingPhase.h; path = dfg/DFGStructureCheckHoistingPhase.h; sourceTree = "<group>"; };
+		0F63945115D07051006A597C /* ArrayProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayProfile.cpp; sourceTree = "<group>"; };
+		0F63945215D07051006A597C /* ArrayProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayProfile.h; sourceTree = "<group>"; };
 		0F66E16814DF3F1300B7B2E4 /* DFGAdjacencyList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGAdjacencyList.h; path = dfg/DFGAdjacencyList.h; sourceTree = "<group>"; };
 		0F66E16914DF3F1300B7B2E4 /* DFGEdge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGEdge.h; path = dfg/DFGEdge.h; sourceTree = "<group>"; };
 		0F766D1C15A5028D008F363E /* JITStubRoutine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITStubRoutine.h; sourceTree = "<group>"; };
@@ -2407,6 +2411,8 @@
 		969A078F0ED1D3AE00F1F681 /* bytecode */ = {
 			isa = PBXGroup;
 			children = (
+				0F63945115D07051006A597C /* ArrayProfile.cpp */,
+				0F63945215D07051006A597C /* ArrayProfile.h */,
 				0F56A1D415001CF2002992B1 /* ExecutionCounter.cpp */,
 				0F56A1D115000F31002992B1 /* ExecutionCounter.h */,
 				0FB5467C14F5CFD3002C2989 /* MethodOfGettingAValueProfile.cpp */,
@@ -2867,6 +2873,7 @@
 				0F766D4415B2A3C0008F363E /* DFGRegisterSet.h in Headers */,
 				0F766D4615B3701F008F363E /* DFGScratchRegisterAllocator.h in Headers */,
 				0F63943F15C75F19006A597C /* DFGStructureCheckHoistingPhase.h in Headers */,
+				0F63945515D07057006A597C /* ArrayProfile.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -3465,6 +3472,7 @@
 				0F766D3415AE2538008F363E /* JumpReplacementWatchpoint.cpp in Sources */,
 				0F766D3815AE4A1C008F363E /* StructureStubClearingWatchpoint.cpp in Sources */,
 				0F63944015C75F1D006A597C /* DFGStructureCheckHoistingPhase.cpp in Sources */,
+				0F63945415D07055006A597C /* ArrayProfile.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri
index 3d0e41d..5340032 100644
--- a/Source/JavaScriptCore/Target.pri
+++ b/Source/JavaScriptCore/Target.pri
@@ -46,6 +46,7 @@
     assembler/LinkBuffer.cpp \
     assembler/MacroAssemblerARM.cpp \
     assembler/MacroAssemblerSH4.cpp \
+    bytecode/ArrayProfile.cpp \
     bytecode/CallLinkInfo.cpp \
     bytecode/CallLinkStatus.cpp \
     bytecode/CodeBlock.cpp \
diff --git a/Source/JavaScriptCore/bytecode/ArrayProfile.cpp b/Source/JavaScriptCore/bytecode/ArrayProfile.cpp
new file mode 100644
index 0000000..6b97f78
--- /dev/null
+++ b/Source/JavaScriptCore/bytecode/ArrayProfile.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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 "ArrayProfile.h"
+
+namespace JSC {
+
+void ArrayProfile::computeUpdatedPrediction(OperationInProgress operation)
+{
+    if (m_lastSeenStructure) {
+        m_observedArrayModes |= arrayModeFromStructure(m_lastSeenStructure);
+        if (!m_structureIsPolymorphic) {
+            if (!m_expectedStructure)
+                m_expectedStructure = m_lastSeenStructure;
+            else if (m_expectedStructure != m_lastSeenStructure) {
+                m_expectedStructure = 0;
+                m_structureIsPolymorphic = true;
+            }
+        }
+        m_lastSeenStructure = 0;
+    }
+    
+    if (operation == Collection
+        && m_expectedStructure
+        && !Heap::isMarked(m_expectedStructure)) {
+        m_expectedStructure = 0;
+        m_structureIsPolymorphic = true;
+    }
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/bytecode/ArrayProfile.h b/Source/JavaScriptCore/bytecode/ArrayProfile.h
new file mode 100644
index 0000000..5a656e2
--- /dev/null
+++ b/Source/JavaScriptCore/bytecode/ArrayProfile.h
@@ -0,0 +1,104 @@
+/*
+ * 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 ArrayProfile_h
+#define ArrayProfile_h
+
+#include "JSArray.h"
+#include "Structure.h"
+#include <wtf/HashMap.h>
+#include <wtf/SegmentedVector.h>
+
+namespace JSC {
+
+class LLIntOffsetsExtractor;
+
+typedef unsigned ArrayModes;
+
+static const unsigned IsNotArray = 1;
+static const unsigned IsJSArray  = 2;
+
+inline ArrayModes arrayModeFromStructure(Structure* structure)
+{
+    if (structure->classInfo() == &JSArray::s_info)
+        return IsJSArray;
+    return IsNotArray;
+}
+
+class ArrayProfile {
+public:
+    ArrayProfile()
+        : m_bytecodeOffset(std::numeric_limits<unsigned>::max())
+        , m_lastSeenStructure(0)
+        , m_expectedStructure(0)
+        , m_structureIsPolymorphic(false)
+        , m_observedArrayModes(0)
+    {
+    }
+    
+    ArrayProfile(unsigned bytecodeOffset)
+        : m_bytecodeOffset(bytecodeOffset)
+        , m_lastSeenStructure(0)
+        , m_expectedStructure(0)
+        , m_structureIsPolymorphic(false)
+        , m_observedArrayModes(0)
+    {
+    }
+    
+    unsigned bytecodeOffset() const { return m_bytecodeOffset; }
+    
+    Structure** addressOfLastSeenStructure() { return &m_lastSeenStructure; }
+    
+    void observeStructure(Structure* structure)
+    {
+        m_lastSeenStructure = structure;
+    }
+    
+    void computeUpdatedPrediction(OperationInProgress operation = NoOperation);
+    
+    Structure* expectedStructure() const { return m_expectedStructure; }
+    bool structureIsPolymorphic() const { return m_structureIsPolymorphic; }
+    bool hasDefiniteStructure() const
+    {
+        return !structureIsPolymorphic() && m_expectedStructure;
+    }
+    ArrayModes observedArrayModes() const { return m_observedArrayModes; }
+    
+private:
+    friend class LLIntOffsetsExtractor;
+    
+    unsigned m_bytecodeOffset;
+    Structure* m_lastSeenStructure;
+    Structure* m_expectedStructure;
+    bool m_structureIsPolymorphic;
+    ArrayModes m_observedArrayModes;
+};
+
+typedef SegmentedVector<ArrayProfile, 4, 0> ArrayProfileVector;
+
+} // namespace JSC
+
+#endif // ArrayProfile_h
+
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index 0e2a98b..ce45b15 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -1155,6 +1155,7 @@
             dataLog("[%4d] get_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
             dumpBytecodeCommentAndNewLine(location);
             it++;
+            it++;
             break;
         }
         case op_get_argument_by_val: {
@@ -1164,6 +1165,7 @@
             dataLog("[%4d] get_argument_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
             dumpBytecodeCommentAndNewLine(location);
             ++it;
+            ++it;
             break;
         }
         case op_get_by_pname: {
@@ -1183,6 +1185,7 @@
             int r2 = (++it)->u.operand;
             dataLog("[%4d] put_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
             dumpBytecodeCommentAndNewLine(location);
+            ++it;
             break;
         }
         case op_del_by_val: {
@@ -2769,6 +2772,23 @@
 #endif
 
 #if ENABLE(VALUE_PROFILER)
+ArrayProfile* CodeBlock::getArrayProfile(unsigned bytecodeOffset)
+{
+    for (unsigned i = 0; i < m_arrayProfiles.size(); ++i) {
+        if (m_arrayProfiles[i].bytecodeOffset() == bytecodeOffset)
+            return &m_arrayProfiles[i];
+    }
+    return 0;
+}
+
+ArrayProfile* CodeBlock::getOrAddArrayProfile(unsigned bytecodeOffset)
+{
+    ArrayProfile* result = getArrayProfile(bytecodeOffset);
+    if (result)
+        return result;
+    return addArrayProfile(bytecodeOffset);
+}
+
 void CodeBlock::updateAllPredictionsAndCountLiveness(
     OperationInProgress operation, unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles)
 {
@@ -2792,6 +2812,12 @@
 #if ENABLE(DFG_JIT)
     m_lazyOperandValueProfiles.computeUpdatedPredictions(operation);
 #endif
+    
+    // Don't count the array profiles towards statistics, since each array profile
+    // site also has a value profile site - so we already know whether or not it's
+    // live.
+    for (unsigned i = m_arrayProfiles.size(); i--;)
+        m_arrayProfiles[i].computeUpdatedPrediction(operation);
 }
 
 void CodeBlock::updateAllPredictions(OperationInProgress operation)
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h
index 2a7d212..ba3769a 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.h
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.h
@@ -30,6 +30,7 @@
 #ifndef CodeBlock_h
 #define CodeBlock_h
 
+#include "ArrayProfile.h"
 #include "BytecodeConventions.h"
 #include "CallLinkInfo.h"
 #include "CallReturnOffsetToBytecodeOffset.h"
@@ -751,8 +752,18 @@
         }
         
         unsigned executionEntryCount() const { return m_executionEntryCount; }
-#endif
 
+        unsigned numberOfArrayProfiles() const { return m_arrayProfiles.size(); }
+        const ArrayProfileVector& arrayProfiles() { return m_arrayProfiles; }
+        ArrayProfile* addArrayProfile(unsigned bytecodeOffset)
+        {
+            m_arrayProfiles.append(ArrayProfile(bytecodeOffset));
+            return &m_arrayProfiles.last();
+        }
+        ArrayProfile* getArrayProfile(unsigned bytecodeOffset);
+        ArrayProfile* getOrAddArrayProfile(unsigned bytecodeOffset);
+#endif
+        
         unsigned globalResolveInfoCount() const
         {
 #if ENABLE(JIT)    
@@ -1333,6 +1344,7 @@
         SegmentedVector<ValueProfile, 8> m_valueProfiles;
         SegmentedVector<RareCaseProfile, 8> m_rareCaseProfiles;
         SegmentedVector<RareCaseProfile, 8> m_specialFastCaseProfiles;
+        ArrayProfileVector m_arrayProfiles;
         unsigned m_executionEntryCount;
 #endif
 
diff --git a/Source/JavaScriptCore/bytecode/Instruction.h b/Source/JavaScriptCore/bytecode/Instruction.h
index 2e94b45..6c1260a 100644
--- a/Source/JavaScriptCore/bytecode/Instruction.h
+++ b/Source/JavaScriptCore/bytecode/Instruction.h
@@ -46,6 +46,7 @@
     // curently actually use PolymorphicAccessStructureLists, which we should).  Anyway, this seems like the best
     // solution for now - will need to something smarter if/when we actually want mixed-mode operation.
 
+    class ArrayProfile;
     class JSCell;
     class Structure;
     class StructureChain;
@@ -190,6 +191,7 @@
         Instruction(LLIntCallLinkInfo* callLinkInfo) { u.callLinkInfo = callLinkInfo; }
         
         Instruction(ValueProfile* profile) { u.profile = profile; }
+        Instruction(ArrayProfile* profile) { u.arrayProfile = profile; }
         
         Instruction(WriteBarrier<Unknown>* registerPointer) { u.registerPointer = registerPointer; }
         
@@ -205,6 +207,7 @@
             PropertySlot::GetValueFunc getterFunc;
             LLIntCallLinkInfo* callLinkInfo;
             ValueProfile* profile;
+            ArrayProfile* arrayProfile;
             void* pointer;
             bool* predicatePointer;
         } u;
diff --git a/Source/JavaScriptCore/bytecode/Opcode.h b/Source/JavaScriptCore/bytecode/Opcode.h
index 4308e79..777b487 100644
--- a/Source/JavaScriptCore/bytecode/Opcode.h
+++ b/Source/JavaScriptCore/bytecode/Opcode.h
@@ -132,10 +132,10 @@
         macro(op_put_by_id_replace, 9) \
         macro(op_put_by_id_generic, 9) \
         macro(op_del_by_id, 4) \
-        macro(op_get_by_val, 5) /* has value profiling */ \
-        macro(op_get_argument_by_val, 5) /* must be the same size as op_get_by_val */ \
+        macro(op_get_by_val, 6) /* has value profiling */ \
+        macro(op_get_argument_by_val, 6) /* must be the same size as op_get_by_val */ \
         macro(op_get_by_pname, 7) \
-        macro(op_put_by_val, 4) \
+        macro(op_put_by_val, 5) \
         macro(op_del_by_val, 4) \
         macro(op_put_by_index, 4) \
         macro(op_put_getter_setter, 5) \
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index 14a69b5..78d2852 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -708,6 +708,15 @@
 }
 #endif
 
+ArrayProfile* BytecodeGenerator::newArrayProfile()
+{
+#if ENABLE(VALUE_PROFILER)
+    return m_codeBlock->addArrayProfile(instructions().size());
+#else
+    return 0;
+#endif
+}
+
 ValueProfile* BytecodeGenerator::emitProfiledOpcode(OpcodeID opcodeID)
 {
 #if ENABLE(VALUE_PROFILER)
@@ -1669,11 +1678,13 @@
 
 RegisterID* BytecodeGenerator::emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
 {
+    ArrayProfile* arrayProfile = newArrayProfile();
     ValueProfile* profile = emitProfiledOpcode(op_get_argument_by_val);
     instructions().append(dst->index());
     ASSERT(base->index() == m_codeBlock->argumentsRegister());
     instructions().append(base->index());
     instructions().append(property->index());
+    instructions().append(arrayProfile);
     instructions().append(profile);
     return dst;
 }
@@ -1693,20 +1704,24 @@
             return dst;
         }
     }
+    ArrayProfile* arrayProfile = newArrayProfile();
     ValueProfile* profile = emitProfiledOpcode(op_get_by_val);
     instructions().append(dst->index());
     instructions().append(base->index());
     instructions().append(property->index());
+    instructions().append(arrayProfile);
     instructions().append(profile);
     return dst;
 }
 
 RegisterID* BytecodeGenerator::emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value)
 {
+    ArrayProfile* arrayProfile = newArrayProfile();
     emitOpcode(op_put_by_val);
     instructions().append(base->index());
     instructions().append(property->index());
     instructions().append(value->index());
+    instructions().append(arrayProfile);
     return value;
 }
 
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index 490991f..9c09441 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -555,6 +555,7 @@
 #endif
 
         void emitOpcode(OpcodeID);
+        ArrayProfile* newArrayProfile();
         ValueProfile* emitProfiledOpcode(OpcodeID);
         void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index);
         void retrieveLastUnaryOp(int& dstIndex, int& srcIndex);
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index 4f02ee7..e09b940 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -106,8 +106,6 @@
         SpeculatedType prediction = node.variableAccessData()->prediction();
         if (isInt32Speculation(prediction))
             root->valuesAtHead.argument(i).set(SpecInt32);
-        else if (isArraySpeculation(prediction))
-            root->valuesAtHead.argument(i).set(SpecArray);
         else if (isBooleanSpeculation(prediction))
             root->valuesAtHead.argument(i).set(SpecBoolean);
         else if (isInt8ArraySpeculation(prediction))
@@ -290,10 +288,7 @@
         SpeculatedType predictedType = node.variableAccessData()->argumentAwarePrediction();
         if (isInt32Speculation(predictedType))
             speculateInt32Unary(node);
-        else if (isArraySpeculation(predictedType)) {
-            node.setCanExit(!isArraySpeculation(forNode(node.child1()).m_type));
-            forNode(node.child1()).filter(SpecArray);
-        } else if (isCellSpeculation(predictedType)) {
+        else if (isCellSpeculation(predictedType)) {
             node.setCanExit(!isCellSpeculation(forNode(node.child1()).m_type));
             forNode(node.child1()).filter(SpecCell);
         } else if (isBooleanSpeculation(predictedType))
@@ -867,7 +862,7 @@
             m_isValid = false;
             break;
         }
-        if (!isActionableArraySpeculation(m_graph[node.child1()].prediction()) || !m_graph[node.child2()].shouldSpeculateInteger()) {
+        if (!m_graph[node.child2()].shouldSpeculateInteger() || (!node.child3() && !m_graph[node.child1()].shouldSpeculateArguments())) {
             clobberWorld(node.codeOrigin, indexInBlock);
             forNode(nodeIndex).makeTop();
             break;
@@ -942,8 +937,7 @@
             forNode(nodeIndex).set(SpecDouble);
             break;
         }
-        ASSERT(m_graph[node.child1()].shouldSpeculateArray());
-        forNode(node.child1()).filter(SpecArray);
+        forNode(node.child1()).filter(SpecCell);
         forNode(node.child2()).filter(SpecInt32);
         forNode(nodeIndex).makeTop();
         break;
@@ -1053,8 +1047,7 @@
             forNode(child3).filter(SpecNumber);
             break;
         }
-        ASSERT(m_graph[child1].shouldSpeculateArray());
-        forNode(child1).filter(SpecArray);
+        forNode(child1).filter(SpecCell);
         forNode(child2).filter(SpecInt32);
         if (node.op() == PutByValSafe)
             clobberWorld(node.codeOrigin, indexInBlock);
@@ -1063,13 +1056,13 @@
             
     case ArrayPush:
         node.setCanExit(true);
-        forNode(node.child1()).filter(SpecArray);
+        forNode(node.child1()).filter(SpecCell);
         forNode(nodeIndex).set(SpecNumber);
         break;
             
     case ArrayPop:
         node.setCanExit(true);
-        forNode(node.child1()).filter(SpecArray);
+        forNode(node.child1()).filter(SpecCell);
         forNode(nodeIndex).makeTop();
         break;
             
@@ -1354,7 +1347,7 @@
             
     case GetArrayLength:
         node.setCanExit(true);
-        forNode(node.child1()).filter(SpecArray);
+        forNode(node.child1()).filter(SpecCell);
         forNode(nodeIndex).set(SpecInt32);
         break;
 
@@ -1453,12 +1446,9 @@
         forNode(nodeIndex).clear(); // The result is not a JS value.
         break;
     case GetIndexedPropertyStorage: {
+        ASSERT(m_graph[node.child1()].prediction());
+        ASSERT(m_graph[node.child2()].shouldSpeculateInteger());
         node.setCanExit(true); // Lies, but this is (almost) always followed by GetByVal, which does exit. So no point in trying to be more precise.
-        SpeculatedType basePrediction = m_graph[node.child2()].prediction();
-        if (!(basePrediction & SpecInt32) && basePrediction) {
-            forNode(nodeIndex).clear();
-            break;
-        }
         if (m_graph[node.child1()].shouldSpeculateArguments()) {
             ASSERT_NOT_REACHED();
             break;
@@ -1514,7 +1504,7 @@
             forNode(nodeIndex).clear();
             break;
         }
-        forNode(node.child1()).filter(SpecArray);
+        forNode(node.child1()).filter(SpecCell);
         forNode(nodeIndex).clear();
         break; 
     }
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractValue.h b/Source/JavaScriptCore/dfg/DFGAbstractValue.h
index 402fd0f..6358822 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractValue.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractValue.h
@@ -282,6 +282,17 @@
         return speculationFromStructure(m_structure);
     }
     
+    bool hasSingleton() const
+    {
+        return isNeitherClearNorTop();
+    }
+    
+    Structure* singleton() const
+    {
+        ASSERT(isNeitherClearNorTop());
+        return m_structure;
+    }
+    
     bool operator==(const StructureAbstractValue& other) const
     {
         return m_structure == other.m_structure;
diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
index 9208cde..6850981 100644
--- a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
@@ -317,6 +317,15 @@
                     // PhantomArguments and OSR exit will still do the right things.
                     break;
                     
+                case CheckStructure:
+                case StructureTransitionWatchpoint:
+                    // We don't care about these because if we get uses of the relevant
+                    // variable then we can safely get rid of these, too. This of course
+                    // relies on there not being any information transferred by the CFA
+                    // from a CheckStructure on one variable to the information about the
+                    // structures of another variable.
+                    break;
+                    
                 default:
                     observeBadArgumentsUses(node);
                     break;
@@ -471,6 +480,17 @@
                     break;
                 }
                     
+                case CheckStructure:
+                case StructureTransitionWatchpoint: {
+                    // We can just get rid of this node, if it references a phantom argument.
+                    if (!isOKToOptimize(m_graph[node.child1()]))
+                        break;
+                    m_graph.deref(node.child1());
+                    node.setOpAndDefaultFlags(Phantom);
+                    node.children.setChild1(Edge());
+                    break;
+                }
+                    
                 case GetByVal: {
                     if (!node.prediction()
                         || !m_graph[node.child1()].prediction()
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index b7f48aa..460019b 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -2149,6 +2149,10 @@
             
             NodeIndex base = get(currentInstruction[2].u.operand);
             NodeIndex property = get(currentInstruction[3].u.operand);
+            ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
+            profile->computeUpdatedPrediction();
+            if (profile->hasDefiniteStructure())
+                addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(profile->expectedStructure())), base);
             NodeIndex propertyStorage = addToGraph(GetIndexedPropertyStorage, base, property);
             NodeIndex getByVal = addToGraph(GetByVal, OpInfo(0), OpInfo(prediction), base, property, propertyStorage);
             set(currentInstruction[1].u.operand, getByVal);
@@ -2160,6 +2164,15 @@
             NodeIndex base = get(currentInstruction[1].u.operand);
             NodeIndex property = get(currentInstruction[2].u.operand);
             NodeIndex value = get(currentInstruction[3].u.operand);
+            
+            ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
+            profile->computeUpdatedPrediction();
+            if (profile->hasDefiniteStructure())
+                addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(profile->expectedStructure())), base);
+
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+            dataLog("Slow case profile for bc#%u: %u\n", m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter);
+#endif
 
             bool makeSafe =
                 m_inlineStackTop->m_profiledBlock->couldTakeSlowCase(m_currentIndex)
diff --git a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
index dc1632d..f054707 100644
--- a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
@@ -613,7 +613,9 @@
                 
                 ASSERT(node.shouldGenerate());
                 Node& possibleLocalOp = m_graph[node.child1()];
-                if (possibleLocalOp.hasLocal() && !possibleLocalOp.variableAccessData()->isCaptured()) {
+                if (possibleLocalOp.op() != GetLocal
+                    && possibleLocalOp.hasLocal()
+                    && !possibleLocalOp.variableAccessData()->isCaptured()) {
                     NodeIndex setLocalIndex =
                         firstBlock->variablesAtTail.operand(possibleLocalOp.local());
                     Node& setLocal = m_graph[setLocalIndex];
diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
index a8eb9ee..2aa1a55 100644
--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
@@ -103,9 +103,7 @@
             }
                 
             m_state.execute(indexInBlock);
-            if (!node.shouldGenerate()
-                || m_state.didClobber()
-                || node.hasConstant())
+            if (!node.shouldGenerate() || m_state.didClobber() || node.hasConstant())
                 continue;
             JSValue value = m_state.forNode(nodeIndex).value();
             if (!value)
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 4e3cd57..f7b10fc 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -96,9 +96,29 @@
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
             dataLog("  @%u -> %s", m_compileIndex, isArray ? "GetArrayLength" : "GetStringLength");
 #endif
-            if (isArray)
+            if (isArray) {
                 node.setOp(GetArrayLength);
-            else if (isArguments)
+                ASSERT(node.flags() & NodeMustGenerate);
+                node.clearFlags(NodeMustGenerate);
+                m_graph.deref(m_compileIndex);
+                
+                ArrayProfile* arrayProfile = 
+                    m_graph.baselineCodeBlockFor(node.codeOrigin)->getArrayProfile(
+                        node.codeOrigin.bytecodeIndex);
+                if (!arrayProfile)
+                    break;
+                arrayProfile->computeUpdatedPrediction();
+                if (!arrayProfile->hasDefiniteStructure())
+                    break;
+                m_graph.ref(node.child1());
+                Node checkStructure(CheckStructure, node.codeOrigin, OpInfo(m_graph.addStructureSet(arrayProfile->expectedStructure())), node.child1().index());
+                checkStructure.ref();
+                NodeIndex checkStructureIndex = m_graph.size();
+                m_graph.append(checkStructure);
+                m_insertionSet.append(m_indexInBlock, checkStructureIndex);
+                break;
+            }
+            if (isArguments)
                 node.setOp(GetArgumentsLength);
             else if (isString)
                 node.setOp(GetStringLength);
@@ -129,10 +149,9 @@
             break;
         }
         case GetIndexedPropertyStorage: {
-            SpeculatedType basePrediction = m_graph[node.child2()].prediction();
-            if ((!(basePrediction & SpecInt32) && basePrediction)
-                || m_graph[node.child1()].shouldSpeculateArguments()
-                || !isActionableArraySpeculation(m_graph[node.child1()].prediction())) {
+            if (!m_graph[node.child1()].prediction()
+                || !m_graph[node.child2()].shouldSpeculateInteger()
+                || m_graph[node.child1()].shouldSpeculateArguments()) {
                 node.setOpAndDefaultFlags(Nop);
                 m_graph.clearAndDerefChild1(node);
                 m_graph.clearAndDerefChild2(node);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index f17e2d7..8383f80 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -155,6 +155,10 @@
     ASSERT(setLocal->codeOrigin == at(m_compileIndex).codeOrigin);
 
     Node* nextNode = &at(m_jit.graph().m_blocks[m_block]->at(setLocalIndexInBlock + 1));
+    if (nextNode->op() == Jump && nextNode->codeOrigin == at(m_compileIndex).codeOrigin) {
+        // We're at an inlined return. Use a backward speculation instead.
+        return;
+    }
     ASSERT(nextNode->codeOrigin != at(m_compileIndex).codeOrigin);
         
     OSRExit& exit = m_jit.codeBlock()->lastOSRExit();
@@ -246,6 +250,24 @@
     m_fprs = RegisterBank<FPRInfo>();
 }
 
+void SpeculativeJIT::speculateArray(Edge edge, GPRReg baseReg)
+{
+    AbstractValue& arrayValue = m_state.forNode(edge);
+    if (arrayValue.m_structure.hasSingleton()
+        && arrayValue.m_structure.singleton()->classInfo() == &JSArray::s_info)
+        return;
+    
+    GPRTemporary temp(this);
+    m_jit.loadPtr(
+        MacroAssembler::Address(baseReg, JSCell::structureOffset()), temp.gpr());
+    speculationCheck(
+        Uncountable, JSValueRegs(), NoNode,
+        m_jit.branchPtr(
+            MacroAssembler::NotEqual,
+            MacroAssembler::Address(temp.gpr(), Structure::classInfoOffset()),
+            MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
+}
+
 GPRReg SpeculativeJIT::fillStorage(NodeIndex nodeIndex)
 {
     Node& node = m_jit.graph()[nodeIndex];
@@ -1220,7 +1242,7 @@
                             valueSource = ValueSource(DoubleInRegisterFile);
                         else if (isInt32Speculation(argumentPosition.prediction()))
                             valueSource = ValueSource(Int32InRegisterFile);
-                        else if (isArraySpeculation(argumentPosition.prediction()) || isCellSpeculation(argumentPosition.prediction()))
+                        else if (isCellSpeculation(argumentPosition.prediction()))
                             valueSource = ValueSource(CellInRegisterFile);
                         else if (isBooleanSpeculation(argumentPosition.prediction()))
                             valueSource = ValueSource(BooleanInRegisterFile);
@@ -1343,12 +1365,7 @@
 #if USE(JSVALUE64)
         if (isInt32Speculation(predictedType))
             speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::Below, JITCompiler::addressFor(virtualRegister), GPRInfo::tagTypeNumberRegister));
-        else if (isArraySpeculation(predictedType)) {
-            GPRTemporary temp(this);
-            m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
-            speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
-            speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
-        } else if (isBooleanSpeculation(predictedType)) {
+        else if (isBooleanSpeculation(predictedType)) {
             GPRTemporary temp(this);
             m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
             m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), temp.gpr());
@@ -1403,13 +1420,7 @@
 #else
         if (isInt32Speculation(predictedType))
             speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag)));
-        else if (isArraySpeculation(predictedType)) {
-            GPRTemporary temp(this);
-            m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
-            speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
-            m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
-            speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
-        } else if (isBooleanSpeculation(predictedType))
+        else if (isBooleanSpeculation(predictedType))
             speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag)));
         else if (isInt8ArraySpeculation(predictedType)) {
             GPRTemporary temp(this);
@@ -1591,7 +1602,6 @@
     GPRReg storageReg = storage.gpr();
 
     if (!isStringSpeculation(m_state.forNode(node.child1()).m_type)) {
-        ASSERT(!(at(node.child1()).prediction() & SpecString));
         terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
         noResult(m_compileIndex);
         return;
@@ -3037,22 +3047,12 @@
 
 void SpeculativeJIT::compileGetIndexedPropertyStorage(Node& node)
 {
-    if (!node.prediction() || !at(node.child1()).prediction() || !at(node.child2()).prediction()) {
-        terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode);
-        return;
-    }
+    ASSERT(at(node.child1()).prediction());
+    ASSERT(at(node.child2()).shouldSpeculateInteger());
         
     SpeculateCellOperand base(this, node.child1());
     GPRReg baseReg = base.gpr();
     
-    SpeculatedType basePrediction = at(node.child2()).prediction();
-    if (!(basePrediction & SpecInt32) && basePrediction) {
-        ASSERT_NOT_REACHED();
-        terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
-        noResult(m_compileIndex);
-        return;
-    }
-    
     GPRTemporary storage(this);
     GPRReg storageReg = storage.gpr();
     if (at(node.child1()).shouldSpeculateArguments()) {
@@ -3113,8 +3113,7 @@
             speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo)));
         m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg);
     } else {
-        if (!isArraySpeculation(m_state.forNode(node.child1()).m_type))
-            speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
+        speculateArray(node.child1(), baseReg);
         m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
     }
     storageResult(storageReg, m_compileIndex);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 96f2fec..0e7452e 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -2191,6 +2191,8 @@
     void terminateSpeculativeExecution(ExitKind, JSValueRegs, Edge);
     void terminateSpeculativeExecutionWithConditionalDirection(ExitKind, JSValueRegs, NodeIndex, bool isForward);
     
+    void speculateArray(Edge baseEdge, GPRReg baseReg);
+    
     template<bool strict>
     GPRReg fillSpeculateIntInternal(NodeIndex, DataFormat& returnFormat);
     
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index bf3503d..92bb8b1 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -1918,7 +1918,7 @@
                 break;
             }
 
-            if (isArraySpeculation(value.m_type) || isCellSpeculation(value.m_type)) {
+            if (isCellSpeculation(value.m_type)) {
                 GPRTemporary result(this);
                 m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr());
 
@@ -2036,16 +2036,6 @@
                 recordSetLocal(node.local(), ValueSource(Int32InRegisterFile));
                 break;
             }
-            if (isArraySpeculation(predictedType)) {
-                SpeculateCellOperand cell(this, node.child1());
-                GPRReg cellGPR = cell.gpr();
-                if (!isArraySpeculation(m_state.forNode(node.child1()).m_type))
-                    speculationCheck(BadType, JSValueSource::unboxedCell(cellGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
-                m_jit.storePtr(cellGPR, JITCompiler::payloadFor(node.local()));
-                noResult(m_compileIndex);
-                recordSetLocal(node.local(), ValueSource(CellInRegisterFile));
-                break;
-            }
             if (isCellSpeculation(predictedType)) {
                 SpeculateCellOperand cell(this, node.child1());
                 GPRReg cellGPR = cell.gpr();
@@ -2356,7 +2346,7 @@
             break;
         }
         
-        if (!at(node.child2()).shouldSpeculateInteger() || !isActionableArraySpeculation(at(node.child1()).prediction())) {
+        if (!at(node.child2()).shouldSpeculateInteger() || (!node.child3() && !at(node.child1()).shouldSpeculateArguments())) {
             SpeculateCellOperand base(this, node.child1()); // Save a register, speculate cell. We'll probably be right.
             JSValueOperand property(this, node.child2());
             GPRReg baseGPR = base.gpr();
@@ -2449,8 +2439,6 @@
             break;            
         }
         
-        ASSERT(at(node.child1()).shouldSpeculateArray());
-
         SpeculateStrictInt32Operand property(this, node.child2());
         StorageOperand storage(this, node.child3());
         GPRReg propertyReg = property.gpr();
@@ -2464,17 +2452,13 @@
         {
             SpeculateCellOperand base(this, node.child1());
             GPRReg baseReg = base.gpr();
-            if (!isArraySpeculation(m_state.forNode(node.child1()).m_type))
-                speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
+            // We've already speculated that it's some kind of array, at this point.
             speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())));
         }
 
         GPRTemporary resultTag(this);
         GPRTemporary resultPayload(this);
 
-        // FIXME: In cases where there are subsequent by_val accesses to the same base it might help to cache
-        // the storage pointer - especially if there happens to be another register free right now. If we do so,
-        // then we'll need to allocate a new temporary for result.
         m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag.gpr());
         speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag)));
         m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr());
@@ -2495,7 +2479,6 @@
         }
         
         if (!at(child2).shouldSpeculateInteger()
-            || !isActionableMutableArraySpeculation(at(child1).prediction())
             || at(child1).shouldSpeculateArguments()) {
             SpeculateCellOperand base(this, child1); // Save a register, speculate cell. We'll probably be right.
             JSValueOperand property(this, child2);
@@ -2578,27 +2561,23 @@
             break;            
         }
         
-        ASSERT(at(child1).shouldSpeculateArray());
-
         JSValueOperand value(this, child3);
-        GPRTemporary scratch(this);
-
         // Map base, property & value into registers, allocate a scratch register.
         GPRReg baseReg = base.gpr();
         GPRReg propertyReg = property.gpr();
         GPRReg valueTagReg = value.tagGPR();
         GPRReg valuePayloadReg = value.payloadGPR();
-        GPRReg scratchReg = scratch.gpr();
         
         if (!m_compileOkay)
             return;
-        
-        writeBarrier(baseReg, valueTagReg, child3, WriteBarrierForPropertyAccess, scratchReg);
 
-        // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
-        // If we have predicted the base to be type array, we can skip the check.
-        if (!isArraySpeculation(m_state.forNode(child1).m_type))
-            speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), child1, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
+        {
+            GPRTemporary scratch(this);
+            GPRReg scratchReg = scratch.gpr();
+            writeBarrier(baseReg, valueTagReg, child3, WriteBarrierForPropertyAccess, scratchReg);
+        }
+
+        speculateArray(child1, baseReg);
 
         MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()));
         if (node.op() == PutByVal)
@@ -2609,7 +2588,8 @@
         value.use();
         
         // Get the array storage.
-        GPRReg storageReg = scratchReg;
+        GPRTemporary storage(this);
+        GPRReg storageReg = storage.gpr();
         m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
 
         // Check if we're writing to a hole; if so increment m_numValuesInVector.
@@ -2795,20 +2775,23 @@
     case ArrayPush: {
         SpeculateCellOperand base(this, node.child1());
         JSValueOperand value(this, node.child2());
-        GPRTemporary storage(this);
         GPRTemporary storageLength(this);
         
         GPRReg baseGPR = base.gpr();
         GPRReg valueTagGPR = value.tagGPR();
         GPRReg valuePayloadGPR = value.payloadGPR();
-        GPRReg storageGPR = storage.gpr();
         GPRReg storageLengthGPR = storageLength.gpr();
         
-        writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, storageGPR, storageLengthGPR);
+        {
+            GPRTemporary scratch(this);
+            writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR);
+        }
 
-        if (!isArraySpeculation(m_state.forNode(node.child1()).m_type))
-            speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
+        speculateArray(node.child1(), baseGPR);
         
+        GPRTemporary storage(this);
+        GPRReg storageGPR = storage.gpr();
+
         m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR);
         m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
         
@@ -2844,8 +2827,7 @@
         GPRReg storageGPR = storage.gpr();
         GPRReg storageLengthGPR = storageLength.gpr();
         
-        if (!isArraySpeculation(m_state.forNode(node.child1()).m_type))
-            speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
+        speculateArray(node.child1(), baseGPR);
         
         m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR);
         m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
@@ -3395,8 +3377,7 @@
         SpeculateCellOperand base(this, node.child1());
         GPRReg baseGPR = base.gpr();
         
-        if (!isArraySpeculation(m_state.forNode(node.child1()).m_type))
-            speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
+        speculateArray(node.child1(), baseGPR);
         
         GPRTemporary result(this);
         GPRReg resultGPR = result.gpr();
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 5541113..4f3dabb 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -2072,16 +2072,6 @@
                 recordSetLocal(node.local(), ValueSource(Int32InRegisterFile));
                 break;
             }
-            if (isArraySpeculation(predictedType)) {
-                SpeculateCellOperand cell(this, node.child1());
-                GPRReg cellGPR = cell.gpr();
-                if (!isArraySpeculation(m_state.forNode(node.child1()).m_type))
-                    speculationCheck(BadType, JSValueRegs(cellGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
-                m_jit.storePtr(cellGPR, JITCompiler::addressFor(node.local()));
-                noResult(m_compileIndex);
-                recordSetLocal(node.local(), ValueSource(CellInRegisterFile));
-                break;
-            }
             if (isCellSpeculation(predictedType)) {
                 SpeculateCellOperand cell(this, node.child1());
                 GPRReg cellGPR = cell.gpr();
@@ -2389,7 +2379,7 @@
             break;
         }
         
-        if (!at(node.child2()).shouldSpeculateInteger() || !isActionableArraySpeculation(at(node.child1()).prediction())) {
+        if (!at(node.child2()).shouldSpeculateInteger() || (!node.child3() && !at(node.child1()).shouldSpeculateArguments())) {
             JSValueOperand base(this, node.child1());
             JSValueOperand property(this, node.child2());
             GPRReg baseGPR = base.gpr();
@@ -2480,8 +2470,6 @@
             break;            
         }
         
-        ASSERT(at(node.child1()).shouldSpeculateArray());
-
         SpeculateCellOperand base(this, node.child1());
         SpeculateStrictInt32Operand property(this, node.child2());
         StorageOperand storage(this, node.child3());
@@ -2493,13 +2481,11 @@
         if (!m_compileOkay)
             return;
 
-        if (!isArraySpeculation(m_state.forNode(node.child1()).m_type))
-            speculationCheck(BadType, JSValueRegs(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
+        // We will have already speculated that the base is some kind of array,
+        // at this point.
+        
         speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())));
 
-        // FIXME: In cases where there are subsequent by_val accesses to the same base it might help to cache
-        // the storage pointer - especially if there happens to be another register free right now. If we do so,
-        // then we'll need to allocate a new temporary for result.
         GPRTemporary result(this);
         m_jit.loadPtr(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), result.gpr());
         speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branchTestPtr(MacroAssembler::Zero, result.gpr()));
@@ -2519,7 +2505,7 @@
             break;
         }
         
-        if (!at(child2).shouldSpeculateInteger() || !isActionableMutableArraySpeculation(at(child1).prediction())) {
+        if (!at(child2).shouldSpeculateInteger()) {
             JSValueOperand arg1(this, child1);
             JSValueOperand arg2(this, child2);
             JSValueOperand arg3(this, child3);
@@ -2537,9 +2523,8 @@
         SpeculateCellOperand base(this, child1);
         SpeculateStrictInt32Operand property(this, child2);
         if (at(child1).shouldSpeculateArguments()) {
+            dataLog(" in here ");
             JSValueOperand value(this, child3);
-            SpeculateCellOperand base(this, child1);
-            SpeculateStrictInt32Operand property(this, child2);
             GPRTemporary scratch(this);
             GPRTemporary scratch2(this);
             
@@ -2656,8 +2641,6 @@
             break;            
         }
             
-        ASSERT(at(child1).shouldSpeculateArray());
-
         JSValueOperand value(this, child3);
         GPRTemporary scratch(this);
 
@@ -2672,11 +2655,8 @@
         
         writeBarrier(baseReg, value.gpr(), child3, WriteBarrierForPropertyAccess, scratchReg);
 
-        // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
-        // If we have predicted the base to be type array, we can skip the check.
-        if (!isArraySpeculation(m_state.forNode(child1).m_type))
-            speculationCheck(BadType, JSValueRegs(baseReg), child1, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
-        
+        speculateArray(child1, baseReg);
+
         MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()));
         if (node.op() == PutByVal)
             speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds);
@@ -2879,9 +2859,8 @@
         
         writeBarrier(baseGPR, valueGPR, node.child2(), WriteBarrierForPropertyAccess, storageGPR, storageLengthGPR);
 
-        if (!isArraySpeculation(m_state.forNode(node.child1()).m_type))
-            speculationCheck(BadType, JSValueRegs(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
-        
+        speculateArray(node.child1(), baseGPR);
+
         m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR);
         m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
         
@@ -2917,9 +2896,8 @@
         GPRReg storageGPR = storage.gpr();
         GPRReg storageLengthGPR = storageLength.gpr();
         
-        if (!isArraySpeculation(m_state.forNode(node.child1()).m_type))
-            speculationCheck(BadType, JSValueRegs(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
-        
+        speculateArray(node.child1(), baseGPR);
+
         m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR);
         m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
         
@@ -3415,9 +3393,8 @@
         GPRReg baseGPR = base.gpr();
         GPRReg resultGPR = result.gpr();
         
-        if (!isArraySpeculation(m_state.forNode(node.child1()).m_type))
-            speculationCheck(BadType, JSValueRegs(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
-        
+        speculateArray(node.child1(), baseGPR);
+
         m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), resultGPR);
         m_jit.load32(MacroAssembler::Address(resultGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), resultGPR);
         
diff --git a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
index e86c57d..c7ceead 100644
--- a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
@@ -94,6 +94,11 @@
                 case AllocatePropertyStorage:
                 case ReallocatePropertyStorage:
                 case GetPropertyStorage:
+                case GetByVal:
+                case PutByVal:
+                case PutByValAlias:
+                case GetArrayLength:
+                case Phantom:
                     // Don't count these uses.
                     break;
                     
diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
index dfb2dc8..c611ada 100644
--- a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
+++ b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
@@ -110,7 +110,9 @@
     zeroExtend32ToPtr(regT1, regT1);
 
     emitJumpSlowCaseIfNotJSCell(regT0, base);
-    addSlowCase(branchPtr(NotEqual, Address(regT0, JSCell::classInfoOffset()), TrustedImmPtr(&JSArray::s_info)));
+    loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
+    storePtr(regT2, currentInstruction[4].u.arrayProfile->addressOfLastSeenStructure());
+    addSlowCase(branchPtr(NotEqual, Address(regT2, Structure::classInfoOffset()), TrustedImmPtr(&JSArray::s_info)));
 
     loadPtr(Address(regT0, JSArray::storageOffset()), regT2);
     addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, JSArray::vectorLengthOffset())));
@@ -231,7 +233,9 @@
     // See comment in op_get_by_val.
     zeroExtend32ToPtr(regT1, regT1);
     emitJumpSlowCaseIfNotJSCell(regT0, base);
-    addSlowCase(branchPtr(NotEqual, Address(regT0, JSCell::classInfoOffset()), TrustedImmPtr(&JSArray::s_info)));
+    loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
+    storePtr(regT2, currentInstruction[4].u.arrayProfile->addressOfLastSeenStructure());
+    addSlowCase(branchPtr(NotEqual, Address(regT2, Structure::classInfoOffset()), TrustedImmPtr(&JSArray::s_info)));
     addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, JSArray::vectorLengthOffset())));
 
     loadPtr(Address(regT0, JSArray::storageOffset()), regT2);
@@ -645,7 +649,9 @@
     StructureStubInfo* stubInfo = &m_codeBlock->getStubInfo(returnAddress);
 
     // Check eax is an array
-    Jump failureCases1 = branchPtr(NotEqual, Address(regT0, JSCell::classInfoOffset()), TrustedImmPtr(&JSArray::s_info));
+    loadPtr(Address(regT0, JSCell::structureOffset()), regT3);
+    storePtr(regT3, m_codeBlock->getOrAddArrayProfile(stubInfo->bytecodeIndex)->addressOfLastSeenStructure());
+    Jump failureCases1 = branchPtr(NotEqual, Address(regT3, Structure::classInfoOffset()), TrustedImmPtr(&JSArray::s_info));
 
     // Checks out okay! - get the length from the storage
     loadPtr(Address(regT0, JSArray::storageOffset()), regT3);
diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
index b506f4e..212e93b 100644
--- a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
+++ b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
@@ -209,7 +209,9 @@
     
     addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
     emitJumpSlowCaseIfNotJSCell(base, regT1);
-    addSlowCase(branchPtr(NotEqual, Address(regT0, JSCell::classInfoOffset()), TrustedImmPtr(&JSArray::s_info)));
+    loadPtr(Address(regT0, JSCell::structureOffset()), regT1);
+    storePtr(regT1, currentInstruction[4].u.arrayProfile->addressOfLastSeenStructure());
+    addSlowCase(branchPtr(NotEqual, Address(regT1, JSCell::classInfoOffset()), TrustedImmPtr(&JSArray::s_info)));
     
     loadPtr(Address(regT0, JSArray::storageOffset()), regT3);
     addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, JSArray::vectorLengthOffset())));
@@ -264,7 +266,9 @@
     
     addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
     emitJumpSlowCaseIfNotJSCell(base, regT1);
-    addSlowCase(branchPtr(NotEqual, Address(regT0, JSCell::classInfoOffset()), TrustedImmPtr(&JSArray::s_info)));
+    loadPtr(Address(regT0, JSCell::structureOffset()), regT1);
+    storePtr(regT1, currentInstruction[4].u.arrayProfile->addressOfLastSeenStructure());
+    addSlowCase(branchPtr(NotEqual, Address(regT1, Structure::classInfoOffset()), TrustedImmPtr(&JSArray::s_info)));
     addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, JSArray::vectorLengthOffset())));
 
     emitWriteBarrier(regT0, regT1, regT1, regT3, UnconditionalWriteBarrier, WriteBarrierForPropertyAccess);
@@ -608,7 +612,9 @@
     // regT0 holds a JSCell*
     
     // Check for array
-    Jump failureCases1 = branchPtr(NotEqual, Address(regT0, JSCell::classInfoOffset()), TrustedImmPtr(&JSArray::s_info));
+    loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
+    storePtr(regT2, m_codeBlock->getOrAddArrayProfile(stubInfo->bytecodeIndex)->addressOfLastSeenStructure());
+    Jump failureCases1 = branchPtr(NotEqual, Address(regT2, Structure::classInfoOffset()), TrustedImmPtr(&JSArray::s_info));
     
     // Checks out okay! - get the length from the storage
     loadPtr(Address(regT0, JSArray::storageOffset()), regT2);
diff --git a/Source/JavaScriptCore/llint/LLIntOffsetsExtractor.cpp b/Source/JavaScriptCore/llint/LLIntOffsetsExtractor.cpp
index f863cb2..cbb4258 100644
--- a/Source/JavaScriptCore/llint/LLIntOffsetsExtractor.cpp
+++ b/Source/JavaScriptCore/llint/LLIntOffsetsExtractor.cpp
@@ -25,6 +25,7 @@
 
 #include "config.h"
 
+#include "ArrayProfile.h"
 #include "CodeBlock.h"
 #include "Executable.h"
 #include "Heap.h"
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
index b8115dd..3246422 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
@@ -1255,14 +1255,17 @@
 
 _llint_op_get_by_val:
     traceExecution()
-    loadp CodeBlock[cfr], t1
     loadi 8[PC], t2
     loadi 12[PC], t3
-    loadp CodeBlock::m_globalData[t1], t1
     loadConstantOrVariablePayload(t2, CellTag, t0, .opGetByValSlow)
-    loadp JSGlobalData::jsArrayClassInfo[t1], t2
     loadConstantOrVariablePayload(t3, Int32Tag, t1, .opGetByValSlow)
-    bpneq [t0], t2, .opGetByValSlow
+    loadp JSCell::m_structure[t0], t3
+    loadp 16[PC], t2
+    storep t3, ArrayProfile::m_lastSeenStructure[t2]
+    loadp CodeBlock[cfr], t2
+    loadp CodeBlock::m_globalData[t2], t2
+    loadp JSGlobalData::jsArrayClassInfo[t2], t2
+    bpneq Structure::m_classInfo[t3], t2, .opGetByValSlow
     loadp JSArray::m_storage[t0], t3
     biaeq t1, JSArray::m_vectorLength[t0], .opGetByValSlow
     loadi 4[PC], t0
@@ -1271,16 +1274,18 @@
     bieq t2, EmptyValueTag, .opGetByValSlow
     storei t2, TagOffset[cfr, t0, 8]
     storei t1, PayloadOffset[cfr, t0, 8]
-    loadi 16[PC], t0
+    loadi 20[PC], t0
     valueProfile(t2, t1, t0)
-    dispatch(5)
+    dispatch(6)
 
 .opGetByValSlow:
     callSlowPath(_llint_slow_path_get_by_val)
-    dispatch(5)
+    dispatch(6)
 
 
 _llint_op_get_argument_by_val:
+    # FIXME: At some point we should array profile this. Right now it isn't necessary
+    # since the DFG will never turn a get_argument_by_val into a GetByVal.
     traceExecution()
     loadi 8[PC], t0
     loadi 12[PC], t1
@@ -1293,15 +1298,15 @@
     loadi 4[PC], t3
     loadi ThisArgumentOffset + TagOffset[cfr, t2, 8], t0
     loadi ThisArgumentOffset + PayloadOffset[cfr, t2, 8], t1
-    loadi 16[PC], t2
+    loadi 20[PC], t2
     storei t0, TagOffset[cfr, t3, 8]
     storei t1, PayloadOffset[cfr, t3, 8]
     valueProfile(t0, t1, t2)
-    dispatch(5)
+    dispatch(6)
 
 .opGetArgumentByValSlow:
     callSlowPath(_llint_slow_path_get_argument_by_val)
-    dispatch(5)
+    dispatch(6)
 
 
 _llint_op_get_by_pname:
@@ -1338,10 +1343,13 @@
     loadConstantOrVariablePayload(t0, CellTag, t1, .opPutByValSlow)
     loadi 8[PC], t0
     loadConstantOrVariablePayload(t0, Int32Tag, t2, .opPutByValSlow)
+    loadp JSCell::m_structure[t1], t3
+    loadp 16[PC], t0
+    storep t3, ArrayProfile::m_lastSeenStructure[t0]
     loadp CodeBlock[cfr], t0
     loadp CodeBlock::m_globalData[t0], t0
     loadp JSGlobalData::jsArrayClassInfo[t0], t0
-    bpneq [t1], t0, .opPutByValSlow
+    bpneq Structure::m_classInfo[t3], t0, .opPutByValSlow
     biaeq t2, JSArray::m_vectorLength[t1], .opPutByValSlow
     loadp JSArray::m_storage[t1], t0
     bieq ArrayStorage::m_vector + TagOffset[t0, t2, 8], EmptyValueTag, .opPutByValEmpty
@@ -1351,7 +1359,7 @@
     writeBarrier(t1, t3)
     storei t1, ArrayStorage::m_vector + TagOffset[t0, t2, 8]
     storei t3, ArrayStorage::m_vector + PayloadOffset[t0, t2, 8]
-    dispatch(4)
+    dispatch(5)
 
 .opPutByValEmpty:
     addi 1, ArrayStorage::m_numValuesInVector[t0]
@@ -1362,7 +1370,7 @@
 
 .opPutByValSlow:
     callSlowPath(_llint_slow_path_put_by_val)
-    dispatch(4)
+    dispatch(5)
 
 
 _llint_op_loop:
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
index 6e752a6..31f997c 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
@@ -1099,31 +1099,36 @@
 
 _llint_op_get_by_val:
     traceExecution()
-    loadp CodeBlock[cfr], t1
     loadis 16[PB, PC, 8], t2
     loadis 24[PB, PC, 8], t3
-    loadp CodeBlock::m_globalData[t1], t1
     loadConstantOrVariableCell(t2, t0, .opGetByValSlow)
-    loadp JSGlobalData::jsArrayClassInfo[t1], t2
     loadConstantOrVariableInt32(t3, t1, .opGetByValSlow)
     sxi2p t1, t1
-    bpneq [t0], t2, .opGetByValSlow
+    loadp JSCell::m_structure[t0], t3
+    loadp 32[PB, PC, 8], t2
+    storep t3, ArrayProfile::m_lastSeenStructure[t2]
+    loadp CodeBlock[cfr], t2
+    loadp CodeBlock::m_globalData[t2], t2
+    loadp JSGlobalData::jsArrayClassInfo[t2], t2
+    bpneq Structure::m_classInfo[t3], t2, .opGetByValSlow
     loadp JSArray::m_storage[t0], t3
     biaeq t1, JSArray::m_vectorLength[t0], .opGetByValSlow
     loadis 8[PB, PC, 8], t0
     loadp ArrayStorage::m_vector[t3, t1, 8], t2
     btpz t2, .opGetByValSlow
     storep t2, [cfr, t0, 8]
-    loadp 32[PB, PC, 8], t0
+    loadp 40[PB, PC, 8], t0
     valueProfile(t2, t0)
-    dispatch(5)
+    dispatch(6)
 
 .opGetByValSlow:
     callSlowPath(_llint_slow_path_get_by_val)
-    dispatch(5)
+    dispatch(6)
 
 
 _llint_op_get_argument_by_val:
+    # FIXME: At some point we should array profile this. Right now it isn't necessary
+    # since the DFG will never turn a get_argument_by_val into a GetByVal.
     traceExecution()
     loadis 16[PB, PC, 8], t0
     loadis 24[PB, PC, 8], t1
@@ -1139,11 +1144,11 @@
     loadp ThisArgumentOffset[cfr, t2, 8], t0
     storep t0, [cfr, t3, 8]
     valueProfile(t0, t1)
-    dispatch(5)
+    dispatch(6)
 
 .opGetArgumentByValSlow:
     callSlowPath(_llint_slow_path_get_argument_by_val)
-    dispatch(5)
+    dispatch(6)
 
 
 _llint_op_get_by_pname:
@@ -1182,10 +1187,13 @@
     loadis 16[PB, PC, 8], t0
     loadConstantOrVariableInt32(t0, t2, .opPutByValSlow)
     sxi2p t2, t2
+    loadp JSCell::m_structure[t1], t3
+    loadp 32[PB, PC, 8], t0
+    storep t3, ArrayProfile::m_lastSeenStructure[t0]
     loadp CodeBlock[cfr], t0
     loadp CodeBlock::m_globalData[t0], t0
     loadp JSGlobalData::jsArrayClassInfo[t0], t0
-    bpneq [t1], t0, .opPutByValSlow
+    bpneq Structure::m_classInfo[t3], t0, .opPutByValSlow
     biaeq t2, JSArray::m_vectorLength[t1], .opPutByValSlow
     loadp JSArray::m_storage[t1], t0
     btpz ArrayStorage::m_vector[t0, t2, 8], .opPutByValEmpty
@@ -1194,7 +1202,7 @@
     loadConstantOrVariable(t3, t1)
     writeBarrier(t1)
     storep t1, ArrayStorage::m_vector[t0, t2, 8]
-    dispatch(4)
+    dispatch(5)
 
 .opPutByValEmpty:
     addi 1, ArrayStorage::m_numValuesInVector[t0]
@@ -1205,7 +1213,7 @@
 
 .opPutByValSlow:
     callSlowPath(_llint_slow_path_put_by_val)
-    dispatch(4)
+    dispatch(5)
 
 
 _llint_op_loop:
diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h
index ee0b573..0b9c922 100644
--- a/Source/JavaScriptCore/runtime/Structure.h
+++ b/Source/JavaScriptCore/runtime/Structure.h
@@ -322,6 +322,11 @@
         {
             return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::typeOffset();
         }
+        
+        static ptrdiff_t classInfoOffset()
+        {
+            return OBJECT_OFFSETOF(Structure, m_classInfo);
+        }
 
         static Structure* createStructure(JSGlobalData&);