Title: [185240] trunk/Source/_javascript_Core
Revision
185240
Author
benja...@webkit.org
Date
2015-06-04 22:20:45 -0700 (Thu, 04 Jun 2015)

Log Message

[JSC] Always track out-of-bounds array access explicitly instead of relying on the slow case
https://bugs.webkit.org/show_bug.cgi?id=145673

Patch by Benjamin Poulain <bpoul...@apple.com> on 2015-06-04
Reviewed by Geoffrey Garen.

Previously, we were deciding to use out-of-bounds speculation based on two informations:
-Explicitly detected out-of-bounds accesses tracked on ArrayProfile.
-The number of time we took the slow cases in the baseline JIT.

The heuristic based on slow cases was a little too fragile.

In some cases, we were running into that limit just because the indexing type changes between
two values (typically Int32Array and DoubleArray). Sometimes we were just unlucky on what
we used for the inline cache.

In Kraken, this was hurting us on "audio-beat-detection" and "audio-fft". The array types we see
change between Int32 and Double. We run into the slow path a bit but never hit
out-of-bounds.

By the time we compile in DFG, we have stable Double Arrays but we speculate out-of-bounds based
on the number of slow cases we took. Because of that, we start boxing the double on GetByVal,
using DoubleRep, etc. adding a ton of overhead over otherwise very simple operations.

WebXPRT was also suffering from this problem but the other way arround: we were missing
the out-of-bounds accesses due to changes in indexing types, we were below the threshold
of slow-path access, thus we predicted in-bounds accesses for code that was doing plenty
of out-of-bands.


This patch fixes the problem by tracking the out-of-bounds access explicitly any time we go
into the slow path in baseline JIT. Since we no longer miss any out-of-bounds, we can remove
the slow-path heuristic.

There is new additional special case in the C code regarding out-of-bounds: Arguments access.
Mispredicting out-of-bounds accesses on arguments is a disaster for performance, so those are
tracked in the way DFG expect it.


There are a few important cases that are still not covered optimally:
-PutByVal on Arguments.
-Get/Put ByVal on TypedArray.
Those are simply not used by DFG in any way. TypedArrays should probably be looked at in the future.

* bytecode/ArrayProfile.cpp:
(JSC::ArrayProfile::computeUpdatedPrediction):
The inline-cache repatch cases now update the ArrayProfile information. This has no value in baseline
JIT but it helps avoiding one recompile in DFG for the missing ArrayProfile information.

* bytecode/ArrayProfile.h:
(JSC::ArrayProfile::setOutOfBounds):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::getArrayMode):
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::getArrayModeConsideringSlowPath): Deleted.
* jit/CCallHelpers.h:
(JSC::CCallHelpers::setupArgumentsWithExecState):
* jit/JIT.h:
* jit/JITInlines.h:
(JSC::JIT::callOperation):
* jit/JITOpcodes.cpp:
(JSC::JIT::emitSlow_op_has_indexed_property):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emitSlow_op_has_indexed_property):
* jit/JITOperations.cpp:
(JSC::canUseFastArgumentAccess):
This is not my favorite part of this patch.

I tried having JSObject::canGetIndexQuickly() handle arguments which would put everything
on the generic path. Unfortunately, that code is very performance sensitive and some benchmarks were
impacted by over 10%

I left JSObject::canGetIndexQuickly() alone, and I added the canUseFastArgumentAccess() mirroring
how DFG uses out-of-bounds for Arguments.

(JSC::getByVal):
* jit/JITOperations.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emitSlow_op_get_by_val):
(JSC::JIT::emitSlow_op_put_by_val):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emitSlow_op_get_by_val):
(JSC::JIT::emitSlow_op_put_by_val):
* runtime/JSPromiseFunctions.cpp:
* tests/stress/get-by-val-out-of-bounds-basics.js: Added.
(opaqueGetByValOnInt32ArrayEarlyOutOfBounds):
(testInt32ArrayEarlyOutOfBounds):
(testIndexingTypeChangesOnInt32Array):
(opaqueGetByValOnStringArrayHotOutOfBounds):
(testStringArrayHotOutOfBounds):
(testIndexingTypeChangesOnStringArray):
(opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds):
(testStringAndInt32ArrayHotOutOfBounds):
(opaqueGetByValOnDoubleArrayHotOutOfBounds):
* tests/stress/put-by-val-out-of-bounds-basics.js: Added.
(opaquePutByValOnInt32ArrayEarlyOutOfBounds):
(testInt32ArrayEarlyOutOfBounds):
(opaquePutByValOnStringArrayHotOutOfBounds):
(testStringArrayHotOutOfBounds):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (185239 => 185240)


--- trunk/Source/_javascript_Core/ChangeLog	2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-06-05 05:20:45 UTC (rev 185240)
@@ -1,3 +1,104 @@
+2015-06-04  Benjamin Poulain  <bpoul...@apple.com>
+
+        [JSC] Always track out-of-bounds array access explicitly instead of relying on the slow case
+        https://bugs.webkit.org/show_bug.cgi?id=145673
+
+        Reviewed by Geoffrey Garen.
+
+        Previously, we were deciding to use out-of-bounds speculation based on two informations:
+        -Explicitly detected out-of-bounds accesses tracked on ArrayProfile.
+        -The number of time we took the slow cases in the baseline JIT.
+
+        The heuristic based on slow cases was a little too fragile.
+
+        In some cases, we were running into that limit just because the indexing type changes between
+        two values (typically Int32Array and DoubleArray). Sometimes we were just unlucky on what
+        we used for the inline cache.
+
+        In Kraken, this was hurting us on "audio-beat-detection" and "audio-fft". The array types we see
+        change between Int32 and Double. We run into the slow path a bit but never hit
+        out-of-bounds.
+
+        By the time we compile in DFG, we have stable Double Arrays but we speculate out-of-bounds based
+        on the number of slow cases we took. Because of that, we start boxing the double on GetByVal,
+        using DoubleRep, etc. adding a ton of overhead over otherwise very simple operations.
+
+        WebXPRT was also suffering from this problem but the other way arround: we were missing
+        the out-of-bounds accesses due to changes in indexing types, we were below the threshold
+        of slow-path access, thus we predicted in-bounds accesses for code that was doing plenty
+        of out-of-bands.
+
+
+        This patch fixes the problem by tracking the out-of-bounds access explicitly any time we go
+        into the slow path in baseline JIT. Since we no longer miss any out-of-bounds, we can remove
+        the slow-path heuristic.
+
+        There is new additional special case in the C code regarding out-of-bounds: Arguments access.
+        Mispredicting out-of-bounds accesses on arguments is a disaster for performance, so those are
+        tracked in the way DFG expect it.
+
+
+        There are a few important cases that are still not covered optimally:
+        -PutByVal on Arguments.
+        -Get/Put ByVal on TypedArray.
+        Those are simply not used by DFG in any way. TypedArrays should probably be looked at in the future.
+
+        * bytecode/ArrayProfile.cpp:
+        (JSC::ArrayProfile::computeUpdatedPrediction):
+        The inline-cache repatch cases now update the ArrayProfile information. This has no value in baseline
+        JIT but it helps avoiding one recompile in DFG for the missing ArrayProfile information.
+
+        * bytecode/ArrayProfile.h:
+        (JSC::ArrayProfile::setOutOfBounds):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::getArrayMode):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        (JSC::DFG::ByteCodeParser::getArrayModeConsideringSlowPath): Deleted.
+        * jit/CCallHelpers.h:
+        (JSC::CCallHelpers::setupArgumentsWithExecState):
+        * jit/JIT.h:
+        * jit/JITInlines.h:
+        (JSC::JIT::callOperation):
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emitSlow_op_has_indexed_property):
+        * jit/JITOpcodes32_64.cpp:
+        (JSC::JIT::emitSlow_op_has_indexed_property):
+        * jit/JITOperations.cpp:
+        (JSC::canUseFastArgumentAccess):
+        This is not my favorite part of this patch.
+
+        I tried having JSObject::canGetIndexQuickly() handle arguments which would put everything
+        on the generic path. Unfortunately, that code is very performance sensitive and some benchmarks were
+        impacted by over 10%
+
+        I left JSObject::canGetIndexQuickly() alone, and I added the canUseFastArgumentAccess() mirroring
+        how DFG uses out-of-bounds for Arguments.
+
+        (JSC::getByVal):
+        * jit/JITOperations.h:
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emitSlow_op_get_by_val):
+        (JSC::JIT::emitSlow_op_put_by_val):
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::emitSlow_op_get_by_val):
+        (JSC::JIT::emitSlow_op_put_by_val):
+        * runtime/JSPromiseFunctions.cpp:
+        * tests/stress/get-by-val-out-of-bounds-basics.js: Added.
+        (opaqueGetByValOnInt32ArrayEarlyOutOfBounds):
+        (testInt32ArrayEarlyOutOfBounds):
+        (testIndexingTypeChangesOnInt32Array):
+        (opaqueGetByValOnStringArrayHotOutOfBounds):
+        (testStringArrayHotOutOfBounds):
+        (testIndexingTypeChangesOnStringArray):
+        (opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds):
+        (testStringAndInt32ArrayHotOutOfBounds):
+        (opaqueGetByValOnDoubleArrayHotOutOfBounds):
+        * tests/stress/put-by-val-out-of-bounds-basics.js: Added.
+        (opaquePutByValOnInt32ArrayEarlyOutOfBounds):
+        (testInt32ArrayEarlyOutOfBounds):
+        (opaquePutByValOnStringArrayHotOutOfBounds):
+        (testStringArrayHotOutOfBounds):
+
 2015-06-03  Filip Pizlo  <fpi...@apple.com>
 
         Simplify unboxing of double JSValues known to be not NaN and not Int32

Modified: trunk/Source/_javascript_Core/bytecode/ArrayProfile.cpp (185239 => 185240)


--- trunk/Source/_javascript_Core/bytecode/ArrayProfile.cpp	2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/_javascript_Core/bytecode/ArrayProfile.cpp	2015-06-05 05:20:45 UTC (rev 185240)
@@ -94,12 +94,18 @@
         out.print(comma, "Float64ArrayMode");
 }
 
-void ArrayProfile::computeUpdatedPrediction(const ConcurrentJITLocker&, CodeBlock* codeBlock)
+void ArrayProfile::computeUpdatedPrediction(const ConcurrentJITLocker& locker, CodeBlock* codeBlock)
 {
     if (!m_lastSeenStructureID)
         return;
     
     Structure* lastSeenStructure = codeBlock->heap()->structureIDTable().get(m_lastSeenStructureID);
+    computeUpdatedPrediction(locker, codeBlock, lastSeenStructure);
+    m_lastSeenStructureID = 0;
+}
+
+void ArrayProfile::computeUpdatedPrediction(const ConcurrentJITLocker&, CodeBlock* codeBlock, Structure* lastSeenStructure)
+{
     m_observedArrayModes |= arrayModeFromStructure(lastSeenStructure);
     
     if (!m_didPerformFirstRunPruning
@@ -114,7 +120,6 @@
     if (!globalObject->isOriginalArrayStructure(lastSeenStructure)
         && !globalObject->isOriginalTypedArrayStructure(lastSeenStructure))
         m_usesOriginalArrayStructures = false;
-    m_lastSeenStructureID = 0;
 }
 
 CString ArrayProfile::briefDescription(const ConcurrentJITLocker& locker, CodeBlock* codeBlock)

Modified: trunk/Source/_javascript_Core/bytecode/ArrayProfile.h (185239 => 185240)


--- trunk/Source/_javascript_Core/bytecode/ArrayProfile.h	2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/_javascript_Core/bytecode/ArrayProfile.h	2015-06-05 05:20:45 UTC (rev 185240)
@@ -209,6 +209,8 @@
     StructureID* addressOfLastSeenStructureID() { return &m_lastSeenStructureID; }
     ArrayModes* addressOfArrayModes() { return &m_observedArrayModes; }
     bool* addressOfMayStoreToHole() { return &m_mayStoreToHole; }
+
+    void setOutOfBounds() { m_outOfBounds = true; }
     bool* addressOfOutOfBounds() { return &m_outOfBounds; }
     
     void observeStructure(Structure* structure)
@@ -217,6 +219,7 @@
     }
     
     void computeUpdatedPrediction(const ConcurrentJITLocker&, CodeBlock*);
+    void computeUpdatedPrediction(const ConcurrentJITLocker&, CodeBlock*, Structure* lastSeenStructure);
     
     ArrayModes observedArrayModes(const ConcurrentJITLocker&) const { return m_observedArrayModes; }
     bool mayInterceptIndexedAccesses(const ConcurrentJITLocker&) const { return m_mayInterceptIndexedAccesses; }

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (185239 => 185240)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2015-06-05 05:20:45 UTC (rev 185240)
@@ -745,7 +745,8 @@
     {
         ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
         profile->computeUpdatedPrediction(locker, m_inlineStackTop->m_profiledBlock);
-        return ArrayMode::fromObserved(locker, profile, action, false);
+        bool makeSafe = profile->outOfBounds(locker);
+        return ArrayMode::fromObserved(locker, profile, action, makeSafe);
     }
     
     ArrayMode getArrayMode(ArrayProfile* profile)
@@ -753,21 +754,6 @@
         return getArrayMode(profile, Array::Read);
     }
     
-    ArrayMode getArrayModeConsideringSlowPath(ArrayProfile* profile, Array::Action action)
-    {
-        ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
-        
-        profile->computeUpdatedPrediction(locker, m_inlineStackTop->m_profiledBlock);
-        
-        bool makeSafe =
-            m_inlineStackTop->m_profiledBlock->likelyToTakeSlowCase(m_currentIndex)
-            || profile->outOfBounds(locker);
-        
-        ArrayMode result = ArrayMode::fromObserved(locker, profile, action, makeSafe);
-        
-        return result;
-    }
-    
     Node* makeSafe(Node* node)
     {
         if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow))
@@ -3099,7 +3085,7 @@
             SpeculatedType prediction = getPredictionWithoutOSRExit();
             
             Node* base = get(VirtualRegister(currentInstruction[2].u.operand));
-            ArrayMode arrayMode = getArrayModeConsideringSlowPath(currentInstruction[4].u.arrayProfile, Array::Read);
+            ArrayMode arrayMode = getArrayMode(currentInstruction[4].u.arrayProfile, Array::Read);
             Node* property = get(VirtualRegister(currentInstruction[3].u.operand));
             Node* getByVal = addToGraph(GetByVal, OpInfo(arrayMode.asWord()), OpInfo(prediction), base, property);
             set(VirtualRegister(currentInstruction[1].u.operand), getByVal);
@@ -3111,7 +3097,7 @@
         case op_put_by_val: {
             Node* base = get(VirtualRegister(currentInstruction[1].u.operand));
 
-            ArrayMode arrayMode = getArrayModeConsideringSlowPath(currentInstruction[4].u.arrayProfile, Array::Write);
+            ArrayMode arrayMode = getArrayMode(currentInstruction[4].u.arrayProfile, Array::Write);
             
             Node* property = get(VirtualRegister(currentInstruction[2].u.operand));
             Node* value = get(VirtualRegister(currentInstruction[3].u.operand));
@@ -3864,7 +3850,7 @@
 
         case op_has_indexed_property: {
             Node* base = get(VirtualRegister(currentInstruction[2].u.operand));
-            ArrayMode arrayMode = getArrayModeConsideringSlowPath(currentInstruction[4].u.arrayProfile, Array::Read);
+            ArrayMode arrayMode = getArrayMode(currentInstruction[4].u.arrayProfile, Array::Read);
             Node* property = get(VirtualRegister(currentInstruction[3].u.operand));
             Node* hasIterableProperty = addToGraph(HasIndexedProperty, OpInfo(arrayMode.asWord()), base, property);
             set(VirtualRegister(currentInstruction[1].u.operand), hasIterableProperty);

Modified: trunk/Source/_javascript_Core/jit/CCallHelpers.h (185239 => 185240)


--- trunk/Source/_javascript_Core/jit/CCallHelpers.h	2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/_javascript_Core/jit/CCallHelpers.h	2015-06-05 05:20:45 UTC (rev 185240)
@@ -734,6 +734,19 @@
         addCallArgument(arg6);
     }
 
+    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5, GPRReg arg6, TrustedImmPtr arg7)
+    {
+        resetCallArguments();
+        addCallArgument(GPRInfo::callFrameRegister);
+        addCallArgument(arg1);
+        addCallArgument(arg2);
+        addCallArgument(arg3);
+        addCallArgument(arg4);
+        addCallArgument(arg5);
+        addCallArgument(arg6);
+        addCallArgument(arg7);
+    }
+
     ALWAYS_INLINE void setupArgumentsWithExecState(FPRReg arg1, GPRReg arg2)
     {
         resetCallArguments();
@@ -1466,6 +1479,13 @@
         setupArgumentsWithExecState(arg1, arg2, arg3);
     }
 
+    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, TrustedImmPtr arg5)
+    {
+        poke(arg5, POKE_ARGUMENT_OFFSET + 1);
+        poke(arg4, POKE_ARGUMENT_OFFSET);
+        setupArgumentsWithExecState(arg1, arg2, arg3);
+    }
+
     ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2, GPRReg arg3,  GPRReg arg4)
     {
         poke(arg4, POKE_ARGUMENT_OFFSET);
@@ -1726,6 +1746,15 @@
         setupArgumentsWithExecState(arg1, arg2, arg3);
     }
 
+    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5, GPRReg arg6, TrustedImmPtr arg7)
+    {
+        poke(arg7, POKE_ARGUMENT_OFFSET + 3);
+        poke(arg6, POKE_ARGUMENT_OFFSET + 2);
+        poke(arg5, POKE_ARGUMENT_OFFSET + 1);
+        poke(arg4, POKE_ARGUMENT_OFFSET);
+        setupArgumentsWithExecState(arg1, arg2, arg3);
+    }
+
     ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImmPtr arg3, GPRReg arg4, GPRReg arg5)
     {
         poke(arg5, POKE_ARGUMENT_OFFSET + 1);
@@ -1830,6 +1859,13 @@
         setupThreeStubArgsGPR<GPRInfo::argumentGPR1, GPRInfo::argumentGPR3, GPRInfo::argumentGPR4>(arg1, arg3, arg4);
     }
 
+    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, TrustedImmPtr arg4)
+    {
+        setupThreeStubArgsGPR<GPRInfo::argumentGPR1, GPRInfo::argumentGPR2, GPRInfo::argumentGPR3>(arg1, arg2, arg3);
+        move(arg4, GPRInfo::argumentGPR4);
+        move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+    }
+
     ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2, TrustedImm32 arg3, GPRReg arg4)
     {
         setupTwoStubArgsGPR<GPRInfo::argumentGPR1, GPRInfo::argumentGPR4>(arg1, arg4);

Modified: trunk/Source/_javascript_Core/jit/JIT.h (185239 => 185240)


--- trunk/Source/_javascript_Core/jit/JIT.h	2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/_javascript_Core/jit/JIT.h	2015-06-05 05:20:45 UTC (rev 185240)
@@ -702,6 +702,7 @@
 #endif
         MacroAssembler::Call callOperation(J_JITOperation_EJIdc, int, GPRReg, const Identifier*);
         MacroAssembler::Call callOperation(J_JITOperation_EJJ, int, GPRReg, GPRReg);
+        MacroAssembler::Call callOperation(J_JITOperation_EJJAp, int, GPRReg, GPRReg, ArrayProfile*);
         MacroAssembler::Call callOperation(C_JITOperation_EJsc, GPRReg);
         MacroAssembler::Call callOperation(J_JITOperation_EJscC, int, GPRReg, JSCell*);
         MacroAssembler::Call callOperation(C_JITOperation_EJscZ, GPRReg, int32_t);
@@ -743,6 +744,7 @@
         MacroAssembler::Call callOperation(V_JITOperation_ESsiJJI, StructureStubInfo*, RegisterID, RegisterID, RegisterID, RegisterID, UniquedStringImpl*);
 #endif
         MacroAssembler::Call callOperation(V_JITOperation_EJJJ, RegisterID, RegisterID, RegisterID);
+        MacroAssembler::Call callOperation(V_JITOperation_EJJJAp, RegisterID, RegisterID, RegisterID, ArrayProfile*);
         MacroAssembler::Call callOperation(V_JITOperation_EJZJ, RegisterID, int32_t, RegisterID);
         MacroAssembler::Call callOperation(V_JITOperation_EJZ, RegisterID, int32_t);
         MacroAssembler::Call callOperation(V_JITOperation_EPc, Instruction*);
@@ -758,12 +760,14 @@
         MacroAssembler::Call callOperation(J_JITOperation_EJ, int, GPRReg, GPRReg);
         MacroAssembler::Call callOperation(J_JITOperation_EJIdc, int, GPRReg, GPRReg, const Identifier*);
         MacroAssembler::Call callOperation(J_JITOperation_EJJ, int, GPRReg, GPRReg, GPRReg, GPRReg);
+        MacroAssembler::Call callOperation(J_JITOperation_EJJAp, int, GPRReg, GPRReg, GPRReg, GPRReg, ArrayProfile*);
         MacroAssembler::Call callOperation(P_JITOperation_EJS, GPRReg, GPRReg, size_t);
         MacroAssembler::Call callOperation(S_JITOperation_EJ, RegisterID, RegisterID);
         MacroAssembler::Call callOperation(S_JITOperation_EJJ, RegisterID, RegisterID, RegisterID, RegisterID);
         MacroAssembler::Call callOperation(V_JITOperation_EZSymtabJ, int, SymbolTable*, RegisterID, RegisterID);
         MacroAssembler::Call callOperation(V_JITOperation_EJ, RegisterID, RegisterID);
         MacroAssembler::Call callOperation(V_JITOperation_EJJJ, RegisterID, RegisterID, RegisterID, RegisterID, RegisterID, RegisterID);
+        MacroAssembler::Call callOperation(V_JITOperation_EJJJAp, RegisterID, RegisterID, RegisterID, RegisterID, RegisterID, RegisterID, ArrayProfile*);
         MacroAssembler::Call callOperation(V_JITOperation_EJZ, RegisterID, RegisterID, int32_t);
         MacroAssembler::Call callOperation(V_JITOperation_EJZJ, RegisterID, RegisterID, int32_t, RegisterID, RegisterID);
         MacroAssembler::Call callOperation(V_JITOperation_EZJ, int32_t, RegisterID, RegisterID);

Modified: trunk/Source/_javascript_Core/jit/JITInlines.h (185239 => 185240)


--- trunk/Source/_javascript_Core/jit/JITInlines.h	2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/_javascript_Core/jit/JITInlines.h	2015-06-05 05:20:45 UTC (rev 185240)
@@ -399,6 +399,12 @@
     return appendCallWithExceptionCheck(operation);
 }
 
+ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_EJJJAp operation, RegisterID regOp1, RegisterID regOp2, RegisterID regOp3, ArrayProfile* arrayProfile)
+{
+    setupArgumentsWithExecState(regOp1, regOp2, regOp3, TrustedImmPtr(arrayProfile));
+    return appendCallWithExceptionCheck(operation);
+}
+
 ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_EZJ operation, int dst, GPRReg arg)
 {
     setupArgumentsWithExecState(TrustedImm32(dst), arg);
@@ -441,6 +447,12 @@
     return appendCallWithExceptionCheckSetJSValueResult(operation, dst);
 }
 
+ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(J_JITOperation_EJJAp operation, int dst, GPRReg arg1, GPRReg arg2, ArrayProfile* arrayProfile)
+{
+    setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(arrayProfile));
+    return appendCallWithExceptionCheckSetJSValueResult(operation, dst);
+}
+
 ALWAYS_INLINE MacroAssembler::Call JIT::callOperationNoExceptionCheck(V_JITOperation_EJ operation, GPRReg arg1)
 {
     setupArgumentsWithExecState(arg1);
@@ -570,6 +582,12 @@
     return appendCallWithExceptionCheckSetJSValueResult(operation, dst);
 }
 
+ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(J_JITOperation_EJJAp operation, int dst, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload, ArrayProfile* arrayProfile)
+{
+    setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, SH4_32BIT_DUMMY_ARG arg2Payload, arg2Tag, TrustedImmPtr(arrayProfile));
+    return appendCallWithExceptionCheckSetJSValueResult(operation, dst);
+}
+
 ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(JIT::WithProfileTag, J_JITOperation_EJJ operation, int dst, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload)
 {
     setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, SH4_32BIT_DUMMY_ARG arg2Payload, arg2Tag);
@@ -630,6 +648,12 @@
     return appendCallWithExceptionCheck(operation);
 }
 
+ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_EJJJAp operation, RegisterID regOp1Tag, RegisterID regOp1Payload, RegisterID regOp2Tag, RegisterID regOp2Payload, RegisterID regOp3Tag, RegisterID regOp3Payload, ArrayProfile* arrayProfile)
+{
+    setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG regOp1Payload, regOp1Tag, SH4_32BIT_DUMMY_ARG regOp2Payload, regOp2Tag, regOp3Payload, regOp3Tag, TrustedImmPtr(arrayProfile));
+    return appendCallWithExceptionCheck(operation);
+}
+
 ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_EZJ operation, int dst, RegisterID regOp1Tag, RegisterID regOp1Payload)
 {
     setupArgumentsWithExecState(TrustedImm32(dst), regOp1Payload, regOp1Tag);

Modified: trunk/Source/_javascript_Core/jit/JITOpcodes.cpp (185239 => 185240)


--- trunk/Source/_javascript_Core/jit/JITOpcodes.cpp	2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/_javascript_Core/jit/JITOpcodes.cpp	2015-06-05 05:20:45 UTC (rev 185240)
@@ -1125,21 +1125,14 @@
     
     linkSlowCaseIfNotJSCell(iter, base); // base cell check
     linkSlowCase(iter); // base array check
-    
-    Jump skipProfiling = jump();
-    
     linkSlowCase(iter); // vector length check
     linkSlowCase(iter); // empty value
     
-    emitArrayProfileOutOfBoundsSpecialCase(profile);
-    
-    skipProfiling.link(this);
-    
     Label slowPath = label();
     
     emitGetVirtualRegister(base, regT0);
     emitGetVirtualRegister(property, regT1);
-    Call call = callOperation(operationHasIndexedPropertyDefault, dst, regT0, regT1);
+    Call call = callOperation(operationHasIndexedPropertyDefault, dst, regT0, regT1, profile);
 
     m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
     m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call;

Modified: trunk/Source/_javascript_Core/jit/JITOpcodes32_64.cpp (185239 => 185240)


--- trunk/Source/_javascript_Core/jit/JITOpcodes32_64.cpp	2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/_javascript_Core/jit/JITOpcodes32_64.cpp	2015-06-05 05:20:45 UTC (rev 185240)
@@ -1122,21 +1122,14 @@
     
     linkSlowCaseIfNotJSCell(iter, base); // base cell check
     linkSlowCase(iter); // base array check
-    
-    Jump skipProfiling = jump();
-    
     linkSlowCase(iter); // vector length check
     linkSlowCase(iter); // empty value
-    
-    emitArrayProfileOutOfBoundsSpecialCase(profile);
-    
-    skipProfiling.link(this);
-    
+
     Label slowPath = label();
     
     emitLoad(base, regT1, regT0);
     emitLoad(property, regT3, regT2);
-    Call call = callOperation(operationHasIndexedPropertyDefault, dst, regT1, regT0, regT3, regT2);
+    Call call = callOperation(operationHasIndexedPropertyDefault, dst, regT1, regT0, regT3, regT2, profile);
 
     m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
     m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call;

Modified: trunk/Source/_javascript_Core/jit/JITOperations.cpp (185239 => 185240)


--- trunk/Source/_javascript_Core/jit/JITOperations.cpp	2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/_javascript_Core/jit/JITOperations.cpp	2015-06-05 05:20:45 UTC (rev 185240)
@@ -35,6 +35,7 @@
 #include "DFGThunks.h"
 #include "DFGWorklist.h"
 #include "Debugger.h"
+#include "DirectArguments.h"
 #include "Error.h"
 #include "ErrorHandlingScope.h"
 #include "ExceptionFuzz.h"
@@ -56,6 +57,7 @@
 #include "PropertyName.h"
 #include "Repatch.h"
 #include "RepatchBuffer.h"
+#include "ScopedArguments.h"
 #include "TestRunnerUtils.h"
 #include "TypeProfilerLog.h"
 #include <wtf/InlineASM.h>
@@ -497,7 +499,7 @@
     base->putDirect(vm, offset, JSValue::decode(value));
 }
 
-static void putByVal(CallFrame* callFrame, JSValue baseValue, JSValue subscript, JSValue value)
+static void putByVal(CallFrame* callFrame, JSValue baseValue, JSValue subscript, JSValue value, ArrayProfile* arrayProfile)
 {
     VM& vm = callFrame->vm();
     if (LIKELY(subscript.isUInt32())) {
@@ -506,8 +508,10 @@
             JSObject* object = asObject(baseValue);
             if (object->canSetIndexQuickly(i))
                 object->setIndexQuickly(callFrame->vm(), i, value);
-            else
+            else {
+                arrayProfile->setOutOfBounds();
                 object->methodTable(vm)->putByIndex(object, callFrame, i, value, callFrame->codeBlock()->isStrictMode());
+            }
         } else
             baseValue.putByIndex(callFrame, i, value, callFrame->codeBlock()->isStrictMode());
     } else {
@@ -519,13 +523,20 @@
     }
 }
 
-static void directPutByVal(CallFrame* callFrame, JSObject* baseObject, JSValue subscript, JSValue value)
+static void directPutByVal(CallFrame* callFrame, JSObject* baseObject, JSValue subscript, JSValue value, ArrayProfile* arrayProfile)
 {
     bool isStrictMode = callFrame->codeBlock()->isStrictMode();
     if (LIKELY(subscript.isUInt32())) {
         // Despite its name, JSValue::isUInt32 will return true only for positive boxed int32_t; all those values are valid array indices.
-        ASSERT(isIndex(subscript.asUInt32()));
-        baseObject->putDirectIndex(callFrame, subscript.asUInt32(), value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
+        uint32_t index = subscript.asUInt32();
+        ASSERT(isIndex(index));
+        if (baseObject->canSetIndexQuicklyForPutDirect(index)) {
+            baseObject->setIndexQuickly(callFrame->vm(), index, value);
+            return;
+        }
+
+        arrayProfile->setOutOfBounds();
+        baseObject->putDirectIndex(callFrame, index, value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
         return;
     }
 
@@ -550,7 +561,7 @@
         baseObject->putDirect(callFrame->vm(), property, value, slot);
     }
 }
-void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue)
+void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
@@ -569,10 +580,15 @@
         ByValInfo& byValInfo = exec->codeBlock()->getByValInfo(bytecodeOffset - 1);
         ASSERT(!byValInfo.stubRoutine);
 
-        if (hasOptimizableIndexing(object->structure(vm))) {
+        Structure* structure = object->structure(vm);
+        if (hasOptimizableIndexing(structure)) {
             // Attempt to optimize.
-            JITArrayMode arrayMode = jitArrayModeForStructure(object->structure(vm));
+            JITArrayMode arrayMode = jitArrayModeForStructure(structure);
             if (jitArrayModePermitsPut(arrayMode) && arrayMode != byValInfo.arrayMode) {
+                CodeBlock* codeBlock = exec->codeBlock();
+                ConcurrentJITLocker locker(codeBlock->m_lock);
+                arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure);
+
                 JIT::compilePutByVal(&vm, exec->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode);
                 didOptimize = true;
             }
@@ -592,10 +608,10 @@
         }
     }
 
-    putByVal(exec, baseValue, subscript, value);
+    putByVal(exec, baseValue, subscript, value, arrayProfile);
 }
 
-void JIT_OPERATION operationDirectPutByVal(ExecState* callFrame, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue)
+void JIT_OPERATION operationDirectPutByVal(ExecState* callFrame, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile)
 {
     VM& vm = callFrame->vm();
     NativeCallFrameTracer tracer(&vm, callFrame);
@@ -613,11 +629,16 @@
         ASSERT(bytecodeOffset);
         ByValInfo& byValInfo = callFrame->codeBlock()->getByValInfo(bytecodeOffset - 1);
         ASSERT(!byValInfo.stubRoutine);
-        
-        if (hasOptimizableIndexing(object->structure(vm))) {
+
+        Structure* structure = object->structure(vm);
+        if (hasOptimizableIndexing(structure)) {
             // Attempt to optimize.
-            JITArrayMode arrayMode = jitArrayModeForStructure(object->structure(vm));
+            JITArrayMode arrayMode = jitArrayModeForStructure(structure);
             if (jitArrayModePermitsPut(arrayMode) && arrayMode != byValInfo.arrayMode) {
+                CodeBlock* codeBlock = callFrame->codeBlock();
+                ConcurrentJITLocker locker(codeBlock->m_lock);
+                arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure);
+
                 JIT::compileDirectPutByVal(&vm, callFrame->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode);
                 didOptimize = true;
             }
@@ -636,10 +657,10 @@
             }
         }
     }
-    directPutByVal(callFrame, object, subscript, value);
+    directPutByVal(callFrame, object, subscript, value, arrayProfile);
 }
 
-void JIT_OPERATION operationPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue)
+void JIT_OPERATION operationPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
@@ -648,11 +669,11 @@
     JSValue subscript = JSValue::decode(encodedSubscript);
     JSValue value = JSValue::decode(encodedValue);
 
-    putByVal(exec, baseValue, subscript, value);
+    putByVal(exec, baseValue, subscript, value, arrayProfile);
 }
 
 
-void JIT_OPERATION operationDirectPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue)
+void JIT_OPERATION operationDirectPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
@@ -661,7 +682,7 @@
     JSValue subscript = JSValue::decode(encodedSubscript);
     JSValue value = JSValue::decode(encodedValue);
     RELEASE_ASSERT(baseValue.isObject());
-    directPutByVal(exec, asObject(baseValue), subscript, value);
+    directPutByVal(exec, asObject(baseValue), subscript, value, arrayProfile);
 }
 
 EncodedJSValue JIT_OPERATION operationCallEval(ExecState* exec, ExecState* execCallee)
@@ -1480,8 +1501,29 @@
 
 }
 
-static JSValue getByVal(ExecState* exec, JSValue baseValue, JSValue subscript, ReturnAddressPtr returnAddress)
+static bool canAccessArgumentIndexQuickly(JSObject& object, uint32_t index)
 {
+    switch (object.structure()->typeInfo().type()) {
+    case DirectArgumentsType: {
+        DirectArguments* directArguments = jsCast<DirectArguments*>(&object);
+        if (directArguments->canAccessArgumentIndexQuicklyInDFG(index))
+            return true;
+        break;
+    }
+    case ScopedArgumentsType: {
+        ScopedArguments* scopedArguments = jsCast<ScopedArguments*>(&object);
+        if (scopedArguments->canAccessArgumentIndexQuicklyInDFG(index))
+            return true;
+        break;
+    }
+    default:
+        break;
+    }
+    return false;
+}
+
+static JSValue getByVal(ExecState* exec, JSValue baseValue, JSValue subscript, ArrayProfile* arrayProfile, ReturnAddressPtr returnAddress)
+{
     if (LIKELY(baseValue.isCell() && subscript.isString())) {
         VM& vm = exec->vm();
         Structure& structure = *baseValue.asCell()->structure(vm);
@@ -1495,10 +1537,21 @@
 
     if (subscript.isUInt32()) {
         uint32_t i = subscript.asUInt32();
-        if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i)) {
-            ctiPatchCallByReturnAddress(exec->codeBlock(), returnAddress, FunctionPtr(operationGetByValString));
-            return asString(baseValue)->getIndex(exec, i);
+        if (isJSString(baseValue)) {
+            if (asString(baseValue)->canGetIndex(i)) {
+                ctiPatchCallByReturnAddress(exec->codeBlock(), returnAddress, FunctionPtr(operationGetByValString));
+                return asString(baseValue)->getIndex(exec, i);
+            }
+            arrayProfile->setOutOfBounds();
+        } else if (baseValue.isObject()) {
+            JSObject* object = asObject(baseValue);
+            if (object->canGetIndexQuickly(i))
+                return object->getIndexQuickly(i);
+
+            if (!canAccessArgumentIndexQuickly(*object, i))
+                arrayProfile->setOutOfBounds();
         }
+
         return baseValue.get(exec, i);
     }
 
@@ -1513,18 +1566,18 @@
 
 extern "C" {
     
-EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript)
+EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
     JSValue baseValue = JSValue::decode(encodedBase);
     JSValue subscript = JSValue::decode(encodedSubscript);
 
-    JSValue result = getByVal(exec, baseValue, subscript, ReturnAddressPtr(OUR_RETURN_ADDRESS));
+    JSValue result = getByVal(exec, baseValue, subscript, arrayProfile, ReturnAddressPtr(OUR_RETURN_ADDRESS));
     return JSValue::encode(result);
 }
 
-EncodedJSValue JIT_OPERATION operationGetByValDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript)
+EncodedJSValue JIT_OPERATION operationGetByValDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
@@ -1543,8 +1596,15 @@
         
         if (hasOptimizableIndexing(object->structure(vm))) {
             // Attempt to optimize.
-            JITArrayMode arrayMode = jitArrayModeForStructure(object->structure(vm));
+            Structure* structure = object->structure(vm);
+            JITArrayMode arrayMode = jitArrayModeForStructure(structure);
             if (arrayMode != byValInfo.arrayMode) {
+                // If we reached this case, we got an interesting array mode we did not expect when we compiled.
+                // Let's update the profile to do better next time.
+                CodeBlock* codeBlock = exec->codeBlock();
+                ConcurrentJITLocker locker(codeBlock->m_lock);
+                arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure);
+
                 JIT::compileGetByVal(&vm, exec->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode);
                 didOptimize = true;
             }
@@ -1564,11 +1624,11 @@
         }
     }
     
-    JSValue result = getByVal(exec, baseValue, subscript, ReturnAddressPtr(OUR_RETURN_ADDRESS));
+    JSValue result = getByVal(exec, baseValue, subscript, arrayProfile, ReturnAddressPtr(OUR_RETURN_ADDRESS));
     return JSValue::encode(result);
 }
     
-EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript)
+EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
@@ -1607,11 +1667,17 @@
             ctiPatchCallByReturnAddress(exec->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationHasIndexedPropertyGeneric)); 
         }
     }
-    
-    return JSValue::encode(jsBoolean(object->hasProperty(exec, subscript.asUInt32())));
+
+    uint32_t index = subscript.asUInt32();
+    if (object->canGetIndexQuickly(index))
+        return JSValue::encode(JSValue(JSValue::JSTrue));
+
+    if (!canAccessArgumentIndexQuickly(*object, index))
+        arrayProfile->setOutOfBounds();
+    return JSValue::encode(jsBoolean(object->hasProperty(exec, index)));
 }
     
-EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript)
+EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
@@ -1622,6 +1688,12 @@
     ASSERT(subscript.isUInt32());
 
     JSObject* object = asObject(baseValue);
+    uint32_t index = subscript.asUInt32();
+    if (object->canGetIndexQuickly(index))
+        return JSValue::encode(JSValue(JSValue::JSTrue));
+
+    if (!canAccessArgumentIndexQuickly(*object, index))
+        arrayProfile->setOutOfBounds();
     return JSValue::encode(jsBoolean(object->hasProperty(exec, subscript.asUInt32())));
 }
     

Modified: trunk/Source/_javascript_Core/jit/JITOperations.h (185239 => 185240)


--- trunk/Source/_javascript_Core/jit/JITOperations.h	2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/_javascript_Core/jit/JITOperations.h	2015-06-05 05:20:45 UTC (rev 185240)
@@ -57,6 +57,7 @@
     Key:
     A: JSArray*
     Aap: ArrayAllocationProfile*
+    Ap: ArrayProfile*
     C: JSCell*
     Cb: CodeBlock*
     Cli: CallLinkInfo*
@@ -111,6 +112,7 @@
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJI)(ExecState*, EncodedJSValue, UniquedStringImpl*);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJIdc)(ExecState*, EncodedJSValue, const Identifier*);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
+typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJJAp)(ExecState*, EncodedJSValue, EncodedJSValue, ArrayProfile*);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJssZ)(ExecState*, JSString*, int32_t);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJP)(ExecState*, EncodedJSValue, void*);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EP)(ExecState*, void*);
@@ -191,6 +193,7 @@
 typedef void JIT_OPERATION (*V_JITOperation_EJIdJ)(ExecState*, EncodedJSValue, Identifier*, EncodedJSValue);
 typedef void JIT_OPERATION (*V_JITOperation_EJIdJJ)(ExecState*, EncodedJSValue, Identifier*, EncodedJSValue, EncodedJSValue);
 typedef void JIT_OPERATION (*V_JITOperation_EJJJ)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue);
+typedef void JIT_OPERATION (*V_JITOperation_EJJJAp)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*);
 typedef void JIT_OPERATION (*V_JITOperation_EJPP)(ExecState*, EncodedJSValue, void*, void*);
 typedef void JIT_OPERATION (*V_JITOperation_EJZJ)(ExecState*, EncodedJSValue, int32_t, EncodedJSValue);
 typedef void JIT_OPERATION (*V_JITOperation_EJZ)(ExecState*, EncodedJSValue, int32_t);
@@ -255,10 +258,10 @@
 void JIT_OPERATION operationPutByIdDirectStrictBuildList(ExecState*, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl*) WTF_INTERNAL;
 void JIT_OPERATION operationPutByIdDirectNonStrictBuildList(ExecState*, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl*) WTF_INTERNAL;
 void JIT_OPERATION operationReallocateStorageAndFinishPut(ExecState*, JSObject*, Structure*, PropertyOffset, EncodedJSValue) WTF_INTERNAL;
-void JIT_OPERATION operationPutByVal(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
-void JIT_OPERATION operationDirectPutByVal(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
-void JIT_OPERATION operationPutByValGeneric(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
-void JIT_OPERATION operationDirectPutByValGeneric(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
+void JIT_OPERATION operationPutByVal(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*) WTF_INTERNAL;
+void JIT_OPERATION operationDirectPutByVal(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*) WTF_INTERNAL;
+void JIT_OPERATION operationPutByValGeneric(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*) WTF_INTERNAL;
+void JIT_OPERATION operationDirectPutByValGeneric(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationCallEval(ExecState*, ExecState*) WTF_INTERNAL;
 char* JIT_OPERATION operationLinkCall(ExecState*, CallLinkInfo*) WTF_INTERNAL;
 char* JIT_OPERATION operationLinkPolymorphicCall(ExecState*, CallLinkInfo*) WTF_INTERNAL;
@@ -315,11 +318,11 @@
 void JIT_OPERATION operationProfileWillCall(ExecState*, EncodedJSValue) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationCheckHasInstance(ExecState*, EncodedJSValue, EncodedJSValue baseVal) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationCreateActivation(ExecState*, JSScope* currentScope) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationGetByValDefault(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationGetByValDefault(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetByValString(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationDeleteById(ExecState*, EncodedJSValue base, const Identifier*) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationGetPNames(ExecState*, JSObject*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationInstanceOf(ExecState*, EncodedJSValue, EncodedJSValue proto) WTF_INTERNAL;

Modified: trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp (185239 => 185240)


--- trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp	2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp	2015-06-05 05:20:45 UTC (rev 185240)
@@ -217,20 +217,14 @@
     notString.link(this);
     nonCell.link(this);
     
-    Jump skipProfiling = jump();
-    
     linkSlowCase(iter); // vector length check
     linkSlowCase(iter); // empty value
     
-    emitArrayProfileOutOfBoundsSpecialCase(profile);
-    
-    skipProfiling.link(this);
-    
     Label slowPath = label();
     
     emitGetVirtualRegister(base, regT0);
     emitGetVirtualRegister(property, regT1);
-    Call call = callOperation(operationGetByValDefault, dst, regT0, regT1);
+    Call call = callOperation(operationGetByValDefault, dst, regT0, regT1, profile);
 
     m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
     m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call;
@@ -430,7 +424,7 @@
     emitGetVirtualRegister(property, regT1);
     emitGetVirtualRegister(value, regT2);
     bool isDirect = m_interpreter->getOpcodeID(currentInstruction->u.opcode) == op_put_by_val_direct;
-    Call call = callOperation(isDirect ? operationDirectPutByVal : operationPutByVal, regT0, regT1, regT2);
+    Call call = callOperation(isDirect ? operationDirectPutByVal : operationPutByVal, regT0, regT1, regT2, profile);
 
     m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
     m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call;

Modified: trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp (185239 => 185240)


--- trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp	2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp	2015-06-05 05:20:45 UTC (rev 185240)
@@ -257,21 +257,15 @@
     failed.link(this);
     notString.link(this);
     nonCell.link(this);
-    
-    Jump skipProfiling = jump();
 
     linkSlowCase(iter); // vector length check
     linkSlowCase(iter); // empty value
     
-    emitArrayProfileOutOfBoundsSpecialCase(profile);
-    
-    skipProfiling.link(this);
-    
     Label slowPath = label();
     
     emitLoad(base, regT1, regT0);
     emitLoad(property, regT3, regT2);
-    Call call = callOperation(operationGetByValDefault, dst, regT1, regT0, regT3, regT2);
+    Call call = callOperation(operationGetByValDefault, dst, regT1, regT0, regT3, regT2, profile);
 
     m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
     m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call;
@@ -464,6 +458,7 @@
     emitLoad(value, regT0, regT1);
     addCallArgument(regT1);
     addCallArgument(regT0);
+    addCallArgument(TrustedImmPtr(profile));
     Call call = appendCallWithExceptionCheck(isDirect ? operationDirectPutByVal : operationPutByVal);
 #else
     // The register selection below is chosen to reduce register swapping on ARM.
@@ -471,7 +466,7 @@
     emitLoad(base, regT2, regT1);
     emitLoad(property, regT3, regT0);
     emitLoad(value, regT5, regT4);
-    Call call = callOperation(isDirect ? operationDirectPutByVal : operationPutByVal, regT2, regT1, regT3, regT0, regT5, regT4);
+    Call call = callOperation(isDirect ? operationDirectPutByVal : operationPutByVal, regT2, regT1, regT3, regT0, regT5, regT4, profile);
 #endif
 
     m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;

Modified: trunk/Source/_javascript_Core/runtime/DirectArguments.h (185239 => 185240)


--- trunk/Source/_javascript_Core/runtime/DirectArguments.h	2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/_javascript_Core/runtime/DirectArguments.h	2015-06-05 05:20:45 UTC (rev 185240)
@@ -75,7 +75,12 @@
     {
         return i < m_length && (!m_overrides || !m_overrides.get()[i]);
     }
-    
+
+    bool canAccessArgumentIndexQuicklyInDFG(uint32_t i) const
+    {
+        return i < m_length && !overrodeThings();
+    }
+
     JSValue getIndexQuickly(uint32_t i) const
     {
         ASSERT_WITH_SECURITY_IMPLICATION(canAccessIndexQuickly(i));

Modified: trunk/Source/_javascript_Core/runtime/JSPromiseFunctions.cpp (185239 => 185240)


--- trunk/Source/_javascript_Core/runtime/JSPromiseFunctions.cpp	2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/_javascript_Core/runtime/JSPromiseFunctions.cpp	2015-06-05 05:20:45 UTC (rev 185240)
@@ -29,8 +29,7 @@
 #if ENABLE(PROMISES)
 
 #include "Error.h"
-#include "JSCJSValueInlines.h"
-#include "JSCellInlines.h"
+#include "JSCInlines.h"
 #include "JSPromise.h"
 #include "JSPromiseConstructor.h"
 #include "JSPromiseDeferred.h"

Modified: trunk/Source/_javascript_Core/runtime/ScopedArguments.h (185239 => 185240)


--- trunk/Source/_javascript_Core/runtime/ScopedArguments.h	2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/_javascript_Core/runtime/ScopedArguments.h	2015-06-05 05:20:45 UTC (rev 185240)
@@ -80,6 +80,11 @@
             return !!m_table->get(i);
         return !!overflowStorage()[i - namedLength].get();
     }
+
+    bool canAccessArgumentIndexQuicklyInDFG(uint32_t i) const
+    {
+        return canAccessIndexQuickly(i);
+    }
     
     JSValue getIndexQuickly(uint32_t i) const
     {

Added: trunk/Source/_javascript_Core/tests/stress/get-by-val-out-of-bounds-basics.js (0 => 185240)


--- trunk/Source/_javascript_Core/tests/stress/get-by-val-out-of-bounds-basics.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/get-by-val-out-of-bounds-basics.js	2015-06-05 05:20:45 UTC (rev 185240)
@@ -0,0 +1,221 @@
+// Get early out-of-bound data.
+function opaqueGetByValOnInt32ArrayEarlyOutOfBounds(array, index)
+{
+    return array[index];
+}
+noInline(opaqueGetByValOnInt32ArrayEarlyOutOfBounds);
+
+function testInt32ArrayEarlyOutOfBounds()
+{
+    // Warm up with an immediate out of bounds.
+    var int32Array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+    for (var i = 0; i <= 10; ++i) {
+        var value = opaqueGetByValOnInt32ArrayEarlyOutOfBounds(int32Array, i);
+        if ((i < 10 && value !== i) || (i >= 10 && value !== undefined))
+            throw "Failed opaqueGetByValOnInt32ArrayEarlyOutOfBounds(int32Array, i) warmup with i = " + i + " value = " + value;
+    }
+
+    // We then do plenty of in-bounds accesses.
+    for (var i = 0; i < 1e4; ++i) {
+        for (var j = 0; j < 10; ++j) {
+            var value = opaqueGetByValOnInt32ArrayEarlyOutOfBounds(int32Array, j);
+            if (j < 10 && value !== j)
+                throw "Failed opaqueGetByValOnInt32ArrayEarlyOutOfBounds(int32Array, j) in-bounds with j = " + j + " value = " + value;
+        }
+    }
+
+    // Followed by plenty of out-of-bounds accesses.
+    for (var i = 0; i < 1e4; ++i) {
+        for (var j = 0; j <= 10; ++j) {
+            var value = opaqueGetByValOnInt32ArrayEarlyOutOfBounds(int32Array, j);
+            if ((j < 10 && value !== j) || (j >= 10 && value !== undefined))
+                throw "Failed opaqueGetByValOnInt32ArrayEarlyOutOfBounds(int32Array, j) out-of-bounds with j = " + j + " value = " + value;
+        }
+    }
+}
+testInt32ArrayEarlyOutOfBounds();
+
+// One more access, with a completely different array type.
+function testIndexingTypeChangesOnInt32Array()
+{
+    var doubleArray = [-0, 5.5, -42.1];
+    var value = opaqueGetByValOnInt32ArrayEarlyOutOfBounds(doubleArray, 0);
+    if (value || 1 / value !== -Infinity)
+        throw "Failed opaqueGetByValOnInt32ArrayEarlyOutOfBounds(doubleArray, 0)";
+    var value = opaqueGetByValOnInt32ArrayEarlyOutOfBounds(doubleArray, 1);
+    if (value !== 5.5)
+        throw "Failed opaqueGetByValOnInt32ArrayEarlyOutOfBounds(doubleArray, 1)";
+    var value = opaqueGetByValOnInt32ArrayEarlyOutOfBounds(doubleArray, 2);
+    if (value !== -42.1)
+        throw "Failed opaqueGetByValOnInt32ArrayEarlyOutOfBounds(doubleArray, 2)";
+}
+testIndexingTypeChangesOnInt32Array();
+
+
+
+// Get out-of-bound data after a thousand run.
+function opaqueGetByValOnStringArrayHotOutOfBounds(array, index)
+{
+    return array[index];
+}
+noInline(opaqueGetByValOnStringArrayHotOutOfBounds);
+
+function testStringArrayHotOutOfBounds()
+{
+    // Warm up with in bounds access.
+    var stringArray = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
+    for (var i = 0; i < 1e2; ++i) {
+        for (var j = 0; j < 10; ++j) {
+            var value = opaqueGetByValOnStringArrayHotOutOfBounds(stringArray, j);
+            if (value !== "" + j)
+                throw "Failed opaqueGetByValOnStringArrayHotOutOfBounds(stringArray, j) in-bounds with j = " + j + " value = " + value;
+        }
+    }
+
+    // Do a single out of bounds after warmup.
+    var value = opaqueGetByValOnStringArrayHotOutOfBounds(stringArray, 10);
+    if (value !== undefined)
+        throw "Failed opaqueGetByValOnStringArrayHotOutOfBounds(stringArray, 10) with i = " + i + " value = " + value;
+
+    // We then do plenty of in-bounds accesses.
+    for (var i = 0; i < 1e3; ++i) {
+        for (var j = 0; j < 10; ++j) {
+            var value = opaqueGetByValOnStringArrayHotOutOfBounds(stringArray, j);
+            if (value !== "" + j)
+                throw "Failed opaqueGetByValOnStringArrayHotOutOfBounds(stringArray, j) in-bounds with j = " + j + " value = " + value;
+        }
+    }
+
+    // Followed by plenty of out-of-bounds accesses.
+    for (var i = 0; i < 1e3; ++i) {
+        for (var j = 0; j <= 10; ++j) {
+            var value = opaqueGetByValOnStringArrayHotOutOfBounds(stringArray, j);
+            if ((j < 10 && value !== "" + j) || (j >= 10 && value !== undefined))
+                throw "Failed opaqueGetByValOnStringArrayHotOutOfBounds(stringArray, j) out-of-bounds with j = " + j + " value = " + value;
+        }
+    }
+}
+testStringArrayHotOutOfBounds();
+
+function testIndexingTypeChangesOnStringArray()
+{
+    var doubleArray = [-0, 5.5, -42.1];
+    var value = opaqueGetByValOnStringArrayHotOutOfBounds(doubleArray, 0);
+    if (value || 1 / value !== -Infinity)
+        throw "Failed opaqueGetByValOnStringArrayHotOutOfBounds(doubleArray, 0)";
+    var value = opaqueGetByValOnStringArrayHotOutOfBounds(doubleArray, 1);
+    if (value !== 5.5)
+        throw "Failed opaqueGetByValOnStringArrayHotOutOfBounds(doubleArray, 1)";
+    var value = opaqueGetByValOnStringArrayHotOutOfBounds(doubleArray, 2);
+    if (value !== -42.1)
+        throw "Failed opaqueGetByValOnStringArrayHotOutOfBounds(doubleArray, 2)";
+}
+testIndexingTypeChangesOnStringArray();
+
+
+
+// Get out-of-bound data after a thousand run, but from a different array type.
+function opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(array, index)
+{
+    return array[index];
+}
+noInline(opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds);
+
+function testStringAndInt32ArrayHotOutOfBounds()
+{
+    // Warm up with in bounds access.
+    var stringArray = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
+    for (var i = 0; i < 1e2; ++i) {
+        for (var j = 0; j < 10; ++j) {
+            var value = opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(stringArray, j);
+            if (value !== "" + j)
+                throw "Failed opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(stringArray, j) in-bounds with j = " + j + " value = " + value;
+        }
+    }
+
+    // Do a single out of bounds after warmup.
+    var int32Array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+    var value = opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(int32Array, 10);
+    if (value !== undefined)
+        throw "Failed opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(stringArray, 10) with i = " + i + " value = " + value;
+
+    // We then do plenty of in-bounds accesses.
+    for (var i = 0; i < 1e3; ++i) {
+        for (var j = 0; j < 10; ++j) {
+            var value = opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(stringArray, j);
+            if (value !== "" + j)
+                throw "Failed opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(stringArray, j) in-bounds with j = " + j + " value = " + value;
+
+            var value = opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(int32Array, j);
+            if (value !== j)
+                throw "Failed opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(int32Array, j) in-bounds with j = " + j + " value = " + value;
+        }
+    }
+
+    // Followed by plenty of out-of-bounds accesses.
+    for (var i = 0; i < 1e3; ++i) {
+        for (var j = 0; j <= 10; ++j) {
+            var value = opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(int32Array, j);
+            if ((j < 10 && value !== j) || (j >= 10 && value !== undefined))
+                throw "Failed opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(int32Array, j) out-of-bounds with j = " + j + " value = " + value;
+
+            var value = opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(stringArray, j);
+            if ((j < 10 && value !== "" + j) || (j >= 10 && value !== undefined))
+                throw "Failed opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(stringArray, j) out-of-bounds with j = " + j + " value = " + value;
+        }
+    }
+}
+testStringAndInt32ArrayHotOutOfBounds();
+
+
+// Get out-of-bound data from a hole after a thousand run.
+function opaqueGetByValOnDoubleArrayHotOutOfBounds(array, index)
+{
+    return array[index];
+}
+noInline(opaqueGetByValOnDoubleArrayHotOutOfBounds);
+
+function testStringArrayHotOutOfBounds()
+{
+    // Warm up with in bounds access.
+    var doubleArray = new Array(10);
+    for (var i = 0; i < 10; ++i) {
+        if (i !== 5)
+            doubleArray[i] = i + 0.5;
+    }
+    for (var i = 0; i < 1e2; ++i) {
+        for (var j = 0; j < 10; ++j) {
+            if (j !== 5) {
+                var value = opaqueGetByValOnDoubleArrayHotOutOfBounds(doubleArray, j);
+                if (value !== j + 0.5)
+                    throw "Failed opaqueGetByValOnDoubleArrayHotOutOfBounds(doubleArray, j) in-bounds with j = " + j + " value = " + value;
+            }
+        }
+    }
+
+    // Do a single out of bounds after warmup.
+    var value = opaqueGetByValOnDoubleArrayHotOutOfBounds(doubleArray, 5);
+    if (value !== undefined)
+        throw "Failed opaqueGetByValOnDoubleArrayHotOutOfBounds(doubleArray, 5) with i = " + i + " value = " + value;
+
+    // We then do plenty of in-bounds accesses.
+    for (var i = 0; i < 1e3; ++i) {
+        for (var j = 0; j < 10; ++j) {
+            if (j !== 5) {
+                var value = opaqueGetByValOnDoubleArrayHotOutOfBounds(doubleArray, j);
+                if (value !== j + 0.5)
+                    throw "Failed opaqueGetByValOnDoubleArrayHotOutOfBounds(doubleArray, j) in-bounds with j = " + j + " value = " + value;
+            }
+        }
+    }
+
+    // Followed by plenty of out-of-bounds accesses.
+    for (var i = 0; i < 1e3; ++i) {
+        for (var j = 0; j < 10; ++j) {
+            var value = opaqueGetByValOnDoubleArrayHotOutOfBounds(doubleArray, j);
+            if ((j !== 5 && value !== j + 0.5) || (j === 10 && value !== undefined))
+                throw "Failed opaqueGetByValOnDoubleArrayHotOutOfBounds(doubleArray, j) out-of-bounds with j = " + j + " value = " + value;
+        }
+    }
+}
+testStringArrayHotOutOfBounds();
\ No newline at end of file

Added: trunk/Source/_javascript_Core/tests/stress/put-by-val-out-of-bounds-basics.js (0 => 185240)


--- trunk/Source/_javascript_Core/tests/stress/put-by-val-out-of-bounds-basics.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/put-by-val-out-of-bounds-basics.js	2015-06-05 05:20:45 UTC (rev 185240)
@@ -0,0 +1,87 @@
+// Put early out-of-bound data.
+function opaquePutByValOnInt32ArrayEarlyOutOfBounds(array, index, value)
+{
+    array[index] = value;
+}
+noInline(opaquePutByValOnInt32ArrayEarlyOutOfBounds);
+
+function testInt32ArrayEarlyOutOfBounds()
+{
+    // Warm up with an immediate out of bounds.
+    var int32Array = new Array(10);
+    for (var i = 0; i < 10; ++i) {
+        opaquePutByValOnInt32ArrayEarlyOutOfBounds(int32Array, i, i);
+        var value = int32Array[i];
+        if (value !== i)
+            throw "Failed opaquePutByValOnInt32ArrayEarlyOutOfBounds(int32Array, i, i) warmup with i = " + i + " value = " + value;
+    }
+    opaquePutByValOnInt32ArrayEarlyOutOfBounds(int32Array, 1042, 1);
+    var value = int32Array[1042];
+    if (value !== 1)
+        throw "Failed opaquePutByValOnInt32ArrayEarlyOutOfBounds(int32Array, 1042, 1) value = " + value;
+
+    var length = int32Array.length;
+    if (int32Array.length !== 1043)
+        throw "Incorrect int32Array.length, length = " + length;
+
+
+    // We then do plenty of in-bounds accesses.
+    for (var i = 0; i < 1e4; ++i) {
+        for (var j = 0; j < 10; ++j) {
+            opaquePutByValOnInt32ArrayEarlyOutOfBounds(int32Array, j, i);
+            var value = int32Array[j];
+            if (value !== i)
+                throw "Failed opaquePutByValOnInt32ArrayEarlyOutOfBounds(int32Array, j, i) in-bounds with i = " + i + " j = " + j + " value = " + value;
+        }
+    }
+}
+testInt32ArrayEarlyOutOfBounds();
+
+
+// Get out-of-bound data after a thousand run.
+function opaquePutByValOnStringArrayHotOutOfBounds(array, index, value)
+{
+    array[index] = value;
+}
+noInline(opaquePutByValOnStringArrayHotOutOfBounds);
+
+function testStringArrayHotOutOfBounds()
+{
+    // Warm up with in bounds access.
+    var stringArray = new Array(10);
+    for (var i = 0; i < 1e2; ++i) {
+        for (var j = 0; j < 10; ++j) {
+            opaquePutByValOnStringArrayHotOutOfBounds(stringArray, j, "" + i);
+            var value = stringArray[j];
+            if (value !== "" + i)
+                throw "Failed opaquePutByValOnStringArrayHotOutOfBounds(stringArray, j, i) in-bounds with i = " + i + " j = " + j + " value = " + value;
+        }
+    }
+
+    // Do a single out of bounds after warmup.
+    opaquePutByValOnStringArrayHotOutOfBounds(stringArray, 513, 42);
+    var value = stringArray[513];
+    if (value !== 42)
+        throw "Failed opaquePutByValOnStringArrayHotOutOfBounds(stringArray, 513, 42), value = " + value;
+
+    // We then do plenty of in-bounds accesses.
+    for (var i = 0; i < 1e3; ++i) {
+        for (var j = 0; j < 10; ++j) {
+            opaquePutByValOnStringArrayHotOutOfBounds(stringArray, j, "" + i);
+            var value = stringArray[j];
+            if (value !== "" + i)
+                throw "Failed opaquePutByValOnStringArrayHotOutOfBounds(stringArray, j, i) in-bounds with i = " + i + " j = " + j + " value = " + value;
+        }
+    }
+
+    // Followed by plenty of out-of-bounds accesses.
+    for (var j = 514; j <= 1025; ++j)
+        opaquePutByValOnStringArrayHotOutOfBounds(stringArray, j, "" + j);
+
+    for (var j = 514; j <= 1025; ++j) {
+        var value = stringArray[j];
+        if (value !== "" + j)
+            throw "Failed opaquePutByValOnStringArrayHotOutOfBounds(stringArray, j, j) in-bounds with j = " + j + " value = " + value;
+    }
+}
+testStringArrayHotOutOfBounds();
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to