Title: [129045] trunk/Source/_javascript_Core
Revision
129045
Author
[email protected]
Date
2012-09-19 14:43:10 -0700 (Wed, 19 Sep 2012)

Log Message

DFG should not emit PutByVal hole case unless it has to
https://bugs.webkit.org/show_bug.cgi?id=97080

Reviewed by Geoffrey Garen.

This causes us to generate less code for typical PutByVal's. But if profiling tells us
that the hole case is being hit, we generate the same code as we would have generated
before. This seems like a slight speed-up across the board.

* assembler/MacroAssemblerARMv7.h:
(JSC::MacroAssemblerARMv7::store8):
(MacroAssemblerARMv7):
* assembler/MacroAssemblerX86.h:
(MacroAssemblerX86):
(JSC::MacroAssemblerX86::store8):
* assembler/MacroAssemblerX86_64.h:
(MacroAssemblerX86_64):
(JSC::MacroAssemblerX86_64::store8):
* assembler/X86Assembler.h:
(X86Assembler):
(JSC::X86Assembler::movb_i8m):
* bytecode/ArrayProfile.h:
(JSC::ArrayProfile::ArrayProfile):
(JSC::ArrayProfile::addressOfMayStoreToHole):
(JSC::ArrayProfile::mayStoreToHole):
(ArrayProfile):
* dfg/DFGArrayMode.cpp:
(JSC::DFG::fromObserved):
(JSC::DFG::modeAlreadyChecked):
(JSC::DFG::modeToString):
* dfg/DFGArrayMode.h:
(DFG):
(JSC::DFG::mayStoreToHole):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* jit/JIT.h:
(JIT):
* jit/JITInlineMethods.h:
(JSC::JIT::emitArrayProfileStoreToHoleSpecialCase):
(JSC):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_put_by_val):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_put_by_val):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (129044 => 129045)


--- trunk/Source/_javascript_Core/ChangeLog	2012-09-19 21:35:01 UTC (rev 129044)
+++ trunk/Source/_javascript_Core/ChangeLog	2012-09-19 21:43:10 UTC (rev 129045)
@@ -1,3 +1,54 @@
+2012-09-19  Filip Pizlo  <[email protected]>
+
+        DFG should not emit PutByVal hole case unless it has to
+        https://bugs.webkit.org/show_bug.cgi?id=97080
+
+        Reviewed by Geoffrey Garen.
+
+        This causes us to generate less code for typical PutByVal's. But if profiling tells us
+        that the hole case is being hit, we generate the same code as we would have generated
+        before. This seems like a slight speed-up across the board.
+
+        * assembler/MacroAssemblerARMv7.h:
+        (JSC::MacroAssemblerARMv7::store8):
+        (MacroAssemblerARMv7):
+        * assembler/MacroAssemblerX86.h:
+        (MacroAssemblerX86):
+        (JSC::MacroAssemblerX86::store8):
+        * assembler/MacroAssemblerX86_64.h:
+        (MacroAssemblerX86_64):
+        (JSC::MacroAssemblerX86_64::store8):
+        * assembler/X86Assembler.h:
+        (X86Assembler):
+        (JSC::X86Assembler::movb_i8m):
+        * bytecode/ArrayProfile.h:
+        (JSC::ArrayProfile::ArrayProfile):
+        (JSC::ArrayProfile::addressOfMayStoreToHole):
+        (JSC::ArrayProfile::mayStoreToHole):
+        (ArrayProfile):
+        * dfg/DFGArrayMode.cpp:
+        (JSC::DFG::fromObserved):
+        (JSC::DFG::modeAlreadyChecked):
+        (JSC::DFG::modeToString):
+        * dfg/DFGArrayMode.h:
+        (DFG):
+        (JSC::DFG::mayStoreToHole):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * jit/JIT.h:
+        (JIT):
+        * jit/JITInlineMethods.h:
+        (JSC::JIT::emitArrayProfileStoreToHoleSpecialCase):
+        (JSC):
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emit_op_put_by_val):
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::emit_op_put_by_val):
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+
 2012-09-18  Filip Pizlo  <[email protected]>
 
         DFG should not call out to C++ every time that it tries to put to an object that doesn't yet have array storage

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARMv7.h (129044 => 129045)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARMv7.h	2012-09-19 21:35:01 UTC (rev 129044)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARMv7.h	2012-09-19 21:43:10 UTC (rev 129045)
@@ -737,6 +737,12 @@
         store8(src, setupArmAddress(address));
     }
     
+    void store8(RegisterID src, void* address)
+    {
+        move(TrustedImmPtr(address), addressTempRegister);
+        store8(src, ArmAddress(addressTempRegister, 0));
+    }
+    
     void store16(RegisterID src, BaseIndex address)
     {
         store16(src, setupArmAddress(address));

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86.h (129044 => 129045)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86.h	2012-09-19 21:35:01 UTC (rev 129044)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86.h	2012-09-19 21:43:10 UTC (rev 129045)
@@ -44,6 +44,7 @@
     using MacroAssemblerX86Common::or32;
     using MacroAssemblerX86Common::load32;
     using MacroAssemblerX86Common::store32;
+    using MacroAssemblerX86Common::store8;
     using MacroAssemblerX86Common::branch32;
     using MacroAssemblerX86Common::call;
     using MacroAssemblerX86Common::jump;
@@ -132,6 +133,12 @@
         m_assembler.movl_rm(src, address);
     }
 
+    void store8(TrustedImm32 imm, void* address)
+    {
+        ASSERT(-128 <= imm.m_value && imm.m_value < 128);
+        m_assembler.movb_i8m(imm.m_value, address);
+    }
+
     Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
     {
         m_assembler.addl_im(imm.m_value, dest.m_ptr);

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h (129044 => 129045)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h	2012-09-19 21:35:01 UTC (rev 129044)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h	2012-09-19 21:43:10 UTC (rev 129045)
@@ -45,6 +45,7 @@
     using MacroAssemblerX86Common::sub32;
     using MacroAssemblerX86Common::load32;
     using MacroAssemblerX86Common::store32;
+    using MacroAssemblerX86Common::store8;
     using MacroAssemblerX86Common::call;
     using MacroAssemblerX86Common::jump;
     using MacroAssemblerX86Common::addDouble;
@@ -114,6 +115,12 @@
         move(TrustedImmPtr(address), scratchRegister);
         store32(imm, scratchRegister);
     }
+    
+    void store8(TrustedImm32 imm, void* address)
+    {
+        move(TrustedImmPtr(address), scratchRegister);
+        store8(imm, Address(scratchRegister));
+    }
 
     Call call()
     {

Modified: trunk/Source/_javascript_Core/assembler/X86Assembler.h (129044 => 129045)


--- trunk/Source/_javascript_Core/assembler/X86Assembler.h	2012-09-19 21:35:01 UTC (rev 129044)
+++ trunk/Source/_javascript_Core/assembler/X86Assembler.h	2012-09-19 21:43:10 UTC (rev 129045)
@@ -1155,6 +1155,15 @@
         m_formatter.immediate32(imm);
     }
 
+#if !CPU(X86_64)
+    void movb_i8m(int imm, const void* addr)
+    {
+        ASSERT(-128 <= imm && imm < 128);
+        m_formatter.oneByteOp(OP_GROUP11_EvIb, GROUP11_MOV, addr);
+        m_formatter.immediate8(imm);
+    }
+#endif
+
     void movb_i8m(int imm, int offset, RegisterID base)
     {
         ASSERT(-128 <= imm && imm < 128);

Modified: trunk/Source/_javascript_Core/bytecode/ArrayProfile.h (129044 => 129045)


--- trunk/Source/_javascript_Core/bytecode/ArrayProfile.h	2012-09-19 21:35:01 UTC (rev 129044)
+++ trunk/Source/_javascript_Core/bytecode/ArrayProfile.h	2012-09-19 21:43:10 UTC (rev 129045)
@@ -54,6 +54,7 @@
         , m_lastSeenStructure(0)
         , m_expectedStructure(0)
         , m_structureIsPolymorphic(false)
+        , m_mayStoreToHole(false)
         , m_mayInterceptIndexedAccesses(false)
         , m_observedArrayModes(0)
     {
@@ -64,6 +65,7 @@
         , m_lastSeenStructure(0)
         , m_expectedStructure(0)
         , m_structureIsPolymorphic(false)
+        , m_mayStoreToHole(false)
         , m_mayInterceptIndexedAccesses(false)
         , m_observedArrayModes(0)
     {
@@ -73,6 +75,7 @@
     
     Structure** addressOfLastSeenStructure() { return &m_lastSeenStructure; }
     ArrayModes* addressOfArrayModes() { return &m_observedArrayModes; }
+    bool* addressOfMayStoreToHole() { return &m_mayStoreToHole; }
     
     void observeStructure(Structure* structure)
     {
@@ -93,6 +96,8 @@
     ArrayModes observedArrayModes() const { return m_observedArrayModes; }
     bool mayInterceptIndexedAccesses() const { return m_mayInterceptIndexedAccesses; }
     
+    bool mayStoreToHole() const { return m_mayStoreToHole; }
+    
 private:
     friend class LLIntOffsetsExtractor;
     
@@ -100,6 +105,7 @@
     Structure* m_lastSeenStructure;
     Structure* m_expectedStructure;
     bool m_structureIsPolymorphic;
+    bool m_mayStoreToHole; // This flag may become overloaded to indicate other special cases that were encountered during array access, as it depends on indexing type. Since we currently have basically just one indexing type (two variants of ArrayStorage), this flag for now just means exactly what its name implies.
     bool m_mayInterceptIndexedAccesses;
     ArrayModes m_observedArrayModes;
 };

Modified: trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp (129044 => 129045)


--- trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp	2012-09-19 21:35:01 UTC (rev 129044)
+++ trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp	2012-09-19 21:43:10 UTC (rev 129045)
@@ -42,17 +42,17 @@
             return Array::BlankToArrayStorage; // FIXME: we don't know whether to go to slow put mode, or not. This is a decent guess.
         return Array::Undecided;
     case asArrayModes(NonArrayWithArrayStorage):
-        return makeSafe ? Array::ArrayStorageOutOfBounds : Array::ArrayStorage;
+        return makeSafe ? Array::ArrayStorageOutOfBounds : (profile->mayStoreToHole() ? Array::ArrayStorageToHole : Array::ArrayStorage);
     case asArrayModes(NonArrayWithSlowPutArrayStorage):
     case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage):
         return Array::SlowPutArrayStorage;
     case asArrayModes(ArrayWithArrayStorage):
-        return makeSafe ? Array::ArrayWithArrayStorageOutOfBounds : Array::ArrayWithArrayStorage;
+        return makeSafe ? Array::ArrayWithArrayStorageOutOfBounds : (profile->mayStoreToHole() ? Array::ArrayWithArrayStorageToHole : Array::ArrayWithArrayStorage);
     case asArrayModes(ArrayWithSlowPutArrayStorage):
     case asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
         return Array::ArrayWithSlowPutArrayStorage;
     case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage):
-        return makeSafe ? Array::PossiblyArrayWithArrayStorageOutOfBounds : Array::PossiblyArrayWithArrayStorage;
+        return makeSafe ? Array::PossiblyArrayWithArrayStorageOutOfBounds : (profile->mayStoreToHole() ? Array::PossiblyArrayWithArrayStorageToHole : Array::PossiblyArrayWithArrayStorage);
     case asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
     case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
         return Array::PossiblyArrayWithSlowPutArrayStorage;
@@ -139,8 +139,10 @@
         return isStringSpeculation(value.m_type);
         
     case Array::ArrayStorage:
+    case Array::ArrayStorageToHole:
     case Array::ArrayStorageOutOfBounds:
     case Array::PossiblyArrayWithArrayStorage:
+    case Array::PossiblyArrayWithArrayStorageToHole:
     case Array::PossiblyArrayWithArrayStorageOutOfBounds:
         return value.m_currentKnownStructure.hasSingleton()
             && (value.m_currentKnownStructure.singleton()->indexingType() & HasArrayStorage);
@@ -151,6 +153,7 @@
             && (value.m_currentKnownStructure.singleton()->indexingType() & (HasArrayStorage | HasSlowPutArrayStorage));
         
     case Array::ArrayWithArrayStorage:
+    case Array::ArrayWithArrayStorageToHole:
     case Array::ArrayWithArrayStorageOutOfBounds:
         return value.m_currentKnownStructure.hasSingleton()
             && (value.m_currentKnownStructure.singleton()->indexingType() & HasArrayStorage)
@@ -215,18 +218,24 @@
         return "String";
     case Array::ArrayStorage:
         return "ArrayStorage";
+    case Array::ArrayStorageToHole:
+        return "ArrayStorageToHole";
     case Array::SlowPutArrayStorage:
         return "SlowPutArrayStorage";
     case Array::ArrayStorageOutOfBounds:
         return "ArrayStorageOutOfBounds";
     case Array::ArrayWithArrayStorage:
         return "ArrayWithArrayStorage";
+    case Array::ArrayWithArrayStorageToHole:
+        return "ArrayWithArrayStorageToHole";
     case Array::ArrayWithSlowPutArrayStorage:
         return "ArrayWithSlowPutArrayStorage";
     case Array::ArrayWithArrayStorageOutOfBounds:
         return "ArrayWithArrayStorageOutOfBounds";
     case Array::PossiblyArrayWithArrayStorage:
         return "PossiblyArrayWithArrayStorage";
+    case Array::PossiblyArrayWithArrayStorageToHole:
+        return "PossiblyArrayWithArrayStorageToHole";
     case Array::PossiblyArrayWithSlowPutArrayStorage:
         return "PossiblyArrayWithSlowPutArrayStorage";
     case Array::PossiblyArrayWithArrayStorageOutOfBounds:

Modified: trunk/Source/_javascript_Core/dfg/DFGArrayMode.h (129044 => 129045)


--- trunk/Source/_javascript_Core/dfg/DFGArrayMode.h	2012-09-19 21:35:01 UTC (rev 129044)
+++ trunk/Source/_javascript_Core/dfg/DFGArrayMode.h	2012-09-19 21:43:10 UTC (rev 129045)
@@ -54,12 +54,15 @@
     
     // Modes of conventional indexed storage where the check is non side-effecting.
     ArrayStorage,
+    ArrayStorageToHole,
     SlowPutArrayStorage,
     ArrayStorageOutOfBounds,
     ArrayWithArrayStorage,
+    ArrayWithArrayStorageToHole,
     ArrayWithSlowPutArrayStorage,
     ArrayWithArrayStorageOutOfBounds,
     PossiblyArrayWithArrayStorage,
+    PossiblyArrayWithArrayStorageToHole,
     PossiblyArrayWithSlowPutArrayStorage,
     PossiblyArrayWithArrayStorageOutOfBounds,
     
@@ -87,20 +90,28 @@
 // First: helpers for non-side-effecting checks.
 #define NON_ARRAY_ARRAY_STORAGE_MODES                      \
     Array::ArrayStorage:                                   \
+    case Array::ArrayStorageToHole:                        \
     case Array::SlowPutArrayStorage:                       \
     case Array::ArrayStorageOutOfBounds:                   \
     case Array::PossiblyArrayWithArrayStorage:             \
+    case Array::PossiblyArrayWithArrayStorageToHole:       \
     case Array::PossiblyArrayWithSlowPutArrayStorage:      \
     case Array::PossiblyArrayWithArrayStorageOutOfBounds
 #define ARRAY_WITH_ARRAY_STORAGE_MODES                     \
     Array::ArrayWithArrayStorage:                          \
+    case Array::ArrayWithArrayStorageToHole:               \
     case Array::ArrayWithSlowPutArrayStorage:              \
     case Array::ArrayWithArrayStorageOutOfBounds
 #define ALL_ARRAY_STORAGE_MODES                            \
     NON_ARRAY_ARRAY_STORAGE_MODES:                         \
     case ARRAY_WITH_ARRAY_STORAGE_MODES
+#define ARRAY_STORAGE_TO_HOLE_MODES                        \
+    Array::ArrayStorageToHole:                             \
+    case Array::ArrayWithArrayStorageToHole:               \
+    case Array::PossiblyArrayWithArrayStorageToHole
 #define IN_BOUNDS_ARRAY_STORAGE_MODES                      \
-    Array::ArrayStorage:                                   \
+    ARRAY_STORAGE_TO_HOLE_MODES:                           \
+    case Array::ArrayStorage:                              \
     case Array::ArrayWithArrayStorage:                     \
     case Array::PossiblyArrayWithArrayStorage
 #define SLOW_PUT_ARRAY_STORAGE_MODES                       \
@@ -172,6 +183,18 @@
     }
 }
 
+inline bool mayStoreToHole(Array::Mode arrayMode)
+{
+    switch (arrayMode) {
+    case ARRAY_STORAGE_TO_HOLE_MODES:
+    case OUT_OF_BOUNDS_ARRAY_STORAGE_MODES:
+    case ALL_EFFECTFUL_ARRAY_STORAGE_MODES:
+        return true;
+    default:
+        return false;
+    }
+}
+
 inline bool canCSEStorage(Array::Mode arrayMode)
 {
     switch (arrayMode) {

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (129044 => 129045)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2012-09-19 21:35:01 UTC (rev 129044)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2012-09-19 21:43:10 UTC (rev 129045)
@@ -2741,32 +2741,41 @@
             if (isInBoundsAccess(node.arrayMode()))
                 speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds);
             
-            base.use();
-            property.use();
-            value.use();
-            storage.use();
-            
             // Check if we're writing to a hole; if so increment m_numValuesInVector.
-            MacroAssembler::Jump notHoleValue = m_jit.branch32(MacroAssembler::NotEqual, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag));
             MacroAssembler::Jump isHoleValue;
-            if (isSlowPutAccess(arrayMode)) {
-                // This is sort of strange. If we wanted to optimize this code path, we would invert
-                // the above branch. But it's simply not worth it since this only happens if we're
-                // already having a bad time.
-                isHoleValue = m_jit.jump();
+            if (!mayStoreToHole(arrayMode)) {
+                // This is uncountable because if we take this exit, then the baseline JIT
+                // will immediately count the hole store. So there is no need for exit
+                // profiling.
+                speculationCheck(
+                    Uncountable, JSValueRegs(), NoNode,
+                    m_jit.branch32(MacroAssembler::Equal, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag)));
             } else {
-                m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
-                
-                // If we're writing to a hole we might be growing the array; 
-                MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset()));
-                m_jit.add32(TrustedImm32(1), propertyReg);
-                m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset()));
-                m_jit.sub32(TrustedImm32(1), propertyReg);
-                
-                lengthDoesNotNeedUpdate.link(&m_jit);
+                MacroAssembler::Jump notHoleValue = m_jit.branch32(MacroAssembler::NotEqual, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag));
+                if (isSlowPutAccess(arrayMode)) {
+                    // This is sort of strange. If we wanted to optimize this code path, we would invert
+                    // the above branch. But it's simply not worth it since this only happens if we're
+                    // already having a bad time.
+                    isHoleValue = m_jit.jump();
+                } else {
+                    m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
+                    
+                    // If we're writing to a hole we might be growing the array; 
+                    MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset()));
+                    m_jit.add32(TrustedImm32(1), propertyReg);
+                    m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset()));
+                    m_jit.sub32(TrustedImm32(1), propertyReg);
+                    
+                    lengthDoesNotNeedUpdate.link(&m_jit);
+                }
+                notHoleValue.link(&m_jit);
             }
-            notHoleValue.link(&m_jit);
 
+            base.use();
+            property.use();
+            value.use();
+            storage.use();
+
             // Store the value to the array.
             m_jit.store32(valueTagReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
             m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (129044 => 129045)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2012-09-19 21:35:01 UTC (rev 129044)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2012-09-19 21:43:10 UTC (rev 129045)
@@ -2760,31 +2760,40 @@
             if (isInBoundsAccess(arrayMode))
                 speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds);
 
-            base.use();
-            property.use();
-            value.use();
-            storage.use();
-        
             // Check if we're writing to a hole; if so increment m_numValuesInVector.
-            MacroAssembler::Jump notHoleValue = m_jit.branchTestPtr(MacroAssembler::NonZero, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
             MacroAssembler::Jump isHoleValue;
-            if (isSlowPutAccess(arrayMode)) {
-                // This is sort of strange. If we wanted to optimize this code path, we would invert
-                // the above branch. But it's simply not worth it since this only happens if we're
-                // already having a bad time.
-                isHoleValue = m_jit.jump();
+            if (!mayStoreToHole(arrayMode)) {
+                // This is uncountable because if we take this exit, then the baseline JIT
+                // will immediately count the hole store. So there is no need for exit
+                // profiling.
+                speculationCheck(
+                    Uncountable, JSValueRegs(), NoNode,
+                    m_jit.branchTestPtr(MacroAssembler::Zero, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))));
             } else {
-                m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
+                MacroAssembler::Jump notHoleValue = m_jit.branchTestPtr(MacroAssembler::NonZero, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
+                if (isSlowPutAccess(arrayMode)) {
+                    // This is sort of strange. If we wanted to optimize this code path, we would invert
+                    // the above branch. But it's simply not worth it since this only happens if we're
+                    // already having a bad time.
+                    isHoleValue = m_jit.jump();
+                } else {
+                    m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
                 
-                // If we're writing to a hole we might be growing the array; 
-                MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset()));
-                m_jit.add32(TrustedImm32(1), propertyReg);
-                m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset()));
-                m_jit.sub32(TrustedImm32(1), propertyReg);
+                    // If we're writing to a hole we might be growing the array; 
+                    MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset()));
+                    m_jit.add32(TrustedImm32(1), propertyReg);
+                    m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset()));
+                    m_jit.sub32(TrustedImm32(1), propertyReg);
                 
-                lengthDoesNotNeedUpdate.link(&m_jit);
+                    lengthDoesNotNeedUpdate.link(&m_jit);
+                }
+                notHoleValue.link(&m_jit);
             }
-            notHoleValue.link(&m_jit);
+            
+            base.use();
+            property.use();
+            value.use();
+            storage.use();
 
             // Store the value to the array.
             m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));

Modified: trunk/Source/_javascript_Core/jit/JIT.h (129044 => 129045)


--- trunk/Source/_javascript_Core/jit/JIT.h	2012-09-19 21:35:01 UTC (rev 129044)
+++ trunk/Source/_javascript_Core/jit/JIT.h	2012-09-19 21:43:10 UTC (rev 129045)
@@ -451,6 +451,7 @@
 #endif
         void emitArrayProfilingSite(RegisterID structureAndIndexingType, RegisterID scratch, ArrayProfile*);
         void emitArrayProfilingSiteForBytecodeIndex(RegisterID structureAndIndexingType, RegisterID scratch, unsigned bytecodeIndex);
+        void emitArrayProfileStoreToHoleSpecialCase(ArrayProfile*);
 
         enum FinalObjectMode { MayBeFinal, KnownNotFinal };
 

Modified: trunk/Source/_javascript_Core/jit/JITInlineMethods.h (129044 => 129045)


--- trunk/Source/_javascript_Core/jit/JITInlineMethods.h	2012-09-19 21:35:01 UTC (rev 129044)
+++ trunk/Source/_javascript_Core/jit/JITInlineMethods.h	2012-09-19 21:43:10 UTC (rev 129045)
@@ -556,6 +556,14 @@
 #endif
 }
 
+inline void JIT::emitArrayProfileStoreToHoleSpecialCase(ArrayProfile* arrayProfile)
+{
+    if (!canBeOptimized())
+        return;
+    
+    store8(TrustedImm32(1), arrayProfile->addressOfMayStoreToHole());
+}
+
 #if USE(JSVALUE32_64)
 
 inline void JIT::emitLoadTag(int index, RegisterID tag)

Modified: trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp (129044 => 129045)


--- trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp	2012-09-19 21:35:01 UTC (rev 129044)
+++ trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp	2012-09-19 21:43:10 UTC (rev 129045)
@@ -247,6 +247,7 @@
     Jump end = jump();
     
     empty.link(this);
+    emitArrayProfileStoreToHoleSpecialCase(currentInstruction[4].u.arrayProfile);
     add32(TrustedImm32(1), Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
     branch32(Below, regT1, Address(regT2, ArrayStorage::lengthOffset())).linkTo(storeResult, this);
 

Modified: trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp (129044 => 129045)


--- trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp	2012-09-19 21:35:01 UTC (rev 129044)
+++ trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp	2012-09-19 21:43:10 UTC (rev 129045)
@@ -283,6 +283,7 @@
     Jump end = jump();
     
     empty.link(this);
+    emitArrayProfileStoreToHoleSpecialCase(currentInstruction[4].u.arrayProfile);
     add32(TrustedImm32(1), Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
     branch32(Below, regT2, Address(regT3, ArrayStorage::lengthOffset())).linkTo(storeResult, this);
     

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm (129044 => 129045)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm	2012-09-19 21:35:01 UTC (rev 129044)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm	2012-09-19 21:43:10 UTC (rev 129045)
@@ -1388,8 +1388,8 @@
     loadi 4[PC], t0
     loadConstantOrVariablePayload(t0, CellTag, t1, .opPutByValSlow)
     loadp JSCell::m_structure[t1], t2
-    loadp 16[PC], t0
-    arrayProfile(t2, t0, t3)
+    loadp 16[PC], t3
+    arrayProfile(t2, t3, t0)
     btiz t2, HasArrayStorage, .opPutByValSlow
     loadi 8[PC], t0
     loadConstantOrVariablePayload(t0, Int32Tag, t2, .opPutByValSlow)
@@ -1405,6 +1405,7 @@
     dispatch(5)
 
 .opPutByValEmpty:
+    storeb 1, ArrayProfile::m_mayStoreToHole[t3]
     addi 1, ArrayStorage::m_numValuesInVector[t0]
     bib t2, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0], .opPutByValStoreResult
     addi 1, t2, t1

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm (129044 => 129045)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm	2012-09-19 21:35:01 UTC (rev 129044)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm	2012-09-19 21:43:10 UTC (rev 129045)
@@ -1231,8 +1231,8 @@
     loadis 8[PB, PC, 8], t0
     loadConstantOrVariableCell(t0, t1, .opPutByValSlow)
     loadp JSCell::m_structure[t1], t2
-    loadp 32[PB, PC, 8], t0
-    arrayProfile(t2, t0, t3)
+    loadp 32[PB, PC, 8], t3
+    arrayProfile(t2, t3, t0)
     btiz t2, HasArrayStorage, .opPutByValSlow
     loadis 16[PB, PC, 8], t0
     loadConstantOrVariableInt32(t0, t2, .opPutByValSlow)
@@ -1248,6 +1248,7 @@
     dispatch(5)
 
 .opPutByValEmpty:
+    storeb 1, ArrayProfile::m_mayStoreToHole[t3]
     addi 1, ArrayStorage::m_numValuesInVector[t0]
     bib t2, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0], .opPutByValStoreResult
     addi 1, t2, t1
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to