Constant folding of typed array properties should be handled by AI rather than streng...
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 7 Apr 2015 22:09:15 +0000 (22:09 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 7 Apr 2015 22:09:15 +0000 (22:09 +0000)
https://bugs.webkit.org/show_bug.cgi?id=143496

Reviewed by Geoffrey Garen.

Handling constant folding in AI is better because it precludes us from having to fixpoint the CFA
phase and whatever other phase did the folding in order to find all constants.

This also removes the TypedArrayWatchpoint node type because we can just set the watchpoint
directly.

This also fixes a bug in FTL lowering of GetTypedArrayByteOffset. The bug was previously not
found because all of the tests for it involved the property getting constant folded. I found that
the codegen was bad because an earlier version of the patch broke that constant folding. This
adds a new test for that node type, which makes constant folding impossible by allocating a new
typed array every type. The lesson here is: if you write a test for something, run the test with
full IR dumps to make sure it's actually testing the thing you want it to test.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
(JSC::DFG::Graph::tryGetFoldableView):
(JSC::DFG::Graph::tryGetFoldableViewForChild1): Deleted.
* dfg/DFGGraph.h:
* dfg/DFGNode.h:
(JSC::DFG::Node::hasTypedArray): Deleted.
(JSC::DFG::Node::typedArray): Deleted.
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::jumpForTypedArrayOutOfBounds):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStrengthReductionPhase.cpp:
(JSC::DFG::StrengthReductionPhase::handleNode):
(JSC::DFG::StrengthReductionPhase::foldTypedArrayPropertyToConstant): Deleted.
(JSC::DFG::StrengthReductionPhase::prepareToFoldTypedArray): Deleted.
* dfg/DFGWatchpointCollectionPhase.cpp:
(JSC::DFG::WatchpointCollectionPhase::handle):
(JSC::DFG::WatchpointCollectionPhase::addLazily):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileGetTypedArrayByteOffset):
(JSC::FTL::LowerDFGToLLVM::typedArrayLength):
* tests/stress/fold-typed-array-properties.js:
(foo):
* tests/stress/typed-array-byte-offset.js: Added.
(foo):

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

21 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGGraph.cpp
Source/JavaScriptCore/dfg/DFGGraph.h
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
Source/JavaScriptCore/tests/stress/fold-typed-array-properties.js
Source/JavaScriptCore/tests/stress/typed-array-byte-offset.js [new file with mode: 0644]

index d6024e2..45d35f3 100644 (file)
@@ -1,3 +1,70 @@
+2015-04-07  Filip Pizlo  <fpizlo@apple.com>
+
+        Constant folding of typed array properties should be handled by AI rather than strength reduction
+        https://bugs.webkit.org/show_bug.cgi?id=143496
+
+        Reviewed by Geoffrey Garen.
+        
+        Handling constant folding in AI is better because it precludes us from having to fixpoint the CFA
+        phase and whatever other phase did the folding in order to find all constants.
+        
+        This also removes the TypedArrayWatchpoint node type because we can just set the watchpoint
+        directly.
+        
+        This also fixes a bug in FTL lowering of GetTypedArrayByteOffset. The bug was previously not
+        found because all of the tests for it involved the property getting constant folded. I found that
+        the codegen was bad because an earlier version of the patch broke that constant folding. This
+        adds a new test for that node type, which makes constant folding impossible by allocating a new
+        typed array every type. The lesson here is: if you write a test for something, run the test with
+        full IR dumps to make sure it's actually testing the thing you want it to test.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::dump):
+        (JSC::DFG::Graph::tryGetFoldableView):
+        (JSC::DFG::Graph::tryGetFoldableViewForChild1): Deleted.
+        * dfg/DFGGraph.h:
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasTypedArray): Deleted.
+        (JSC::DFG::Node::typedArray): Deleted.
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::jumpForTypedArrayOutOfBounds):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGStrengthReductionPhase.cpp:
+        (JSC::DFG::StrengthReductionPhase::handleNode):
+        (JSC::DFG::StrengthReductionPhase::foldTypedArrayPropertyToConstant): Deleted.
+        (JSC::DFG::StrengthReductionPhase::prepareToFoldTypedArray): Deleted.
+        * dfg/DFGWatchpointCollectionPhase.cpp:
+        (JSC::DFG::WatchpointCollectionPhase::handle):
+        (JSC::DFG::WatchpointCollectionPhase::addLazily):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::compileNode):
+        (JSC::FTL::LowerDFGToLLVM::compileGetTypedArrayByteOffset):
+        (JSC::FTL::LowerDFGToLLVM::typedArrayLength):
+        * tests/stress/fold-typed-array-properties.js:
+        (foo):
+        * tests/stress/typed-array-byte-offset.js: Added.
+        (foo):
+
 2015-04-07  Matthew Mirman  <mmirman@apple.com>
 
         Source and stack information should get appended only to native errors
index a552bcb..8d15305 100644 (file)
@@ -1383,9 +1383,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->activationStructure());
         break;
         
-    case TypedArrayWatchpoint:
-        break;
-    
     case CreateDirectArguments:
         forNode(node).set(m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->directArgumentsStructure());
         break;
@@ -1520,9 +1517,16 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         break;
     }
             
-    case GetArrayLength:
+    case GetArrayLength: {
+        JSArrayBufferView* view = m_graph.tryGetFoldableView(
+            forNode(node->child1()).m_value, node->arrayMode());
+        if (view) {
+            setConstant(node, jsNumber(view->length()));
+            break;
+        }
         forNode(node).setType(SpecInt32);
         break;
+    }
         
     case CheckStructure: {
         AbstractValue& value = forNode(node->child1());
@@ -1705,13 +1709,25 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         value.set(m_graph, node->structure());
         break;
     }
-    case GetIndexedPropertyStorage:
+    case GetIndexedPropertyStorage: {
+        JSArrayBufferView* view = m_graph.tryGetFoldableView(
+            forNode(node->child1()).m_value, node->arrayMode());
+        if (view)
+            m_state.setFoundConstants(true);
+        forNode(node).clear();
+        break;
+    }
     case ConstantStoragePointer: {
         forNode(node).clear();
         break; 
     }
         
     case GetTypedArrayByteOffset: {
+        JSArrayBufferView* view = m_graph.tryGetFoldableView(forNode(node->child1()).m_value);
+        if (view) {
+            setConstant(node, jsNumber(view->byteOffset()));
+            break;
+        }
         forNode(node).setType(SpecInt32);
         break;
     }
index 49766c0..831d8b7 100644 (file)
@@ -306,11 +306,6 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
         write(SideState);
         return;
 
-    case TypedArrayWatchpoint:
-        read(Watchpoint_fire);
-        write(SideState);
-        return;
-        
     case NotifyWrite:
         write(Watchpoint_fire);
         write(SideState);
index 6dc84c2..9589b5e 100644 (file)
@@ -115,6 +115,30 @@ private:
                 break;
             }
                 
+            case GetIndexedPropertyStorage: {
+                JSArrayBufferView* view = m_graph.tryGetFoldableView(
+                    m_state.forNode(node->child1()).m_value, node->arrayMode());
+                if (!view)
+                    break;
+                
+                if (view->mode() == FastTypedArray) {
+                    // FIXME: It would be awesome to be able to fold the property storage for
+                    // these GC-allocated typed arrays. For now it doesn't matter because the
+                    // most common use-cases for constant typed arrays involve large arrays with
+                    // aliased buffer views.
+                    // https://bugs.webkit.org/show_bug.cgi?id=125425
+                    break;
+                }
+                
+                m_interpreter.execute(indexInBlock);
+                eliminated = true;
+                
+                m_insertionSet.insertNode(
+                    indexInBlock, SpecNone, Phantom, node->origin, node->children);
+                node->convertToConstantStoragePointer(view->vector());
+                break;
+            }
+                
             case CheckStructureImmediate: {
                 AbstractValue& value = m_state.forNode(node->child1());
                 StructureSet& set = node->structureSet();
index 6ed0fbd..a6adaf7 100644 (file)
@@ -164,7 +164,6 @@ bool doesGC(Graph& graph, Node* node)
     case StoreBarrierWithNullCheck:
     case InvalidationPoint:
     case NotifyWrite:
-    case TypedArrayWatchpoint:
     case CheckInBounds:
     case ConstantStoragePointer:
     case Check:
index 9e53a19..9ce826a 100644 (file)
@@ -1238,7 +1238,6 @@ private:
         case LoopHint:
         case StoreBarrier:
         case StoreBarrierWithNullCheck:
-        case TypedArrayWatchpoint:
         case MovHint:
         case ZombieHint:
         case BottomValue:
index f63e899..cf9df62 100644 (file)
@@ -313,8 +313,6 @@ void Graph::dump(PrintStream& out, const char* prefix, Node* node, DumpContext*
         out.print(comma, RawPointer(node->executionCounter()));
     if (node->hasVariableWatchpointSet())
         out.print(comma, RawPointer(node->variableWatchpointSet()));
-    if (node->hasTypedArray())
-        out.print(comma, inContext(JSValue(node->typedArray()), context));
     if (node->hasStoragePointer())
         out.print(comma, RawPointer(node->storagePointer()));
     if (node->hasObjectMaterializationData())
@@ -1071,27 +1069,25 @@ JSValue Graph::tryGetConstantClosureVar(Node* node, ScopeOffset offset)
     return tryGetConstantClosureVar(node->asJSValue(), offset);
 }
 
-JSArrayBufferView* Graph::tryGetFoldableView(Node* node)
+JSArrayBufferView* Graph::tryGetFoldableView(JSValue value)
 {
-    JSArrayBufferView* view = node->dynamicCastConstant<JSArrayBufferView*>();
-    if (!view)
+    if (!value)
+        return nullptr;
+    JSArrayBufferView* view = jsDynamicCast<JSArrayBufferView*>(value);
+    if (!value)
         return nullptr;
     if (!view->length())
         return nullptr;
     WTF::loadLoadFence();
+    watchpoints().addLazily(view);
     return view;
 }
 
-JSArrayBufferView* Graph::tryGetFoldableView(Node* node, ArrayMode arrayMode)
+JSArrayBufferView* Graph::tryGetFoldableView(JSValue value, ArrayMode arrayMode)
 {
     if (arrayMode.typedArrayType() == NotTypedArray)
-        return 0;
-    return tryGetFoldableView(node);
-}
-
-JSArrayBufferView* Graph::tryGetFoldableViewForChild1(Node* node)
-{
-    return tryGetFoldableView(child(node, 0).node(), node->arrayMode());
+        return nullptr;
+    return tryGetFoldableView(value);
 }
 
 void Graph::registerFrozenValues()
index 7ccb765..6b40e4a 100644 (file)
@@ -692,9 +692,8 @@ public:
     JSValue tryGetConstantClosureVar(const AbstractValue&, ScopeOffset);
     JSValue tryGetConstantClosureVar(Node*, ScopeOffset);
     
-    JSArrayBufferView* tryGetFoldableView(Node*);
-    JSArrayBufferView* tryGetFoldableView(Node*, ArrayMode);
-    JSArrayBufferView* tryGetFoldableViewForChild1(Node*);
+    JSArrayBufferView* tryGetFoldableView(JSValue);
+    JSArrayBufferView* tryGetFoldableView(JSValue, ArrayMode arrayMode);
     
     void registerFrozenValues();
     
index d27a6da..c75af88 100644 (file)
@@ -1229,16 +1229,6 @@ struct Node {
         return reinterpret_cast<VariableWatchpointSet*>(m_opInfo);
     }
     
-    bool hasTypedArray()
-    {
-        return op() == TypedArrayWatchpoint;
-    }
-    
-    JSArrayBufferView* typedArray()
-    {
-        return reinterpret_cast<JSArrayBufferView*>(m_opInfo);
-    }
-    
     bool hasStoragePointer()
     {
         return op() == ConstantStoragePointer;
index 1e79d1a..f989914 100644 (file)
@@ -174,7 +174,6 @@ namespace JSC { namespace DFG {
     macro(ArrayifyToStructure, NodeMustGenerate) \
     macro(GetIndexedPropertyStorage, NodeResultStorage) \
     macro(ConstantStoragePointer, NodeResultStorage) \
-    macro(TypedArrayWatchpoint, NodeMustGenerate) \
     macro(GetGetter, NodeResultJS) \
     macro(GetSetter, NodeResultJS) \
     macro(GetByOffset, NodeResultJS) \
index 18e56b6..815c700 100644 (file)
@@ -645,7 +645,6 @@ private:
         case Unreachable:
         case LoopHint:
         case NotifyWrite:
-        case TypedArrayWatchpoint:
         case ConstantStoragePointer:
         case MovHint:
         case ZombieHint:
index be243d7..e530a52 100644 (file)
@@ -251,7 +251,6 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case StoreBarrierWithNullCheck:
     case InvalidationPoint:
     case NotifyWrite:
-    case TypedArrayWatchpoint:
     case CheckInBounds:
     case ConstantStoragePointer:
     case Check:
index 4e5af17..eb50cad 100644 (file)
@@ -2268,7 +2268,9 @@ JITCompiler::Jump SpeculativeJIT::jumpForTypedArrayOutOfBounds(Node* node, GPRRe
 {
     if (node->op() == PutByValAlias)
         return JITCompiler::Jump();
-    if (JSArrayBufferView* view = m_jit.graph().tryGetFoldableViewForChild1(node)) {
+    JSArrayBufferView* view = m_jit.graph().tryGetFoldableView(
+        m_state.forNode(m_jit.graph().child(node, 0)).m_value, node->arrayMode());
+    if (view) {
         uint32_t length = view->length();
         Node* indexNode = m_jit.graph().child(node, 1).node();
         if (indexNode->isInt32Constant() && indexNode->asUInt32() < length)
index a76da85..3a1698e 100644 (file)
@@ -3533,8 +3533,7 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
 
-    case AllocationProfileWatchpoint:
-    case TypedArrayWatchpoint: {
+    case AllocationProfileWatchpoint: {
         noResult(node);
         break;
     }
index 2c81666..e44d14a 100644 (file)
@@ -3608,8 +3608,7 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
         
-    case AllocationProfileWatchpoint:
-    case TypedArrayWatchpoint: {
+    case AllocationProfileWatchpoint: {
         noResult(node);
         break;
     }
index 7a7d42c..d94fade 100644 (file)
@@ -146,33 +146,6 @@ private:
             }
             break;
 
-        case GetArrayLength:
-            if (JSArrayBufferView* view = m_graph.tryGetFoldableViewForChild1(m_node))
-                foldTypedArrayPropertyToConstant(view, jsNumber(view->length()));
-            break;
-            
-        case GetTypedArrayByteOffset:
-            if (JSArrayBufferView* view = m_graph.tryGetFoldableView(m_node->child1().node()))
-                foldTypedArrayPropertyToConstant(view, jsNumber(view->byteOffset()));
-            break;
-            
-        case GetIndexedPropertyStorage:
-            if (JSArrayBufferView* view = m_graph.tryGetFoldableViewForChild1(m_node)) {
-                if (view->mode() != FastTypedArray) {
-                    prepareToFoldTypedArray(view);
-                    m_node->convertToConstantStoragePointer(view->vector());
-                    m_changed = true;
-                    break;
-                } else {
-                    // FIXME: It would be awesome to be able to fold the property storage for
-                    // these GC-allocated typed arrays. For now it doesn't matter because the
-                    // most common use-cases for constant typed arrays involve large arrays with
-                    // aliased buffer views.
-                    // https://bugs.webkit.org/show_bug.cgi?id=125425
-                }
-            }
-            break;
-            
         case ValueRep:
         case Int52Rep:
         case DoubleRep: {
@@ -283,22 +256,6 @@ private:
         convertToIdentityOverChild(1);
     }
     
-    void foldTypedArrayPropertyToConstant(JSArrayBufferView* view, JSValue constant)
-    {
-        prepareToFoldTypedArray(view);
-        m_graph.convertToConstant(m_node, constant);
-        m_changed = true;
-    }
-    
-    void prepareToFoldTypedArray(JSArrayBufferView* view)
-    {
-        m_insertionSet.insertNode(
-            m_nodeIndex, SpecNone, TypedArrayWatchpoint, m_node->origin,
-            OpInfo(view));
-        m_insertionSet.insertNode(
-            m_nodeIndex, SpecNone, Phantom, m_node->origin, m_node->children);
-    }
-    
     void handleCommutativity()
     {
         // If the right side is a constant then there is nothing left to do.
index 1e4000f..3404ead 100644 (file)
@@ -92,14 +92,6 @@ private:
             
             if (m_node->arrayMode().type() == Array::String)
                 handleStringGetByVal();
-
-            if (JSArrayBufferView* view = m_graph.tryGetFoldableViewForChild1(m_node))
-                addLazily(view);
-            break;
-            
-        case PutByVal:
-            if (JSArrayBufferView* view = m_graph.tryGetFoldableViewForChild1(m_node))
-                addLazily(view);
             break;
             
         case StringCharAt:
@@ -121,10 +113,6 @@ private:
             addLazily(globalObject()->varInjectionWatchpoint());
             break;
             
-        case TypedArrayWatchpoint:
-            addLazily(m_node->typedArray());
-            break;
-            
         default:
             break;
         }
@@ -154,10 +142,6 @@ private:
     {
         m_graph.watchpoints().addLazily(set);
     }
-    void addLazily(JSArrayBufferView* view)
-    {
-        m_graph.watchpoints().addLazily(view);
-    }
     
     JSGlobalObject* globalObject()
     {
index 3cd9024..40bf6d8 100644 (file)
@@ -119,7 +119,6 @@ inline CapabilityLevel canCompile(Node* node)
     case StringCharCodeAt:
     case AllocatePropertyStorage:
     case ReallocatePropertyStorage:
-    case TypedArrayWatchpoint:
     case GetTypedArrayByteOffset:
     case NotifyWrite:
     case StoreBarrier:
index 2355787..7142559 100644 (file)
@@ -846,7 +846,6 @@ private:
 
         case PhantomLocal:
         case LoopHint:
-        case TypedArrayWatchpoint:
         case AllocationProfileWatchpoint:
         case MovHint:
         case ZombieHint:
@@ -2105,9 +2104,9 @@ private:
         LBasicBlock wastefulCase = FTL_NEW_BLOCK(m_out, ("wasteful typed array"));
         LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("continuation branch"));
         
-        LValue baseAddress = m_out.addPtr(basePtr, JSArrayBufferView::offsetOfMode());
+        LValue mode = m_out.load32(basePtr, m_heaps.JSArrayBufferView_mode);
         m_out.branch(
-            m_out.notEqual(baseAddress , m_out.constIntPtr(WastefulTypedArray)),
+            m_out.notEqual(mode, m_out.constInt32(WastefulTypedArray)),
             unsure(simpleCase), unsure(wastefulCase));
 
         // begin simple case        
@@ -2125,7 +2124,7 @@ private:
         LValue arrayBufferPtr = m_out.loadPtr(butterflyPtr, m_heaps.Butterfly_arrayBuffer);
         LValue dataPtr = m_out.loadPtr(arrayBufferPtr, m_heaps.ArrayBuffer_data);
 
-        ValueFromBlock wastefulOut = m_out.anchor(m_out.sub(dataPtr, vectorPtr));        
+        ValueFromBlock wastefulOut = m_out.anchor(m_out.sub(vectorPtr, dataPtr));
 
         m_out.jump(continuation);
         m_out.appendTo(continuation, lastNext);
@@ -5785,7 +5784,9 @@ private:
     
     LValue typedArrayLength(Edge baseEdge, ArrayMode arrayMode, LValue base)
     {
-        if (JSArrayBufferView* view = m_graph.tryGetFoldableView(baseEdge.node(), arrayMode))
+        JSArrayBufferView* view = m_graph.tryGetFoldableView(
+            m_state.forNode(baseEdge).m_value, arrayMode);
+        if (view)
             return m_out.constInt32(view->length());
         return m_out.load32NonNegative(base, m_heaps.JSArrayBufferView_length);
     }
index 6523792..be5b482 100644 (file)
@@ -1,29 +1,32 @@
 var a = new Int32Array(new ArrayBuffer(100), 4, 1);
 
 if (a.length != 1)
-    throw "Error: bad length: " + a.length;
+    throw "Error: bad length (start): " + a.length;
 if (a.byteOffset != 4)
-    throw "Error: bad offset: " + a.byteOffset;
+    throw "Error: bad offset (start): " + a.byteOffset;
 if (a.byteLength != 4)
-    throw "Error: bad byte length: " + a.byteLength;
+    throw "Error: bad byte length (start): " + a.byteLength;
 
-function foo() {
-    if (a.length != 1)
-        throw "Error: bad length: " + a.length;
-    if (a.byteOffset != 4)
-        throw "Error: bad offset: " + a.byteOffset;
-    if (a.byteLength != 4)
-        throw "Error: bad byte length: " + a.byteLength;
+function foo(when) {
+    var tmp = a.length;
+    if (tmp != 1)
+        throw "Error: bad length (" + when + "): " + tmp;
+    tmp = a.byteOffset;
+    if (tmp != 4)
+        throw "Error: bad offset (" + when + "): " + tmp;
+    tmp = a.byteLength;
+    if (tmp != 4)
+        throw "Error: bad byte length (" + when + "): " + tmp;
 }
 
 for (var i = 0; i < 1000000; ++i)
-    foo();
+    foo("loop");
 
 transferArrayBuffer(a.buffer);
 
 var didThrow = false;
 try {
-    foo();
+    foo("after transfer");
 } catch (e) {
     didThrow = true;
 }
@@ -32,8 +35,8 @@ if (!didThrow)
     throw "Should have thrown.";
 
 if (a.length != 0)
-    throw "Error: bad length: " + a.length;
+    throw "Error: bad length (end): " + a.length;
 if (a.byteOffset != 0)
-    throw "Error: bad offset: " + a.byteOffset;
+    throw "Error: bad offset (end): " + a.byteOffset;
 if (a.byteLength != 0)
-    throw "Error: bad byte length: " + a.byteLength;
+    throw "Error: bad byte length (end): " + a.byteLength;
diff --git a/Source/JavaScriptCore/tests/stress/typed-array-byte-offset.js b/Source/JavaScriptCore/tests/stress/typed-array-byte-offset.js
new file mode 100644 (file)
index 0000000..39d3cf2
--- /dev/null
@@ -0,0 +1,17 @@
+function foo(array) {
+    return array.byteOffset;
+}
+
+noInline(foo);
+
+for (var i = 0; i < 10000; ++i) {
+    var result = foo(new Int32Array(100));
+    if (result != 0)
+        throw "Error: bad result for fast typed array: " + result;
+    result = foo(new Int32Array(100000));
+    if (result != 0)
+        throw "Error: bad result for big typed array: " + result;
+    result = foo(new Int32Array(new ArrayBuffer(100), 4, 1));
+    if (result != 4)
+        throw "Error: bad result for wasteful typed array: " + result;
+}