Typed arrays should not be 20x slower in the baseline JIT than in the DFG JIT
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 10 Oct 2012 02:14:42 +0000 (02:14 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 10 Oct 2012 02:14:42 +0000 (02:14 +0000)
https://bugs.webkit.org/show_bug.cgi?id=98605

Reviewed by Oliver Hunt and Gavin Barraclough.

This adds typed array get_by_val/put_by_val patching to the baseline JIT. It's
a big (~40%) win on benchmarks that have trouble staying in the DFG JIT. Even
if we fix those benchmarks, this functionality gives us the insurance that we
typically desire with all speculative optimizations: even if we bail to
baseline, we're still reasonably performant.

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* assembler/MacroAssembler.cpp: Added.
(JSC):
* assembler/MacroAssembler.h:
(MacroAssembler):
(JSC::MacroAssembler::patchableBranchPtr):
* assembler/MacroAssemblerARMv7.h:
(MacroAssemblerARMv7):
(JSC::MacroAssemblerARMv7::moveDoubleToInts):
(JSC::MacroAssemblerARMv7::moveIntsToDouble):
(JSC::MacroAssemblerARMv7::patchableBranchPtr):
* assembler/MacroAssemblerX86.h:
(MacroAssemblerX86):
(JSC::MacroAssemblerX86::moveDoubleToInts):
(JSC::MacroAssemblerX86::moveIntsToDouble):
* bytecode/ByValInfo.h:
(JSC::hasOptimizableIndexingForClassInfo):
(JSC):
(JSC::hasOptimizableIndexing):
(JSC::jitArrayModeForClassInfo):
(JSC::jitArrayModeForStructure):
(JSC::ByValInfo::ByValInfo):
(ByValInfo):
* dfg/DFGAssemblyHelpers.cpp:
(DFG):
* dfg/DFGAssemblyHelpers.h:
(AssemblyHelpers):
(JSC::DFG::AssemblyHelpers::boxDouble):
(JSC::DFG::AssemblyHelpers::unboxDouble):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileGetByValOnIntTypedArray):
(JSC::DFG::SpeculativeJIT::compilePutByValForIntTypedArray):
* dfg/DFGSpeculativeJIT.h:
(SpeculativeJIT):
* jit/JIT.h:
(JIT):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::privateCompileGetByVal):
(JSC::JIT::privateCompilePutByVal):
(JSC::JIT::emitIntTypedArrayGetByVal):
(JSC):
(JSC::JIT::emitFloatTypedArrayGetByVal):
(JSC::JIT::emitIntTypedArrayPutByVal):
(JSC::JIT::emitFloatTypedArrayPutByVal):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emit_op_put_by_val):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
* runtime/JSCell.h:
* runtime/JSGlobalData.h:
(JSGlobalData):
(JSC::JSGlobalData::typedArrayDescriptor):
* runtime/TypedArrayDescriptor.h: Added.
(JSC):
(JSC::TypedArrayDescriptor::TypedArrayDescriptor):
(TypedArrayDescriptor):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@130839 268f45cc-cd09-0410-ab3c-d52691b4dbfc

23 files changed:
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/GNUmakefile.list.am
Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/Target.pri
Source/JavaScriptCore/assembler/MacroAssembler.cpp [new file with mode: 0644]
Source/JavaScriptCore/assembler/MacroAssembler.h
Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h
Source/JavaScriptCore/assembler/MacroAssemblerX86.h
Source/JavaScriptCore/bytecode/ByValInfo.h
Source/JavaScriptCore/dfg/DFGAssemblyHelpers.cpp
Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITInlineMethods.h
Source/JavaScriptCore/jit/JITPropertyAccess.cpp
Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
Source/JavaScriptCore/jit/JITStubs.cpp
Source/JavaScriptCore/runtime/JSCell.h
Source/JavaScriptCore/runtime/JSGlobalData.h
Source/JavaScriptCore/runtime/TypedArrayDescriptor.h [new file with mode: 0644]

index ec7052a..f84d01d 100644 (file)
@@ -37,6 +37,7 @@ SET(JavaScriptCore_SOURCES
     API/JSWeakObjectMapRefPrivate.cpp
     API/OpaqueJSString.cpp
     
+    assembler/MacroAssembler.cpp
     assembler/LinkBuffer.cpp
 
     bytecode/ArrayProfile.cpp
index 1d31694..0881c91 100644 (file)
@@ -1,3 +1,80 @@
+2012-10-09  Filip Pizlo  <fpizlo@apple.com>
+
+        Typed arrays should not be 20x slower in the baseline JIT than in the DFG JIT
+        https://bugs.webkit.org/show_bug.cgi?id=98605
+
+        Reviewed by Oliver Hunt and Gavin Barraclough.
+
+        This adds typed array get_by_val/put_by_val patching to the baseline JIT. It's
+        a big (~40%) win on benchmarks that have trouble staying in the DFG JIT. Even
+        if we fix those benchmarks, this functionality gives us the insurance that we
+        typically desire with all speculative optimizations: even if we bail to
+        baseline, we're still reasonably performant.
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Target.pri:
+        * assembler/MacroAssembler.cpp: Added.
+        (JSC):
+        * assembler/MacroAssembler.h:
+        (MacroAssembler):
+        (JSC::MacroAssembler::patchableBranchPtr):
+        * assembler/MacroAssemblerARMv7.h:
+        (MacroAssemblerARMv7):
+        (JSC::MacroAssemblerARMv7::moveDoubleToInts):
+        (JSC::MacroAssemblerARMv7::moveIntsToDouble):
+        (JSC::MacroAssemblerARMv7::patchableBranchPtr):
+        * assembler/MacroAssemblerX86.h:
+        (MacroAssemblerX86):
+        (JSC::MacroAssemblerX86::moveDoubleToInts):
+        (JSC::MacroAssemblerX86::moveIntsToDouble):
+        * bytecode/ByValInfo.h:
+        (JSC::hasOptimizableIndexingForClassInfo):
+        (JSC):
+        (JSC::hasOptimizableIndexing):
+        (JSC::jitArrayModeForClassInfo):
+        (JSC::jitArrayModeForStructure):
+        (JSC::ByValInfo::ByValInfo):
+        (ByValInfo):
+        * dfg/DFGAssemblyHelpers.cpp:
+        (DFG):
+        * dfg/DFGAssemblyHelpers.h:
+        (AssemblyHelpers):
+        (JSC::DFG::AssemblyHelpers::boxDouble):
+        (JSC::DFG::AssemblyHelpers::unboxDouble):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileGetByValOnIntTypedArray):
+        (JSC::DFG::SpeculativeJIT::compilePutByValForIntTypedArray):
+        * dfg/DFGSpeculativeJIT.h:
+        (SpeculativeJIT):
+        * jit/JIT.h:
+        (JIT):
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emit_op_get_by_val):
+        (JSC::JIT::emit_op_put_by_val):
+        (JSC::JIT::privateCompileGetByVal):
+        (JSC::JIT::privateCompilePutByVal):
+        (JSC::JIT::emitIntTypedArrayGetByVal):
+        (JSC):
+        (JSC::JIT::emitFloatTypedArrayGetByVal):
+        (JSC::JIT::emitIntTypedArrayPutByVal):
+        (JSC::JIT::emitFloatTypedArrayPutByVal):
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::emit_op_get_by_val):
+        (JSC::JIT::emit_op_put_by_val):
+        * jit/JITStubs.cpp:
+        (JSC::DEFINE_STUB_FUNCTION):
+        * runtime/JSCell.h:
+        * runtime/JSGlobalData.h:
+        (JSGlobalData):
+        (JSC::JSGlobalData::typedArrayDescriptor):
+        * runtime/TypedArrayDescriptor.h: Added.
+        (JSC):
+        (JSC::TypedArrayDescriptor::TypedArrayDescriptor):
+        (TypedArrayDescriptor):
+
 2012-10-09  Michael Saboff  <msaboff@apple.com>
 
         Add tests to testapi for null OpaqueJSStrings
index d99690a..752e570 100644 (file)
@@ -67,6 +67,7 @@ javascriptcore_sources += \
        Source/JavaScriptCore/assembler/CodeLocation.h \
        Source/JavaScriptCore/assembler/LinkBuffer.cpp \
        Source/JavaScriptCore/assembler/LinkBuffer.h \
+       Source/JavaScriptCore/assembler/MacroAssembler.cpp \
        Source/JavaScriptCore/assembler/MacroAssembler.h \
        Source/JavaScriptCore/assembler/MacroAssemblerARM.cpp \
        Source/JavaScriptCore/assembler/MacroAssemblerARM.h \
@@ -677,6 +678,7 @@ javascriptcore_sources += \
        Source/JavaScriptCore/runtime/TimeoutChecker.cpp \
        Source/JavaScriptCore/runtime/TimeoutChecker.h \
        Source/JavaScriptCore/runtime/Tracing.h \
+       Source/JavaScriptCore/runtime/TypedArrayDescriptor.h \
        Source/JavaScriptCore/runtime/Uint16WithFraction.h \
        Source/JavaScriptCore/runtime/WeakGCMap.h \
        Source/JavaScriptCore/runtime/WeakRandom.h \
index de76e27..86f8d11 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\runtime\TypedArrayDescriptor.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\runtime\WeakGCMap.h"
                                >
                        </File>
                                >
                        </File>
                        <File
+                               RelativePath="..\..\assembler\MacroAssembler.cpp"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\assembler\MacroAssembler.h"
                                >
                        </File>
index b996632..ce349da 100644 (file)
                0FD82E86141F3FF100179C94 /* SpeculatedType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD82E84141F3FDA00179C94 /* SpeculatedType.cpp */; };
                0FE228ED1436AB2700196C48 /* Options.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE228EB1436AB2300196C48 /* Options.h */; settings = {ATTRIBUTES = (Private, ); }; };
                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 */; };
                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 */; };
                0FD82E84141F3FDA00179C94 /* SpeculatedType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpeculatedType.cpp; sourceTree = "<group>"; };
                0FE228EA1436AB2300196C48 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Options.cpp; sourceTree = "<group>"; };
                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>"; };
                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>"; };
                                14A42E3E0F4F60EE00599099 /* TimeoutChecker.h */,
                                5D53726D0E1C546B0021E549 /* Tracing.d */,
                                5D53726E0E1C54880021E549 /* Tracing.h */,
+                               0FEB3ECB16237F4700AB67AD /* TypedArrayDescriptor.h */,
                                866739D113BFDE710023D87C /* Uint16WithFraction.h */,
                                14BFCE6810CDB1FC00364CCE /* WeakGCMap.h */,
                                1420BE7A10AA6DDB00F455D2 /* WeakRandom.h */,
                                86E116B00FE75AC800B512BC /* CodeLocation.h */,
                                0FF4275615914A20004CB9FF /* LinkBuffer.cpp */,
                                86D3B3C110159D7F002865E7 /* LinkBuffer.h */,
+                               0FEB3ECE16237F6700AB67AD /* MacroAssembler.cpp */,
                                86C36EE90EE1289D00B3DF59 /* MacroAssembler.h */,
                                86C568DD11A213EE0007F7F0 /* MacroAssemblerARM.cpp */,
                                86D3B2C210156BDE002865E7 /* MacroAssemblerARM.h */,
                                0F8023EA1613832B00A0BA45 /* ByValInfo.h in Headers */,
                                862553D216136E1A009F17D0 /* JSProxy.h in Headers */,
                                0F5541B21613C1FB00CE3E25 /* SpecialPointer.h in Headers */,
+                               0FEB3ECD16237F4D00AB67AD /* TypedArrayDescriptor.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                862553D116136DA9009F17D0 /* JSProxy.cpp in Sources */,
                                0F13E04E16164A1F00DC8DE7 /* IndexingType.cpp in Sources */,
                                0F5541B11613C1FB00CE3E25 /* SpecialPointer.cpp in Sources */,
+                               0FEB3ECF16237F6C00AB67AD /* MacroAssembler.cpp in Sources */,
                                C24D31E2161CD695002AA4DB /* HeapStatistics.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
index 64b99b6..7d75c9b 100644 (file)
@@ -45,6 +45,7 @@ SOURCES += \
     assembler/ARMAssembler.cpp \
     assembler/ARMv7Assembler.cpp \
     assembler/LinkBuffer.cpp \
+    assembler/MacroAssembler.cpp \
     assembler/MacroAssemblerARM.cpp \
     assembler/MacroAssemblerSH4.cpp \
     bytecode/ArrayProfile.cpp \
diff --git a/Source/JavaScriptCore/assembler/MacroAssembler.cpp b/Source/JavaScriptCore/assembler/MacroAssembler.cpp
new file mode 100644 (file)
index 0000000..2cff056
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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 "MacroAssembler.h"
+
+#if ENABLE(ASSEMBLER)
+
+namespace JSC {
+
+const double MacroAssembler::twoToThe32 = (double)0x100000000ull;
+
+} // namespace JSC
+
+#endif // ENABLE(ASSEMBLER)
+
index 4f7647e..bc3d3f8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 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
@@ -26,6 +26,8 @@
 #ifndef MacroAssembler_h
 #define MacroAssembler_h
 
+#include <wtf/Platform.h>
+
 #if ENABLE(ASSEMBLER)
 
 #if CPU(ARM_THUMB2)
@@ -89,6 +91,8 @@ public:
     using MacroAssemblerBase::xor32;
 #endif
 
+    static const double twoToThe32; // This is super useful for some double code.
+
     // Utilities used by the DFG JIT.
 #if ENABLE(DFG_JIT)
     using MacroAssemblerBase::invert;
@@ -230,6 +234,11 @@ public:
     }
 
 #if !CPU(ARM_THUMB2)
+    PatchableJump patchableBranchPtr(RelationalCondition cond, Address left, TrustedImmPtr right = TrustedImmPtr(0))
+    {
+        return PatchableJump(branchPtr(cond, left, right));
+    }
+    
     PatchableJump patchableBranchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
     {
         return PatchableJump(branchPtrWithPatch(cond, left, dataLabel, initialRightValue));
index 543b228..1c52f6f 100644 (file)
@@ -754,6 +754,18 @@ public:
         store16(src, setupArmAddress(address));
     }
 
+    // Possibly clobbers src, but not on this architecture.
+    void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2)
+    {
+        m_assembler.vmov(dest1, dest2, src);
+    }
+    
+    void moveIntsToDouble(RegisterID src1, RegisterID src2, FPRegisterID dest, FPRegisterID scratch)
+    {
+        UNUSED_PARAM(scratch);
+        m_assembler.vmov(dest, src1, src2);
+    }
+
 #if ENABLE(JIT_CONSTANT_BLINDING)
     static bool shouldBlindForSpecificArch(uint32_t value)
     {
@@ -1673,6 +1685,14 @@ public:
         return branch32(cond, addressTempRegister, dataTempRegister);
     }
     
+    PatchableJump patchableBranchPtr(RelationalCondition cond, Address left, TrustedImmPtr right = TrustedImmPtr(0))
+    {
+        m_makeJumpPatchable = true;
+        Jump result = branchPtr(cond, left, right);
+        m_makeJumpPatchable = false;
+        return PatchableJump(result);
+    }
+    
     PatchableJump patchableBranchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
     {
         m_makeJumpPatchable = true;
index f6e373d..8fd3146 100644 (file)
@@ -138,6 +138,22 @@ public:
         ASSERT(-128 <= imm.m_value && imm.m_value < 128);
         m_assembler.movb_i8m(imm.m_value, address);
     }
+    
+    // Possibly clobbers src.
+    void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2)
+    {
+        movePackedToInt32(src, dest1);
+        rshiftPacked(TrustedImm32(32), src);
+        movePackedToInt32(src, dest2);
+    }
+
+    void moveIntsToDouble(RegisterID src1, RegisterID src2, FPRegisterID dest, FPRegisterID scratch)
+    {
+        moveInt32ToPacked(src1, dest);
+        moveInt32ToPacked(src2, scratch);
+        lshiftPacked(TrustedImm32(32), scratch);
+        orPacked(scratch, dest);
+    }
 
     Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
     {
index 16bad13..8cba446 100644 (file)
 
 #if ENABLE(JIT)
 
+#include "ClassInfo.h"
 #include "CodeLocation.h"
 #include "IndexingType.h"
 #include "JITStubRoutine.h"
+#include "Structure.h"
 
 namespace JSC {
 
-enum JITArrayMode { JITContiguous, JITArrayStorage };
+enum JITArrayMode {
+    JITContiguous,
+    JITArrayStorage,
+    JITInt8Array,
+    JITInt16Array,
+    JITInt32Array,
+    JITUint8Array,
+    JITUint8ClampedArray,
+    JITUint16Array,
+    JITUint32Array,
+    JITFloat32Array,
+    JITFloat64Array
+};
 
 inline bool isOptimizableIndexingType(IndexingType indexingType)
 {
@@ -49,6 +63,17 @@ inline bool isOptimizableIndexingType(IndexingType indexingType)
     }
 }
 
+inline bool hasOptimizableIndexingForClassInfo(const ClassInfo* classInfo)
+{
+    return classInfo->typedArrayStorageType != TypedArrayNone;
+}
+
+inline bool hasOptimizableIndexing(Structure* structure)
+{
+    return isOptimizableIndexingType(structure->indexingType())
+        || hasOptimizableIndexingForClassInfo(structure->classInfo());
+}
+
 inline JITArrayMode jitArrayModeForIndexingType(IndexingType indexingType)
 {
     switch (indexingType) {
@@ -62,6 +87,42 @@ inline JITArrayMode jitArrayModeForIndexingType(IndexingType indexingType)
     }
 }
 
+inline JITArrayMode jitArrayModeForClassInfo(const ClassInfo* classInfo)
+{
+    switch (classInfo->typedArrayStorageType) {
+    case TypedArrayInt8:
+        return JITInt8Array;
+    case TypedArrayInt16:
+        return JITInt16Array;
+    case TypedArrayInt32:
+        return JITInt32Array;
+    case TypedArrayUint8:
+        return JITUint8Array;
+    case TypedArrayUint8Clamped:
+        return JITUint8ClampedArray;
+    case TypedArrayUint16:
+        return JITUint16Array;
+    case TypedArrayUint32:
+        return JITUint32Array;
+    case TypedArrayFloat32:
+        return JITFloat32Array;
+    case TypedArrayFloat64:
+        return JITFloat64Array;
+    default:
+        CRASH();
+        return JITContiguous;
+    }
+}
+
+inline JITArrayMode jitArrayModeForStructure(Structure* structure)
+{
+    if (isOptimizableIndexingType(structure->indexingType()))
+        return jitArrayModeForIndexingType(structure->indexingType());
+    
+    ASSERT(hasOptimizableIndexingForClassInfo(structure->classInfo()));
+    return jitArrayModeForClassInfo(structure->classInfo());
+}
+
 struct ByValInfo {
     ByValInfo() { }
     
@@ -71,6 +132,7 @@ struct ByValInfo {
         , arrayMode(arrayMode)
         , badTypeJumpToDone(badTypeJumpToDone)
         , returnAddressToSlowPath(returnAddressToSlowPath)
+        , slowPathCount(0)
     {
     }
     
@@ -79,6 +141,7 @@ struct ByValInfo {
     JITArrayMode arrayMode; // The array mode that was baked into the inline JIT code.
     int16_t badTypeJumpToDone;
     int16_t returnAddressToSlowPath;
+    unsigned slowPathCount;
     RefPtr<JITStubRoutine> stubRoutine;
 };
 
index b5b6684..a19b723 100644 (file)
@@ -30,8 +30,6 @@
 
 namespace JSC { namespace DFG {
 
-const double AssemblyHelpers::twoToThe32 = (double)0x100000000ull;
-
 ExecutableBase* AssemblyHelpers::executableFor(const CodeOrigin& codeOrigin)
 {
     if (!codeOrigin.inlineCallFrame)
index 348bf67..5d338fa 100644 (file)
@@ -243,33 +243,14 @@ public:
     }
 #endif
 
-#if USE(JSVALUE32_64) && CPU(X86)
+#if USE(JSVALUE32_64)
     void boxDouble(FPRReg fpr, GPRReg tagGPR, GPRReg payloadGPR)
     {
-        movePackedToInt32(fpr, payloadGPR);
-        rshiftPacked(TrustedImm32(32), fpr);
-        movePackedToInt32(fpr, tagGPR);
+        moveDoubleToInts(fpr, payloadGPR, tagGPR);
     }
     void unboxDouble(GPRReg tagGPR, GPRReg payloadGPR, FPRReg fpr, FPRReg scratchFPR)
     {
-        jitAssertIsJSDouble(tagGPR);
-        moveInt32ToPacked(payloadGPR, fpr);
-        moveInt32ToPacked(tagGPR, scratchFPR);
-        lshiftPacked(TrustedImm32(32), scratchFPR);
-        orPacked(scratchFPR, fpr);
-    }
-#endif
-
-#if USE(JSVALUE32_64) && CPU(ARM)
-    void boxDouble(FPRReg fpr, GPRReg tagGPR, GPRReg payloadGPR)
-    {
-        m_assembler.vmov(payloadGPR, tagGPR, fpr);
-    }
-    void unboxDouble(GPRReg tagGPR, GPRReg payloadGPR, FPRReg fpr, FPRReg scratchFPR)
-    {
-        jitAssertIsJSDouble(tagGPR);
-        UNUSED_PARAM(scratchFPR);
-        m_assembler.vmov(fpr, payloadGPR, tagGPR);
+        moveIntsToDouble(payloadGPR, tagGPR, fpr, scratchFPR);
     }
 #endif
     
@@ -364,8 +345,6 @@ public:
 
     Vector<BytecodeAndMachineOffset>& decodedCodeMapFor(CodeBlock*);
     
-    static const double twoToThe32;
-
 protected:
     JSGlobalData* m_globalData;
     CodeBlock* m_codeBlock;
index ca5d903..72203ea 100644 (file)
@@ -2234,7 +2234,7 @@ void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor&
         m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesFour), resultReg);
         break;
     default:
-        ASSERT_NOT_REACHED();
+        CRASH();
     }
     if (elementSize < 4 || signedness == SignedTypedArray) {
         integerResult(resultReg, m_compileIndex);
@@ -2344,7 +2344,7 @@ void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor&
         m_jit.store32(value.gpr(), MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesFour));
         break;
     default:
-        ASSERT_NOT_REACHED();
+        CRASH();
     }
     if (node.op() == PutByVal)
         outOfBounds.link(&m_jit);
index c5f66ec..f2ce6a6 100644 (file)
@@ -2237,14 +2237,6 @@ public:
 #endif
     void compileArithMod(Node&);
     void compileSoftModulo(Node&);
-    enum TypedArraySignedness {
-        SignedTypedArray,
-        UnsignedTypedArray
-    };
-    enum TypedArrayRounding {
-        TruncateRounding,
-        ClampRounding
-    };
     void compileGetIndexedPropertyStorage(Node&);
     void compileGetByValOnIntTypedArray(const TypedArrayDescriptor&, Node&, size_t elementSize, TypedArraySignedness);
     void compilePutByValForIntTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize, TypedArraySignedness, TypedArrayRounding = TruncateRounding);
index 49424c8..410d101 100644 (file)
@@ -497,6 +497,8 @@ namespace JSC {
         // case contains result in regT0, and it is not yet profiled.
         JumpList emitContiguousGetByVal(Instruction*, PatchableJump& badType);
         JumpList emitArrayStorageGetByVal(Instruction*, PatchableJump& badType);
+        JumpList emitIntTypedArrayGetByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor&, size_t elementSize, TypedArraySignedness);
+        JumpList emitFloatTypedArrayGetByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor&, size_t elementSize);
         
         // Property is in regT0, base is in regT0. regT2 contains indecing type.
         // The value to store is not yet loaded. Property is int-checked and
@@ -504,7 +506,9 @@ namespace JSC {
         // returns the slow cases.
         JumpList emitContiguousPutByVal(Instruction*, PatchableJump& badType);
         JumpList emitArrayStoragePutByVal(Instruction*, PatchableJump& badType);
-
+        JumpList emitIntTypedArrayPutByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor&, size_t elementSize, TypedArraySignedness, TypedArrayRounding);
+        JumpList emitFloatTypedArrayPutByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor&, size_t elementSize);
+        
         enum FinalObjectMode { MayBeFinal, KnownNotFinal };
 
 #if USE(JSVALUE32_64)
index 5cb1550..05b64ec 100644 (file)
@@ -562,6 +562,8 @@ inline void JIT::emitArrayProfileStoreToHoleSpecialCase(ArrayProfile* arrayProfi
 {
 #if ENABLE(VALUE_PROFILER)    
     store8(TrustedImm32(1), arrayProfile->addressOfMayStoreToHole());
+#else
+    UNUSED_PARAM(arrayProfile);
 #endif
 }
 
@@ -570,6 +572,8 @@ static inline bool arrayProfileSaw(ArrayProfile* profile, IndexingType capabilit
 #if ENABLE(VALUE_PROFILER)
     return !!(profile->observedArrayModes() & (asArrayModes(NonArray | capability) | asArrayModes(ArrayClass | capability)));
 #else
+    UNUSED_PARAM(profile);
+    UNUSED_PARAM(capability);
     return false;
 #endif
 }
index 9fc410c..4163321 100644 (file)
@@ -125,6 +125,9 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
     case JITArrayStorage:
         slowCases = emitArrayStorageGetByVal(currentInstruction, badType);
         break;
+    default:
+        CRASH();
+        break;
     }
     
     addSlowCase(badType);
@@ -304,6 +307,9 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
     case JITArrayStorage:
         slowCases = emitArrayStoragePutByVal(currentInstruction, badType);
         break;
+    default:
+        CRASH();
+        break;
     }
     
     addSlowCase(badType);
@@ -1413,6 +1419,33 @@ void JIT::privateCompileGetByVal(ByValInfo* byValInfo, ReturnAddressPtr returnAd
     case JITArrayStorage:
         slowCases = emitArrayStorageGetByVal(currentInstruction, badType);
         break;
+    case JITInt8Array:
+        slowCases = emitIntTypedArrayGetByVal(currentInstruction, badType, m_globalData->int8ArrayDescriptor(), 1, SignedTypedArray);
+        break;
+    case JITInt16Array:
+        slowCases = emitIntTypedArrayGetByVal(currentInstruction, badType, m_globalData->int16ArrayDescriptor(), 2, SignedTypedArray);
+        break;
+    case JITInt32Array:
+        slowCases = emitIntTypedArrayGetByVal(currentInstruction, badType, m_globalData->int32ArrayDescriptor(), 4, SignedTypedArray);
+        break;
+    case JITUint8Array:
+    case JITUint8ClampedArray:
+        slowCases = emitIntTypedArrayGetByVal(currentInstruction, badType, m_globalData->uint8ArrayDescriptor(), 1, UnsignedTypedArray);
+        break;
+    case JITUint16Array:
+        slowCases = emitIntTypedArrayGetByVal(currentInstruction, badType, m_globalData->uint16ArrayDescriptor(), 2, UnsignedTypedArray);
+        break;
+    case JITUint32Array:
+        slowCases = emitIntTypedArrayGetByVal(currentInstruction, badType, m_globalData->uint32ArrayDescriptor(), 4, UnsignedTypedArray);
+        break;
+    case JITFloat32Array:
+        slowCases = emitFloatTypedArrayGetByVal(currentInstruction, badType, m_globalData->float32ArrayDescriptor(), 4);
+        break;
+    case JITFloat64Array:
+        slowCases = emitFloatTypedArrayGetByVal(currentInstruction, badType, m_globalData->float64ArrayDescriptor(), 8);
+        break;
+    default:
+        CRASH();
     }
     
     Jump done = jump();
@@ -1447,6 +1480,36 @@ void JIT::privateCompilePutByVal(ByValInfo* byValInfo, ReturnAddressPtr returnAd
     case JITArrayStorage:
         slowCases = emitArrayStoragePutByVal(currentInstruction, badType);
         break;
+    case JITInt8Array:
+        slowCases = emitIntTypedArrayPutByVal(currentInstruction, badType, m_globalData->int8ArrayDescriptor(), 1, SignedTypedArray, TruncateRounding);
+        break;
+    case JITInt16Array:
+        slowCases = emitIntTypedArrayPutByVal(currentInstruction, badType, m_globalData->int16ArrayDescriptor(), 2, SignedTypedArray, TruncateRounding);
+        break;
+    case JITInt32Array:
+        slowCases = emitIntTypedArrayPutByVal(currentInstruction, badType, m_globalData->int32ArrayDescriptor(), 4, SignedTypedArray, TruncateRounding);
+        break;
+    case JITUint8Array:
+        slowCases = emitIntTypedArrayPutByVal(currentInstruction, badType, m_globalData->uint8ArrayDescriptor(), 1, UnsignedTypedArray, TruncateRounding);
+        break;
+    case JITUint8ClampedArray:
+        slowCases = emitIntTypedArrayPutByVal(currentInstruction, badType, m_globalData->uint8ClampedArrayDescriptor(), 1, UnsignedTypedArray, ClampRounding);
+        break;
+    case JITUint16Array:
+        slowCases = emitIntTypedArrayPutByVal(currentInstruction, badType, m_globalData->uint16ArrayDescriptor(), 2, UnsignedTypedArray, TruncateRounding);
+        break;
+    case JITUint32Array:
+        slowCases = emitIntTypedArrayPutByVal(currentInstruction, badType, m_globalData->uint32ArrayDescriptor(), 4, UnsignedTypedArray, TruncateRounding);
+        break;
+    case JITFloat32Array:
+        slowCases = emitFloatTypedArrayPutByVal(currentInstruction, badType, m_globalData->float32ArrayDescriptor(), 4);
+        break;
+    case JITFloat64Array:
+        slowCases = emitFloatTypedArrayPutByVal(currentInstruction, badType, m_globalData->float64ArrayDescriptor(), 8);
+        break;
+    default:
+        CRASH();
+        break;
     }
     
     Jump done = jump();
@@ -1467,6 +1530,252 @@ void JIT::privateCompilePutByVal(ByValInfo* byValInfo, ReturnAddressPtr returnAd
     repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_put_by_val_generic));
 }
 
+JIT::JumpList JIT::emitIntTypedArrayGetByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor& descriptor, size_t elementSize, TypedArraySignedness signedness)
+{
+    // The best way to test the array type is to use the classInfo. We need to do so without
+    // clobbering the register that holds the indexing type, base, and property.
+
+#if USE(JSVALUE64)
+    RegisterID base = regT0;
+    RegisterID property = regT1;
+    RegisterID resultPayload = regT0;
+    RegisterID scratch = regT3;
+#else
+    RegisterID base = regT0;
+    RegisterID property = regT2;
+    RegisterID resultPayload = regT0;
+    RegisterID resultTag = regT1;
+    RegisterID scratch = regT3;
+#endif
+    
+    JumpList slowCases;
+    
+    loadPtr(Address(base, JSCell::structureOffset()), scratch);
+    badType = patchableBranchPtr(NotEqual, Address(scratch, Structure::classInfoOffset()), TrustedImmPtr(descriptor.m_classInfo));
+    slowCases.append(branch32(AboveOrEqual, property, Address(base, descriptor.m_lengthOffset)));
+    loadPtr(Address(base, descriptor.m_storageOffset), base);
+    
+    switch (elementSize) {
+    case 1:
+        if (signedness == SignedTypedArray)
+            load8Signed(BaseIndex(base, property, TimesOne), resultPayload);
+        else
+            load8(BaseIndex(base, property, TimesOne), resultPayload);
+        break;
+    case 2:
+        if (signedness == SignedTypedArray)
+            load16Signed(BaseIndex(base, property, TimesTwo), resultPayload);
+        else
+            load16(BaseIndex(base, property, TimesTwo), resultPayload);
+        break;
+    case 4:
+        load32(BaseIndex(base, property, TimesFour), resultPayload);
+        break;
+    default:
+        CRASH();
+    }
+    
+    Jump done;
+    if (elementSize == 4 && signedness == UnsignedTypedArray) {
+        Jump canBeInt = branch32(GreaterThanOrEqual, resultPayload, TrustedImm32(0));
+        
+        convertInt32ToDouble(resultPayload, fpRegT0);
+        addDouble(AbsoluteAddress(&twoToThe32), fpRegT0);
+#if USE(JSVALUE64)
+        moveDoubleToPtr(fpRegT0, resultPayload);
+        subPtr(tagTypeNumberRegister, resultPayload);
+#else
+        moveDoubleToInts(fpRegT0, resultPayload, resultTag);
+#endif
+        
+        done = jump();
+        canBeInt.link(this);
+    }
+
+#if USE(JSVALUE64)
+    orPtr(tagTypeNumberRegister, resultPayload);
+#else
+    move(TrustedImm32(JSValue::Int32Tag), resultTag);
+#endif
+    if (done.isSet())
+        done.link(this);
+    return slowCases;
+}
+
+JIT::JumpList JIT::emitFloatTypedArrayGetByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor& descriptor, size_t elementSize)
+{
+#if USE(JSVALUE64)
+    RegisterID base = regT0;
+    RegisterID property = regT1;
+    RegisterID resultPayload = regT0;
+    RegisterID scratch = regT3;
+#else
+    RegisterID base = regT0;
+    RegisterID property = regT2;
+    RegisterID resultPayload = regT0;
+    RegisterID resultTag = regT1;
+    RegisterID scratch = regT3;
+#endif
+    
+    JumpList slowCases;
+    
+    loadPtr(Address(base, JSCell::structureOffset()), scratch);
+    badType = patchableBranchPtr(NotEqual, Address(scratch, Structure::classInfoOffset()), TrustedImmPtr(descriptor.m_classInfo));
+    slowCases.append(branch32(AboveOrEqual, property, Address(base, descriptor.m_lengthOffset)));
+    loadPtr(Address(base, descriptor.m_storageOffset), base);
+    
+    switch (elementSize) {
+    case 4:
+        loadFloat(BaseIndex(base, property, TimesFour), fpRegT0);
+        convertFloatToDouble(fpRegT0, fpRegT0);
+        break;
+    case 8: {
+        loadDouble(BaseIndex(base, property, TimesEight), fpRegT0);
+        Jump notNaN = branchDouble(DoubleEqual, fpRegT0, fpRegT0);
+        static const double NaN = std::numeric_limits<double>::quiet_NaN();
+        loadDouble(&NaN, fpRegT0);
+        notNaN.link(this);
+        break;
+    }
+    default:
+        CRASH();
+    }
+    
+#if USE(JSVALUE64)
+    moveDoubleToPtr(fpRegT0, resultPayload);
+    subPtr(tagTypeNumberRegister, resultPayload);
+#else
+    moveDoubleToInts(fpRegT0, resultPayload, resultTag);
+#endif
+    return slowCases;    
+}
+
+JIT::JumpList JIT::emitIntTypedArrayPutByVal(Instruction* currentInstruction, PatchableJump& badType, const TypedArrayDescriptor& descriptor, size_t elementSize, TypedArraySignedness signedness, TypedArrayRounding rounding)
+{
+    unsigned value = currentInstruction[3].u.operand;
+
+#if USE(JSVALUE64)
+    RegisterID base = regT0;
+    RegisterID property = regT1;
+    RegisterID earlyScratch = regT3;
+    RegisterID lateScratch = regT2;
+#else
+    RegisterID base = regT0;
+    RegisterID property = regT2;
+    RegisterID earlyScratch = regT3;
+    RegisterID lateScratch = regT1;
+#endif
+    
+    JumpList slowCases;
+    
+    loadPtr(Address(base, JSCell::structureOffset()), earlyScratch);
+    badType = patchableBranchPtr(NotEqual, Address(earlyScratch, Structure::classInfoOffset()), TrustedImmPtr(descriptor.m_classInfo));
+    slowCases.append(branch32(AboveOrEqual, property, Address(base, descriptor.m_lengthOffset)));
+    
+#if USE(JSVALUE64)
+    emitGetVirtualRegister(value, earlyScratch);
+    slowCases.append(emitJumpIfNotImmediateInteger(earlyScratch));
+#else
+    emitLoad(value, lateScratch, earlyScratch);
+    slowCases.append(branch32(NotEqual, lateScratch, TrustedImm32(JSValue::Int32Tag)));
+#endif
+    
+    // We would be loading this into base as in get_by_val, except that the slow
+    // path expects the base to be unclobbered.
+    loadPtr(Address(base, descriptor.m_storageOffset), lateScratch);
+    
+    if (rounding == ClampRounding) {
+        ASSERT(elementSize == 1);
+        ASSERT_UNUSED(signedness, signedness = UnsignedTypedArray);
+        Jump inBounds = branch32(BelowOrEqual, earlyScratch, TrustedImm32(0xff));
+        Jump tooBig = branch32(GreaterThan, earlyScratch, TrustedImm32(0xff));
+        xor32(earlyScratch, earlyScratch);
+        Jump clamped = jump();
+        tooBig.link(this);
+        move(TrustedImm32(0xff), earlyScratch);
+        clamped.link(this);
+        inBounds.link(this);
+    }
+    
+    switch (elementSize) {
+    case 1:
+        store8(earlyScratch, BaseIndex(lateScratch, property, TimesOne));
+        break;
+    case 2:
+        store16(earlyScratch, BaseIndex(lateScratch, property, TimesTwo));
+        break;
+    case 4:
+        store32(earlyScratch, BaseIndex(lateScratch, property, TimesFour));
+        break;
+    default:
+        CRASH();
+    }
+    
+    return slowCases;
+}
+
+JIT::JumpList JIT::emitFloatTypedArrayPutByVal(Instruction* currentInstruction, PatchableJump& badType, const TypedArrayDescriptor& descriptor, size_t elementSize)
+{
+    unsigned value = currentInstruction[3].u.operand;
+
+#if USE(JSVALUE64)
+    RegisterID base = regT0;
+    RegisterID property = regT1;
+    RegisterID earlyScratch = regT3;
+    RegisterID lateScratch = regT2;
+#else
+    RegisterID base = regT0;
+    RegisterID property = regT2;
+    RegisterID earlyScratch = regT3;
+    RegisterID lateScratch = regT1;
+#endif
+    
+    JumpList slowCases;
+    
+    loadPtr(Address(base, JSCell::structureOffset()), earlyScratch);
+    badType = patchableBranchPtr(NotEqual, Address(earlyScratch, Structure::classInfoOffset()), TrustedImmPtr(descriptor.m_classInfo));
+    slowCases.append(branch32(AboveOrEqual, property, Address(base, descriptor.m_lengthOffset)));
+    
+#if USE(JSVALUE64)
+    emitGetVirtualRegister(value, earlyScratch);
+    Jump doubleCase = emitJumpIfNotImmediateInteger(earlyScratch);
+    convertInt32ToDouble(earlyScratch, fpRegT0);
+    Jump ready = jump();
+    doubleCase.link(this);
+    slowCases.append(emitJumpIfNotImmediateNumber(earlyScratch));
+    addPtr(tagTypeNumberRegister, earlyScratch);
+    movePtrToDouble(earlyScratch, fpRegT0);
+    ready.link(this);
+#else
+    emitLoad(value, lateScratch, earlyScratch);
+    Jump doubleCase = branch32(NotEqual, lateScratch, TrustedImm32(JSValue::Int32Tag));
+    convertInt32ToDouble(earlyScratch, fpRegT0);
+    Jump ready = jump();
+    doubleCase.link(this);
+    slowCases.append(branch32(Above, lateScratch, TrustedImm32(JSValue::LowestTag)));
+    moveIntsToDouble(earlyScratch, lateScratch, fpRegT0, fpRegT1);
+    ready.link(this);
+#endif
+    
+    // We would be loading this into base as in get_by_val, except that the slow
+    // path expects the base to be unclobbered.
+    loadPtr(Address(base, descriptor.m_storageOffset), lateScratch);
+    
+    switch (elementSize) {
+    case 4:
+        convertDoubleToFloat(fpRegT0, fpRegT0);
+        storeFloat(fpRegT0, BaseIndex(lateScratch, property, TimesFour));
+        break;
+    case 8:
+        storeDouble(fpRegT0, BaseIndex(lateScratch, property, TimesEight));
+        break;
+    default:
+        CRASH();
+    }
+    
+    return slowCases;
+}
+
 } // namespace JSC
 
 #endif // ENABLE(JIT)
index b561e8d..52875f5 100644 (file)
@@ -224,6 +224,8 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
     case JITArrayStorage:
         slowCases = emitArrayStorageGetByVal(currentInstruction, badType);
         break;
+    default:
+        CRASH();
     }
     
     addSlowCase(badType);
@@ -337,6 +339,9 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
     case JITArrayStorage:
         slowCases = emitArrayStoragePutByVal(currentInstruction, badType);
         break;
+    default:
+        CRASH();
+        break;
     }
     
     addSlowCase(badType);
index 0a9f8b3..98646b6 100644 (file)
@@ -2451,21 +2451,33 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val)
     if (baseValue.isObject() && subscript.isInt32()) {
         // See if it's worth optimizing this at all.
         JSObject* object = asObject(baseValue);
-        IndexingType indexingType = object->structure()->indexingType();
-        if (object->structure()->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) {
-            // Don't ever try to optimize.
-            RepatchBuffer repatchBuffer(callFrame->codeBlock());
-            repatchBuffer.relinkCallerToFunction(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val_generic));
-        } else {
+        bool didOptimize = false;
+
+        unsigned bytecodeOffset = callFrame->bytecodeOffsetForNonDFGCode();
+        ASSERT(bytecodeOffset);
+        ByValInfo& byValInfo = callFrame->codeBlock()->getByValInfo(bytecodeOffset - 1);
+        ASSERT(!byValInfo.stubRoutine);
+        
+        if (hasOptimizableIndexing(object->structure())) {
             // Attempt to optimize.
-            unsigned bytecodeOffset = callFrame->bytecodeOffsetForNonDFGCode();
-            ASSERT(bytecodeOffset);
-            ByValInfo& byValInfo = callFrame->codeBlock()->getByValInfo(bytecodeOffset - 1);
-            ASSERT(!byValInfo.stubRoutine);
-            if (isOptimizableIndexingType(indexingType)) {
-                JITArrayMode arrayMode = jitArrayModeForIndexingType(indexingType);
-                if (arrayMode != byValInfo.arrayMode)
-                    JIT::compileGetByVal(&callFrame->globalData(), callFrame->codeBlock(), &byValInfo, STUB_RETURN_ADDRESS, arrayMode);
+            JITArrayMode arrayMode = jitArrayModeForStructure(object->structure());
+            if (arrayMode != byValInfo.arrayMode) {
+                JIT::compileGetByVal(&callFrame->globalData(), callFrame->codeBlock(), &byValInfo, STUB_RETURN_ADDRESS, arrayMode);
+                didOptimize = true;
+            }
+        }
+        
+        if (!didOptimize) {
+            // If we take slow path more than 10 times without patching then make sure we
+            // never make that mistake again. Or, if we failed to patch and we have some object
+            // that intercepts indexed get, then don't even wait until 10 times. For cases
+            // where we see non-index-intercepting objects, this gives 10 iterations worth of
+            // opportunity for us to observe that the get_by_val may be polymorphic.
+            if (++byValInfo.slowPathCount >= 10
+                || object->structure()->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) {
+                // Don't ever try to optimize.
+                RepatchBuffer repatchBuffer(callFrame->codeBlock());
+                repatchBuffer.relinkCallerToFunction(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val_generic));
             }
         }
     }
@@ -2573,21 +2585,33 @@ DEFINE_STUB_FUNCTION(void, op_put_by_val)
     if (baseValue.isObject() && subscript.isInt32()) {
         // See if it's worth optimizing at all.
         JSObject* object = asObject(baseValue);
-        IndexingType indexingType = object->structure()->indexingType();
-        if (object->structure()->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) {
-            // Dont ever try to optimize.
-            RepatchBuffer repatchBuffer(callFrame->codeBlock());
-            repatchBuffer.relinkCallerToFunction(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_val_generic));
-        } else {
+        bool didOptimize = false;
+
+        unsigned bytecodeOffset = callFrame->bytecodeOffsetForNonDFGCode();
+        ASSERT(bytecodeOffset);
+        ByValInfo& byValInfo = callFrame->codeBlock()->getByValInfo(bytecodeOffset - 1);
+        ASSERT(!byValInfo.stubRoutine);
+        
+        if (hasOptimizableIndexing(object->structure())) {
             // Attempt to optimize.
-            unsigned bytecodeOffset = callFrame->bytecodeOffsetForNonDFGCode();
-            ASSERT(bytecodeOffset);
-            ByValInfo& byValInfo = callFrame->codeBlock()->getByValInfo(bytecodeOffset - 1);
-            ASSERT(!byValInfo.stubRoutine);
-            if (isOptimizableIndexingType(indexingType)) {
-                JITArrayMode arrayMode = jitArrayModeForIndexingType(indexingType);
-                if (arrayMode != byValInfo.arrayMode)
-                    JIT::compilePutByVal(&callFrame->globalData(), callFrame->codeBlock(), &byValInfo, STUB_RETURN_ADDRESS, arrayMode);
+            JITArrayMode arrayMode = jitArrayModeForStructure(object->structure());
+            if (arrayMode != byValInfo.arrayMode) {
+                JIT::compilePutByVal(&callFrame->globalData(), callFrame->codeBlock(), &byValInfo, STUB_RETURN_ADDRESS, arrayMode);
+                didOptimize = true;
+            }
+        }
+
+        if (!didOptimize) {
+            // If we take slow path more than 10 times without patching then make sure we
+            // never make that mistake again. Or, if we failed to patch and we have some object
+            // that intercepts indexed get, then don't even wait until 10 times. For cases
+            // where we see non-index-intercepting objects, this gives 10 iterations worth of
+            // opportunity for us to observe that the get_by_val may be polymorphic.
+            if (++byValInfo.slowPathCount >= 10
+                || object->structure()->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) {
+                // Don't ever try to optimize.
+                RepatchBuffer repatchBuffer(callFrame->codeBlock());
+                repatchBuffer.relinkCallerToFunction(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_val_generic));
             }
         }
     }
index 87e5737..1cc5b81 100644 (file)
@@ -31,6 +31,7 @@
 #include "JSValueInlineMethods.h"
 #include "SlotVisitor.h"
 #include "SlotVisitorInlineMethods.h"
+#include "TypedArrayDescriptor.h"
 #include "WriteBarrier.h"
 #include <wtf/Noncopyable.h>
 #include <wtf/TypeTraits.h>
@@ -49,19 +50,6 @@ namespace JSC {
         IncludeDontEnumProperties
     };
 
-    enum TypedArrayType {
-        TypedArrayNone,
-        TypedArrayInt8,
-        TypedArrayInt16,
-        TypedArrayInt32,
-        TypedArrayUint8,
-        TypedArrayUint8Clamped,
-        TypedArrayUint16,
-        TypedArrayUint32,
-        TypedArrayFloat32,
-        TypedArrayFloat64
-    };
-
     class JSCell {
         friend class JSValue;
         friend class MarkedBlock;
index 603f9f8..6cc0aad 100644 (file)
@@ -44,6 +44,7 @@
 #include "Strong.h"
 #include "Terminator.h"
 #include "TimeoutChecker.h"
+#include "TypedArrayDescriptor.h"
 #include "WeakRandom.h"
 #include <wtf/BumpPointerAllocator.h>
 #include <wtf/Forward.h>
@@ -108,24 +109,6 @@ namespace JSC {
         ThreadStackTypeSmall
     };
 
-    struct TypedArrayDescriptor {
-        TypedArrayDescriptor()
-            : m_classInfo(0)
-            , m_storageOffset(0)
-            , m_lengthOffset(0)
-        {
-        }
-        TypedArrayDescriptor(const ClassInfo* classInfo, size_t storageOffset, size_t lengthOffset)
-            : m_classInfo(classInfo)
-            , m_storageOffset(storageOffset)
-            , m_lengthOffset(lengthOffset)
-        {
-        }
-        const ClassInfo* m_classInfo;
-        size_t m_storageOffset;
-        size_t m_lengthOffset;
-    };
-
 #if ENABLE(DFG_JIT)
     class ConservativeRoots;
 
@@ -429,6 +412,35 @@ namespace JSC {
         registerTypedArrayFunction(float32, Float32);
         registerTypedArrayFunction(float64, Float64);
 #undef registerTypedArrayFunction
+        
+        const TypedArrayDescriptor* typedArrayDescriptor(TypedArrayType type) const
+        {
+            switch (type) {
+            case TypedArrayNone:
+                return 0;
+            case TypedArrayInt8:
+                return &int8ArrayDescriptor();
+            case TypedArrayInt16:
+                return &int16ArrayDescriptor();
+            case TypedArrayInt32:
+                return &int32ArrayDescriptor();
+            case TypedArrayUint8:
+                return &uint8ArrayDescriptor();
+            case TypedArrayUint8Clamped:
+                return &uint8ClampedArrayDescriptor();
+            case TypedArrayUint16:
+                return &uint16ArrayDescriptor();
+            case TypedArrayUint32:
+                return &uint32ArrayDescriptor();
+            case TypedArrayFloat32:
+                return &float32ArrayDescriptor();
+            case TypedArrayFloat64:
+                return &float64ArrayDescriptor();
+            default:
+                CRASH();
+                return 0;
+            }
+        }
 
         JSLock& apiLock() { return m_apiLock; }
 
diff --git a/Source/JavaScriptCore/runtime/TypedArrayDescriptor.h b/Source/JavaScriptCore/runtime/TypedArrayDescriptor.h
new file mode 100644 (file)
index 0000000..1ae4818
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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 TypedArrayDescriptor_h
+#define TypedArrayDescriptor_h
+
+namespace JSC {
+
+struct ClassInfo;
+
+enum TypedArrayType {
+    TypedArrayNone,
+    TypedArrayInt8,
+    TypedArrayInt16,
+    TypedArrayInt32,
+    TypedArrayUint8,
+    TypedArrayUint8Clamped,
+    TypedArrayUint16,
+    TypedArrayUint32,
+    TypedArrayFloat32,
+    TypedArrayFloat64
+};
+
+struct TypedArrayDescriptor {
+    TypedArrayDescriptor()
+        : m_classInfo(0)
+        , m_storageOffset(0)
+        , m_lengthOffset(0)
+    {
+    }
+    TypedArrayDescriptor(const ClassInfo* classInfo, size_t storageOffset, size_t lengthOffset)
+        : m_classInfo(classInfo)
+        , m_storageOffset(storageOffset)
+        , m_lengthOffset(lengthOffset)
+    {
+    }
+    const ClassInfo* m_classInfo;
+    size_t m_storageOffset;
+    size_t m_lengthOffset;
+};
+
+enum TypedArraySignedness {
+    SignedTypedArray,
+    UnsignedTypedArray
+};
+enum TypedArrayRounding {
+    TruncateRounding,
+    ClampRounding
+};
+
+} // namespace JSC
+
+#endif // TypedArrayDescriptor_h
+