DFG should inline typedArray.byteOffset
https://bugs.webkit.org/show_bug.cgi?id=119962

Source/JavaScriptCore: 

Reviewed by Oliver Hunt.
        
This adds a new node, GetTypedArrayByteOffset, which inlines
typedArray.byteOffset.
        
Also, I improved a bunch of the clobbering logic related to typed arrays
and clobbering in general. For example, PutByOffset/PutStructure are not
clobber-world so they can be handled by most default cases in CSE. Also,
It's better to use the 'Class_field' notation for typed arrays now that
they no longer involve magical descriptor thingies.

* bytecode/SpeculatedType.h:
* dfg/DFGAbstractHeap.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::::executeEffects):
* dfg/DFGArrayMode.h:
(JSC::DFG::neverNeedsStorage):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::getByValLoadElimination):
(JSC::DFG::CSEPhase::getByOffsetLoadElimination):
(JSC::DFG::CSEPhase::getPropertyStorageLoadElimination):
(JSC::DFG::CSEPhase::checkArrayElimination):
(JSC::DFG::CSEPhase::getIndexedPropertyStorageLoadElimination):
(JSC::DFG::CSEPhase::getTypedArrayByteOffsetLoadElimination):
(JSC::DFG::CSEPhase::performNodeCSE):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::attemptToMakeGetTypedArrayByteLength):
(JSC::DFG::FixupPhase::convertToGetArrayLength):
(JSC::DFG::FixupPhase::attemptToMakeGetTypedArrayByteOffset):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileGetTypedArrayByteOffset):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGTypeCheckHoistingPhase.cpp:
(JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks):
* runtime/ArrayBuffer.h:
(JSC::ArrayBuffer::offsetOfData):
* runtime/Butterfly.h:
(JSC::Butterfly::offsetOfArrayBuffer):
* runtime/IndexingHeader.h:
(JSC::IndexingHeader::offsetOfArrayBuffer):

LayoutTests: 

Reviewed by Oliver Hunt.

* fast/js/dfg-byteOffset-neuter.html: Added.
* fast/js/dfg-byteOffset-neuter-expected.txt: Added.
* fast/js/regress/ArrayBuffer-Int32Array-byteOffset-expected.txt: Added.
* fast/js/regress/ArrayBuffer-Int32Array-byteOffset.html: Added.
* fast/js/regress/script-tests/ArrayBuffer-Int32Array-byteOffset.js: Added.
* fast/js/script-tests/dfg-byteOffset-neuter.js: Added.
(foo):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@154305 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 2b36e00..3c3c738 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,61 @@
+2013-08-17  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG should inline typedArray.byteOffset
+        https://bugs.webkit.org/show_bug.cgi?id=119962
+
+        Reviewed by Oliver Hunt.
+        
+        This adds a new node, GetTypedArrayByteOffset, which inlines
+        typedArray.byteOffset.
+        
+        Also, I improved a bunch of the clobbering logic related to typed arrays
+        and clobbering in general. For example, PutByOffset/PutStructure are not
+        clobber-world so they can be handled by most default cases in CSE. Also,
+        It's better to use the 'Class_field' notation for typed arrays now that
+        they no longer involve magical descriptor thingies.
+
+        * bytecode/SpeculatedType.h:
+        * dfg/DFGAbstractHeap.h:
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::::executeEffects):
+        * dfg/DFGArrayMode.h:
+        (JSC::DFG::neverNeedsStorage):
+        * dfg/DFGCSEPhase.cpp:
+        (JSC::DFG::CSEPhase::getByValLoadElimination):
+        (JSC::DFG::CSEPhase::getByOffsetLoadElimination):
+        (JSC::DFG::CSEPhase::getPropertyStorageLoadElimination):
+        (JSC::DFG::CSEPhase::checkArrayElimination):
+        (JSC::DFG::CSEPhase::getIndexedPropertyStorageLoadElimination):
+        (JSC::DFG::CSEPhase::getTypedArrayByteOffsetLoadElimination):
+        (JSC::DFG::CSEPhase::performNodeCSE):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::attemptToMakeGetTypedArrayByteLength):
+        (JSC::DFG::FixupPhase::convertToGetArrayLength):
+        (JSC::DFG::FixupPhase::attemptToMakeGetTypedArrayByteOffset):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileGetTypedArrayByteOffset):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGTypeCheckHoistingPhase.cpp:
+        (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks):
+        * runtime/ArrayBuffer.h:
+        (JSC::ArrayBuffer::offsetOfData):
+        * runtime/Butterfly.h:
+        (JSC::Butterfly::offsetOfArrayBuffer):
+        * runtime/IndexingHeader.h:
+        (JSC::IndexingHeader::offsetOfArrayBuffer):
+
 2013-08-18  Filip Pizlo  <fpizlo@apple.com>
 
         <https://webkit.org/b/119994> DFG new Array() inlining could get confused about global objects
diff --git a/Source/JavaScriptCore/bytecode/SpeculatedType.h b/Source/JavaScriptCore/bytecode/SpeculatedType.h
index bf31c5d..803e7a8 100644
--- a/Source/JavaScriptCore/bytecode/SpeculatedType.h
+++ b/Source/JavaScriptCore/bytecode/SpeculatedType.h
@@ -51,6 +51,7 @@
 static const SpeculatedType SpecUint32Array       = 0x00000400; // It's definitely an Uint32Array or one of its subclasses.
 static const SpeculatedType SpecFloat32Array      = 0x00000800; // It's definitely an Uint16Array or one of its subclasses.
 static const SpeculatedType SpecFloat64Array      = 0x00001000; // It's definitely an Uint16Array or one of its subclasses.
+static const SpeculatedType SpecTypedArrayView    = SpecInt8Array | SpecInt16Array | SpecInt32Array | SpecUint8Array | SpecUint8ClampedArray | SpecUint16Array | SpecUint32Array | SpecFloat32Array | SpecFloat64Array;
 static const SpeculatedType SpecArguments         = 0x00002000; // It's definitely an Arguments object.
 static const SpeculatedType SpecStringObject      = 0x00004000; // It's definitely a StringObject.
 static const SpeculatedType SpecObjectOther       = 0x00008000; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction.
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractHeap.h b/Source/JavaScriptCore/dfg/DFGAbstractHeap.h
index c9bbc56..6914fdf 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractHeap.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractHeap.h
@@ -48,8 +48,13 @@
     macro(Arguments_overrideLength) \
     macro(Arguments_registers) \
     macro(Arguments_slowArguments) \
+    macro(ArrayBuffer_data) \
+    macro(Butterfly_arrayBuffer) \
     macro(Butterfly_publicLength) \
     macro(Butterfly_vectorLength) \
+    macro(JSArrayBufferView_length) \
+    macro(JSArrayBufferView_mode) \
+    macro(JSArrayBufferView_vector) \
     macro(JSCell_structure) \
     macro(JSFunction_executable) \
     macro(JSFunction_scopeChain) \
@@ -61,9 +66,7 @@
     macro(IndexedContiguousProperties) \
     macro(ArrayStorageProperties) \
     macro(Variables) \
-    macro(TypedArrayStoragePointer) \
     macro(TypedArrayProperties) \
-    macro(TypedArrayLength) \
     macro(GCState) \
     macro(RegExpState) \
     macro(InternalState) \
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index 1bb2afa..4a5d46d 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -1376,6 +1376,12 @@
         forNode(node).clear();
         break; 
     }
+        
+    case GetTypedArrayByteOffset: {
+        forNode(node).setType(SpecInt32);
+        break;
+    }
+        
     case GetByOffset: {
         forNode(node).makeTop();
         break;
diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.h b/Source/JavaScriptCore/dfg/DFGArrayMode.h
index 02a69a5..1689189 100644
--- a/Source/JavaScriptCore/dfg/DFGArrayMode.h
+++ b/Source/JavaScriptCore/dfg/DFGArrayMode.h
@@ -445,6 +445,11 @@
     return arrayMode.lengthNeedsStorage();
 }
 
+static inline bool neverNeedsStorage(const ArrayMode&)
+{
+    return false;
+}
+
 } } // namespace JSC::DFG
 
 namespace WTF {
diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
index 0dda196..629b565 100644
--- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
@@ -396,13 +396,6 @@
                 // typed arrays!  An Int32Array can alias a Float64Array for example, and so on.
                 return 0;
             }
-            case PutStructure:
-            case PutByOffset:
-                // GetByVal currently always speculates that it's accessing an
-                // array with an integer index, which means that it's impossible
-                // for a structure change or a put to property storage to affect
-                // the GetByVal.
-                break;
             default:
                 if (m_graph.clobbersWorld(node))
                     return 0;
@@ -634,10 +627,6 @@
                 }
                 break;
                 
-            case PutStructure:
-                // Changing the structure cannot change the outcome of a property get.
-                break;
-                
             case PutByVal:
             case PutByValAlias:
                 if (m_graph.byValIsPure(node)) {
@@ -724,12 +713,6 @@
                 // pointer of any object, including ours.
                 return 0;
                 
-            case PutByOffset:
-            case PutStructure:
-                // Changing the structure or putting to the storage cannot
-                // change the property storage pointer.
-                break;
-                
             case PutByVal:
             case PutByValAlias:
                 if (m_graph.byValIsPure(node)) {
@@ -763,12 +746,6 @@
                 break;
 
             switch (node->op()) {
-            case PutByOffset:
-            case PutStructure:
-                // Changing the structure or putting to the storage cannot
-                // change the property storage pointer.
-                break;
-                
             case CheckArray:
                 if (node->child1() == child1 && node->arrayMode() == arrayMode)
                     return true;
@@ -803,12 +780,29 @@
                 break;
             }
 
-            case PutByOffset:
-            case PutStructure:
-                // Changing the structure or putting to the storage cannot
-                // change the property storage pointer.
+            default:
+                if (m_graph.clobbersWorld(node))
+                    return 0;
                 break;
-                
+            }
+        }
+        return 0;
+    }
+    
+    Node* getTypedArrayByteOffsetLoadElimination(Node* child1)
+    {
+        for (unsigned i = m_indexInBlock; i--;) {
+            Node* node = m_currentBlock->at(i);
+            if (node == child1) 
+                break;
+
+            switch (node->op()) {
+            case GetTypedArrayByteOffset: {
+                if (node->child1() == child1)
+                    return node;
+                break;
+            }
+
             default:
                 if (m_graph.clobbersWorld(node))
                     return 0;
@@ -1343,6 +1337,13 @@
             setReplacement(getIndexedPropertyStorageLoadElimination(node->child1().node(), node->arrayMode()));
             break;
         }
+            
+        case GetTypedArrayByteOffset: {
+            if (cseMode == StoreElimination)
+                break;
+            setReplacement(getTypedArrayByteOffsetLoadElimination(node->child1().node()));
+            break;
+        }
 
         case GetButterfly:
             if (cseMode == StoreElimination)
diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h
index 6ed4a4a..5efd6ca 100644
--- a/Source/JavaScriptCore/dfg/DFGClobberize.h
+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h
@@ -290,6 +290,8 @@
         case Array::Float32Array:
         case Array::Float64Array:
             read(TypedArrayProperties);
+            read(JSArrayBufferView_vector);
+            read(JSArrayBufferView_length);
             return;
         }
         RELEASE_ASSERT_NOT_REACHED();
@@ -377,6 +379,8 @@
         case Array::Uint32Array:
         case Array::Float32Array:
         case Array::Float64Array:
+            read(JSArrayBufferView_vector);
+            read(JSArrayBufferView_length);
             write(TypedArrayProperties);
             return;
         }
@@ -425,7 +429,14 @@
     case GetIndexedPropertyStorage:
         if (node->arrayMode().type() == Array::String)
             return;
-        read(TypedArrayStoragePointer);
+        read(JSArrayBufferView_vector);
+        return;
+        
+    case GetTypedArrayByteOffset:
+        read(JSArrayBufferView_vector);
+        read(JSArrayBufferView_mode);
+        read(Butterfly_arrayBuffer);
+        read(ArrayBuffer_data);
         return;
         
     case GetByOffset:
@@ -456,7 +467,7 @@
             return;
             
         default:
-            read(TypedArrayLength);
+            read(JSArrayBufferView_length);
             return;
         }
     }
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index cab0c23..99d15bb 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -729,12 +729,17 @@
         case GetByIdFlush: {
             if (!node->child1()->shouldSpeculateCell())
                 break;
-            if (m_graph.identifiers()[node->identifierNumber()] == vm().propertyNames->length.impl()) {
+            StringImpl* impl = m_graph.identifiers()[node->identifierNumber()];
+            if (impl == vm().propertyNames->length.impl()) {
                 attemptToMakeGetArrayLength(node);
                 break;
             }
-            if (m_graph.identifiers()[node->identifierNumber()] == vm().propertyNames->byteLength.impl()) {
-                attemptToMakeGetByteLength(node);
+            if (impl == vm().propertyNames->byteLength.impl()) {
+                attemptToMakeGetTypedArrayByteLength(node);
+                break;
+            }
+            if (impl == vm().propertyNames->byteOffset.impl()) {
+                attemptToMakeGetTypedArrayByteOffset(node);
                 break;
             }
             setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
@@ -825,6 +830,7 @@
         case GetArgument:
         case PhantomPutStructure:
         case GetIndexedPropertyStorage:
+        case GetTypedArrayByteOffset:
         case LastNodeType:
         case MovHint:
         case MovHintAndCheck:
@@ -1452,7 +1458,7 @@
         return true;
     }
     
-    bool attemptToMakeGetByteLength(Node* node)
+    bool attemptToMakeGetTypedArrayByteLength(Node* node)
     {
         if (!isInt32Speculation(node->prediction()))
             return false;
@@ -1476,7 +1482,6 @@
         // We can use a BitLShift here because typed arrays will never have a byteLength
         // that overflows int32.
         node->setOp(BitLShift);
-        ASSERT(node->flags() & NodeMustGenerate);
         node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
         observeUseKindOnNode(length, Int32Use);
         observeUseKindOnNode(shiftAmount, Int32Use);
@@ -1488,7 +1493,6 @@
     void convertToGetArrayLength(Node* node, ArrayMode arrayMode)
     {
         node->setOp(GetArrayLength);
-        ASSERT(node->flags() & NodeMustGenerate);
         node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
         setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child1());
         node->setArrayMode(arrayMode);
@@ -1507,6 +1511,25 @@
             m_indexInBlock, SpecInt32, GetArrayLength, codeOrigin,
             OpInfo(arrayMode.asWord()), Edge(child, KnownCellUse), Edge(storage));
     }
+    
+    bool attemptToMakeGetTypedArrayByteOffset(Node* node)
+    {
+        if (!isInt32Speculation(node->prediction()))
+            return false;
+        
+        TypedArrayType type = typedArrayTypeFromSpeculation(node->child1()->prediction());
+        if (!isTypedView(type))
+            return false;
+        
+        checkArray(
+            ArrayMode(toArrayType(type)), node->codeOrigin, node->child1().node(),
+            0, neverNeedsStorage);
+        
+        node->setOp(GetTypedArrayByteOffset);
+        node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
+        setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child1());
+        return true;
+    }
 
     BasicBlock* m_block;
     unsigned m_indexInBlock;
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index d30e4fc..9e3616b 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -154,6 +154,7 @@
     macro(GetByOffset, NodeResultJS) \
     macro(PutByOffset, NodeMustGenerate) \
     macro(GetArrayLength, NodeResultInt32) \
+    macro(GetTypedArrayByteOffset, NodeResultInt32) \
     macro(GetScope, NodeResultJS) \
     macro(GetMyScope, NodeResultJS) \
     macro(SetMyScope, NodeMustGenerate) \
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index a038bf4..cacdd7c 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -466,6 +466,7 @@
             
         case PutByValAlias:
         case GetArrayLength:
+        case GetTypedArrayByteOffset:
         case Int32ToDouble:
         case DoubleAsInt32:
         case GetLocalUnlinked:
diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
index d89c833..39e55ab 100644
--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
@@ -243,6 +243,9 @@
     case StringCharCodeAt:
         return node->arrayMode().alreadyChecked(graph, node, state.forNode(node->child1()));
         
+    case GetTypedArrayByteOffset:
+        return !(state.forNode(node->child1()).m_type & ~(SpecTypedArrayView));
+        
     case PutByVal:
     case PutByValAlias:
         return node->arrayMode().modeForPut().alreadyChecked(
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index dc09322..d615a4e 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -4032,6 +4032,37 @@
     storageResult(storageReg, node);
 }
 
+void SpeculativeJIT::compileGetTypedArrayByteOffset(Node* node)
+{
+    SpeculateCellOperand base(this, node->child1());
+    GPRTemporary vector(this);
+    GPRTemporary data(this);
+    
+    GPRReg baseGPR = base.gpr();
+    GPRReg vectorGPR = vector.gpr();
+    GPRReg dataGPR = data.gpr();
+    
+    JITCompiler::Jump emptyByteOffset = m_jit.branch32(
+        MacroAssembler::NotEqual,
+        MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfMode()),
+        TrustedImm32(WastefulTypedArray));
+    
+    m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), dataGPR);
+    m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfVector()), vectorGPR);
+    m_jit.loadPtr(MacroAssembler::Address(dataGPR, Butterfly::offsetOfArrayBuffer()), dataGPR);
+    m_jit.loadPtr(MacroAssembler::Address(dataGPR, ArrayBuffer::offsetOfData()), dataGPR);
+    m_jit.subPtr(dataGPR, vectorGPR);
+    
+    JITCompiler::Jump done = m_jit.jump();
+    
+    emptyByteOffset.link(&m_jit);
+    m_jit.move(TrustedImmPtr(0), vectorGPR);
+    
+    done.link(&m_jit);
+    
+    integerResult(vectorGPR, node);
+}
+
 void SpeculativeJIT::compileGetByValOnArguments(Node* node)
 {
     SpeculateCellOperand base(this, node->child1());
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 6262686..d87efe0 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -1973,6 +1973,7 @@
     void compileArithDiv(Node*);
     void compileArithMod(Node*);
     void compileGetIndexedPropertyStorage(Node*);
+    void compileGetTypedArrayByteOffset(Node*);
     void compileGetByValOnIntTypedArray(Node*, TypedArrayType);
     void compilePutByValForIntTypedArray(GPRReg base, GPRReg property, Node*, TypedArrayType);
     void compileGetByValOnFloatTypedArray(Node*, TypedArrayType);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index c3a2475e..b45c618 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -4027,6 +4027,11 @@
         break;
     }
 
+    case GetTypedArrayByteOffset: {
+        compileGetTypedArrayByteOffset(node);
+        break;
+    }
+        
     case GetByOffset: {
         StorageOperand storage(this, node->child1());
         GPRTemporary resultTag(this, storage);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 500babf..3364f09 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -3945,6 +3945,11 @@
         break;
     }
         
+    case GetTypedArrayByteOffset: {
+        compileGetTypedArrayByteOffset(node);
+        break;
+    }
+        
     case GetByOffset: {
         StorageOperand storage(this, node->child1());
         GPRTemporary result(this, storage);
diff --git a/Source/JavaScriptCore/dfg/DFGTypeCheckHoistingPhase.cpp b/Source/JavaScriptCore/dfg/DFGTypeCheckHoistingPhase.cpp
index 2254bf9..c2230e3 100644
--- a/Source/JavaScriptCore/dfg/DFGTypeCheckHoistingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGTypeCheckHoistingPhase.cpp
@@ -254,6 +254,7 @@
                 case GetArrayLength:
                 case CheckArray:
                 case GetIndexedPropertyStorage:
+                case GetTypedArrayByteOffset:
                 case Phantom:
                     // Don't count these uses.
                     break;
diff --git a/Source/JavaScriptCore/runtime/ArrayBuffer.h b/Source/JavaScriptCore/runtime/ArrayBuffer.h
index 8977573..204df41 100644
--- a/Source/JavaScriptCore/runtime/ArrayBuffer.h
+++ b/Source/JavaScriptCore/runtime/ArrayBuffer.h
@@ -113,6 +113,8 @@
 
     JS_EXPORT_PRIVATE bool transfer(ArrayBufferContents&);
     bool isNeutered() { return !m_contents.m_data; }
+    
+    static ptrdiff_t offsetOfData() { return OBJECT_OFFSETOF(ArrayBuffer, m_contents) + OBJECT_OFFSETOF(ArrayBufferContents, m_data); }
 
     ~ArrayBuffer() { }
 
diff --git a/Source/JavaScriptCore/runtime/Butterfly.h b/Source/JavaScriptCore/runtime/Butterfly.h
index 3fc0077..ded85fc 100644
--- a/Source/JavaScriptCore/runtime/Butterfly.h
+++ b/Source/JavaScriptCore/runtime/Butterfly.h
@@ -101,6 +101,7 @@
     char* pointer() { return reinterpret_cast<char*>(this); }
     
     static ptrdiff_t offsetOfIndexingHeader() { return IndexingHeader::offsetOfIndexingHeader(); }
+    static ptrdiff_t offsetOfArrayBuffer() { return offsetOfIndexingHeader() + IndexingHeader::offsetOfArrayBuffer(); }
     static ptrdiff_t offsetOfPublicLength() { return offsetOfIndexingHeader() + IndexingHeader::offsetOfPublicLength(); }
     static ptrdiff_t offsetOfVectorLength() { return offsetOfIndexingHeader() + IndexingHeader::offsetOfVectorLength(); }
     
diff --git a/Source/JavaScriptCore/runtime/IndexingHeader.h b/Source/JavaScriptCore/runtime/IndexingHeader.h
index fefaaf6..2788129 100644
--- a/Source/JavaScriptCore/runtime/IndexingHeader.h
+++ b/Source/JavaScriptCore/runtime/IndexingHeader.h
@@ -45,6 +45,7 @@
     
     static ptrdiff_t offsetOfIndexingHeader() { return -static_cast<ptrdiff_t>(sizeof(IndexingHeader)); }
     
+    static ptrdiff_t offsetOfArrayBuffer() { return OBJECT_OFFSETOF(IndexingHeader, u.typedArray.buffer); }
     static ptrdiff_t offsetOfPublicLength() { return OBJECT_OFFSETOF(IndexingHeader, u.lengths.publicLength); }
     static ptrdiff_t offsetOfVectorLength() { return OBJECT_OFFSETOF(IndexingHeader, u.lengths.vectorLength); }