DFG should inline new typedArray()
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 21 Aug 2013 19:43:47 +0000 (19:43 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 21 Aug 2013 19:43:47 +0000 (19:43 +0000)
https://bugs.webkit.org/show_bug.cgi?id=120022

Source/JavaScriptCore:

Reviewed by Oliver Hunt.

Adds inlining of typed array allocations in the DFG. Any operation of the
form:

    new foo(blah)

or:

    foo(blah)

where 'foo' is a typed array constructor and 'blah' is exactly one argument,
is turned into the NewTypedArray intrinsic. Later, of child1 (i.e. 'blah')
is predicted integer, we generate inline code for an allocation. Otherwise
it turns into a call to an operation that behaves like the constructor would
if it was passed one argument (i.e. it may wrap a buffer or it may create a
copy or another array, or it may allocate an array of that length).

* bytecode/SpeculatedType.cpp:
(JSC::speculationFromTypedArrayType):
(JSC::speculationFromClassInfo):
* bytecode/SpeculatedType.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::::executeEffects):
* dfg/DFGBackwardsPropagationPhase.cpp:
(JSC::DFG::BackwardsPropagationPhase::propagate):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleTypedArrayConstructor):
(JSC::DFG::ByteCodeParser::handleConstantInternalFunction):
* dfg/DFGCCallHelpers.h:
(JSC::DFG::CCallHelpers::setupArgumentsWithExecState):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::putStructureStoreElimination):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasTypedArrayType):
(JSC::DFG::Node::typedArrayType):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
(JSC::DFG::newTypedArrayWithSize):
(JSC::DFG::newTypedArrayWithOneArgument):
* dfg/DFGOperations.h:
(JSC::DFG::operationNewTypedArrayWithSizeForType):
(JSC::DFG::operationNewTypedArrayWithOneArgumentForType):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileNewTypedArray):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_new_object):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_new_object):
* runtime/JSArray.h:
(JSC::JSArray::allocationSize):
* runtime/JSArrayBufferView.h:
(JSC::JSArrayBufferView::allocationSize):
* runtime/JSGenericTypedArrayViewConstructorInlines.h:
(JSC::constructGenericTypedArrayView):
* runtime/JSObject.h:
(JSC::JSFinalObject::allocationSize):
* runtime/TypedArrayType.cpp:
(JSC::constructorClassInfoForType):
* runtime/TypedArrayType.h:
(JSC::indexToTypedArrayType):

LayoutTests:

Reviewed by Oliver Hunt.

* fast/js/regress/Float64Array-alloc-long-lived-expected.txt: Added.
* fast/js/regress/Float64Array-alloc-long-lived.html: Added.
* fast/js/regress/Int16Array-alloc-long-lived-expected.txt: Added.
* fast/js/regress/Int16Array-alloc-long-lived.html: Added.
* fast/js/regress/Int8Array-alloc-long-lived-expected.txt: Added.
* fast/js/regress/Int8Array-alloc-long-lived.html: Added.
* fast/js/regress/script-tests/Float64Array-alloc-long-lived.js: Added.
* fast/js/regress/script-tests/Int16Array-alloc-long-lived.js: Added.
* fast/js/regress/script-tests/Int32Array-alloc-long-lived.js:
* fast/js/regress/script-tests/Int8Array-alloc-long-lived.js: Added.

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

40 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/js/regress/Float64Array-alloc-long-lived-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/regress/Float64Array-alloc-long-lived.html [new file with mode: 0644]
LayoutTests/fast/js/regress/Int16Array-alloc-long-lived-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/regress/Int16Array-alloc-long-lived.html [new file with mode: 0644]
LayoutTests/fast/js/regress/Int8Array-alloc-long-lived-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/regress/Int8Array-alloc-long-lived.html [new file with mode: 0644]
LayoutTests/fast/js/regress/script-tests/Float64Array-alloc-long-lived.js [new file with mode: 0644]
LayoutTests/fast/js/regress/script-tests/Int16Array-alloc-long-lived.js [new file with mode: 0644]
LayoutTests/fast/js/regress/script-tests/Int32Array-alloc-long-lived.js
LayoutTests/fast/js/regress/script-tests/Int8Array-alloc-long-lived.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/SpeculatedType.cpp
Source/JavaScriptCore/bytecode/SpeculatedType.h
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCCallHelpers.h
Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGGraph.cpp
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/jit/JITOpcodes.cpp
Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
Source/JavaScriptCore/runtime/JSArray.h
Source/JavaScriptCore/runtime/JSArrayBufferView.h
Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructorInlines.h
Source/JavaScriptCore/runtime/JSObject.h
Source/JavaScriptCore/runtime/TypedArrayType.cpp
Source/JavaScriptCore/runtime/TypedArrayType.h

index 0fdd119..c2e8c8e 100644 (file)
@@ -1,3 +1,21 @@
+2013-08-20  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG should inline new typedArray()
+        https://bugs.webkit.org/show_bug.cgi?id=120022
+
+        Reviewed by Oliver Hunt.
+
+        * fast/js/regress/Float64Array-alloc-long-lived-expected.txt: Added.
+        * fast/js/regress/Float64Array-alloc-long-lived.html: Added.
+        * fast/js/regress/Int16Array-alloc-long-lived-expected.txt: Added.
+        * fast/js/regress/Int16Array-alloc-long-lived.html: Added.
+        * fast/js/regress/Int8Array-alloc-long-lived-expected.txt: Added.
+        * fast/js/regress/Int8Array-alloc-long-lived.html: Added.
+        * fast/js/regress/script-tests/Float64Array-alloc-long-lived.js: Added.
+        * fast/js/regress/script-tests/Int16Array-alloc-long-lived.js: Added.
+        * fast/js/regress/script-tests/Int32Array-alloc-long-lived.js:
+        * fast/js/regress/script-tests/Int8Array-alloc-long-lived.js: Added.
+
 2013-08-21  Tim Horton  <timothy_horton@apple.com>
 
         <https://webkit.org/b/120099> Assertion failure in JSC::SlotVisitor::copyLater when marking DataView
diff --git a/LayoutTests/fast/js/regress/Float64Array-alloc-long-lived-expected.txt b/LayoutTests/fast/js/regress/Float64Array-alloc-long-lived-expected.txt
new file mode 100644 (file)
index 0000000..e9fd082
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/Float64Array-alloc-long-lived
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/regress/Float64Array-alloc-long-lived.html b/LayoutTests/fast/js/regress/Float64Array-alloc-long-lived.html
new file mode 100644 (file)
index 0000000..84c123f
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/regress-pre.js"></script>
+<script src="script-tests/Float64Array-alloc-long-lived.js"></script>
+<script src="resources/regress-post.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/regress/Int16Array-alloc-long-lived-expected.txt b/LayoutTests/fast/js/regress/Int16Array-alloc-long-lived-expected.txt
new file mode 100644 (file)
index 0000000..8c4e9c4
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/Int16Array-alloc-long-lived
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/regress/Int16Array-alloc-long-lived.html b/LayoutTests/fast/js/regress/Int16Array-alloc-long-lived.html
new file mode 100644 (file)
index 0000000..02101af
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/regress-pre.js"></script>
+<script src="script-tests/Int16Array-alloc-long-lived.js"></script>
+<script src="resources/regress-post.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/regress/Int8Array-alloc-long-lived-expected.txt b/LayoutTests/fast/js/regress/Int8Array-alloc-long-lived-expected.txt
new file mode 100644 (file)
index 0000000..fbdbc3b
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/Int8Array-alloc-long-lived
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/regress/Int8Array-alloc-long-lived.html b/LayoutTests/fast/js/regress/Int8Array-alloc-long-lived.html
new file mode 100644 (file)
index 0000000..88eac16
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/regress-pre.js"></script>
+<script src="script-tests/Int8Array-alloc-long-lived.js"></script>
+<script src="resources/regress-post.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/regress/script-tests/Float64Array-alloc-long-lived.js b/LayoutTests/fast/js/regress/script-tests/Float64Array-alloc-long-lived.js
new file mode 100644 (file)
index 0000000..645df1f
--- /dev/null
@@ -0,0 +1,14 @@
+var array = new Array(100000);
+
+for (var i = 0; i < 2000000; ++i)
+    array[i % array.length] = new Float64Array(9);
+
+for (var i = 0; i < array.length; ++i) {
+    var subArray = array[i];
+    if (subArray.length != 9)
+        throw "Error: bad array length: " + subArray.length;
+    for (var j = 0; j < subArray.length; ++j) {
+        if (subArray[j] != 0)
+            throw "Error: array at " + i + " has non-zero element: " + Array.prototype.join.call(subArray, ",");
+    }
+}
diff --git a/LayoutTests/fast/js/regress/script-tests/Int16Array-alloc-long-lived.js b/LayoutTests/fast/js/regress/script-tests/Int16Array-alloc-long-lived.js
new file mode 100644 (file)
index 0000000..6b25c79
--- /dev/null
@@ -0,0 +1,14 @@
+var array = new Array(100000);
+
+for (var i = 0; i < 2000000; ++i)
+    array[i % array.length] = new Int16Array(9);
+
+for (var i = 0; i < array.length; ++i) {
+    var subArray = array[i];
+    if (subArray.length != 9)
+        throw "Error: bad array length: " + subArray.length;
+    for (var j = 0; j < subArray.length; ++j) {
+        if (subArray[j] != 0)
+            throw "Error: array at " + i + " has non-zero element: " + Array.prototype.join.call(subArray, ",");
+    }
+}
index 85046de..3c08294 100644 (file)
@@ -1,9 +1,14 @@
 var array = new Array(100000);
 
 for (var i = 0; i < 2000000; ++i)
-    array[i % array.length] = new Int32Array(10);
+    array[i % array.length] = new Int32Array(9);
 
 for (var i = 0; i < array.length; ++i) {
-    if (array[i].length != 10)
-        throw "Error: bad array length: " + array[i].length;
+    var subArray = array[i];
+    if (subArray.length != 9)
+        throw "Error: bad array length: " + subArray.length;
+    for (var j = 0; j < subArray.length; ++j) {
+        if (subArray[j] != 0)
+            throw "Error: array at " + i + " has non-zero element: " + Array.prototype.join.call(subArray, ",");
+    }
 }
diff --git a/LayoutTests/fast/js/regress/script-tests/Int8Array-alloc-long-lived.js b/LayoutTests/fast/js/regress/script-tests/Int8Array-alloc-long-lived.js
new file mode 100644 (file)
index 0000000..f4e19ce
--- /dev/null
@@ -0,0 +1,14 @@
+var array = new Array(100000);
+
+for (var i = 0; i < 2000000; ++i)
+    array[i % array.length] = new Int8Array(9);
+
+for (var i = 0; i < array.length; ++i) {
+    var subArray = array[i];
+    if (subArray.length != 9)
+        throw "Error: bad array length: " + subArray.length;
+    for (var j = 0; j < subArray.length; ++j) {
+        if (subArray[j] != 0)
+            throw "Error: array at " + i + " has non-zero element: " + Array.prototype.join.call(subArray, ",");
+    }
+}
index d36f706..2cd7f92 100644 (file)
@@ -1,3 +1,86 @@
+2013-08-20  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG should inline new typedArray()
+        https://bugs.webkit.org/show_bug.cgi?id=120022
+
+        Reviewed by Oliver Hunt.
+        
+        Adds inlining of typed array allocations in the DFG. Any operation of the
+        form:
+        
+            new foo(blah)
+        
+        or:
+        
+            foo(blah)
+        
+        where 'foo' is a typed array constructor and 'blah' is exactly one argument,
+        is turned into the NewTypedArray intrinsic. Later, of child1 (i.e. 'blah')
+        is predicted integer, we generate inline code for an allocation. Otherwise
+        it turns into a call to an operation that behaves like the constructor would
+        if it was passed one argument (i.e. it may wrap a buffer or it may create a
+        copy or another array, or it may allocate an array of that length).
+
+        * bytecode/SpeculatedType.cpp:
+        (JSC::speculationFromTypedArrayType):
+        (JSC::speculationFromClassInfo):
+        * bytecode/SpeculatedType.h:
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::::executeEffects):
+        * dfg/DFGBackwardsPropagationPhase.cpp:
+        (JSC::DFG::BackwardsPropagationPhase::propagate):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleTypedArrayConstructor):
+        (JSC::DFG::ByteCodeParser::handleConstantInternalFunction):
+        * dfg/DFGCCallHelpers.h:
+        (JSC::DFG::CCallHelpers::setupArgumentsWithExecState):
+        * dfg/DFGCSEPhase.cpp:
+        (JSC::DFG::CSEPhase::putStructureStoreElimination):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::dump):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasTypedArrayType):
+        (JSC::DFG::Node::typedArrayType):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        (JSC::DFG::newTypedArrayWithSize):
+        (JSC::DFG::newTypedArrayWithOneArgument):
+        * dfg/DFGOperations.h:
+        (JSC::DFG::operationNewTypedArrayWithSizeForType):
+        (JSC::DFG::operationNewTypedArrayWithOneArgumentForType):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileNewTypedArray):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperation):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_new_object):
+        * jit/JITOpcodes32_64.cpp:
+        (JSC::JIT::emit_op_new_object):
+        * runtime/JSArray.h:
+        (JSC::JSArray::allocationSize):
+        * runtime/JSArrayBufferView.h:
+        (JSC::JSArrayBufferView::allocationSize):
+        * runtime/JSGenericTypedArrayViewConstructorInlines.h:
+        (JSC::constructGenericTypedArrayView):
+        * runtime/JSObject.h:
+        (JSC::JSFinalObject::allocationSize):
+        * runtime/TypedArrayType.cpp:
+        (JSC::constructorClassInfoForType):
+        * runtime/TypedArrayType.h:
+        (JSC::indexToTypedArrayType):
+
 2013-08-21  Julien Brianceau  <jbrianceau@nds.com>
 
         <https://webkit.org/b/120106> Fix V_DFGOperation_EJPP signature in DFG.
index bb9cab5..4fef9a9 100644 (file)
@@ -249,24 +249,9 @@ void dumpSpeculationAbbreviated(PrintStream& out, SpeculatedType value)
     out.print(speculationToAbbreviatedString(value));
 }
 
-SpeculatedType speculationFromClassInfo(const ClassInfo* classInfo)
+SpeculatedType speculationFromTypedArrayType(TypedArrayType type)
 {
-    if (classInfo == JSFinalObject::info())
-        return SpecFinalObject;
-    
-    if (classInfo == JSArray::info())
-        return SpecArray;
-    
-    if (classInfo == Arguments::info())
-        return SpecArguments;
-    
-    if (classInfo == StringObject::info())
-        return SpecStringObject;
-    
-    if (classInfo->isSubClassOf(JSFunction::info()))
-        return SpecFunction;
-    
-    switch (classInfo->typedArrayStorageType) {
+    switch (type) {
     case TypeInt8:
         return SpecInt8Array;
     case TypeInt16:
@@ -285,9 +270,33 @@ SpeculatedType speculationFromClassInfo(const ClassInfo* classInfo)
         return SpecFloat32Array;
     case TypeFloat64:
         return SpecFloat64Array;
-    default:
+    case NotTypedArray:
+    case TypeDataView:
         break;
     }
+    RELEASE_ASSERT_NOT_REACHED();
+    return SpecNone;
+}
+
+SpeculatedType speculationFromClassInfo(const ClassInfo* classInfo)
+{
+    if (classInfo == JSFinalObject::info())
+        return SpecFinalObject;
+    
+    if (classInfo == JSArray::info())
+        return SpecArray;
+    
+    if (classInfo == Arguments::info())
+        return SpecArguments;
+    
+    if (classInfo == StringObject::info())
+        return SpecStringObject;
+    
+    if (classInfo->isSubClassOf(JSFunction::info()))
+        return SpecFunction;
+    
+    if (isTypedView(classInfo->typedArrayStorageType))
+        return speculationFromTypedArrayType(classInfo->typedArrayStorageType);
     
     if (classInfo->isSubClassOf(JSObject::info()))
         return SpecObjectOther;
index 803e7a8..3a02e93 100644 (file)
@@ -332,6 +332,7 @@ SpeculatedType speculationFromStructure(Structure*);
 SpeculatedType speculationFromCell(JSCell*);
 SpeculatedType speculationFromValue(JSValue);
 
+SpeculatedType speculationFromTypedArrayType(TypedArrayType); // only valid for typed views.
 TypedArrayType typedArrayTypeFromSpeculation(SpeculatedType);
 
 } // namespace JSC
index 4a5d46d..c721d36 100644 (file)
@@ -1043,6 +1043,24 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         forNode(node).setType(SpecArray);
         m_state.setHaveStructures(true);
         break;
+        
+    case NewTypedArray:
+        switch (node->child1().useKind()) {
+        case Int32Use:
+            break;
+        case UntypedUse:
+            clobberWorld(node->codeOrigin, clobberLimit);
+            break;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+        }
+        forNode(node).set(
+            m_graph,
+            m_graph.globalObjectFor(node->codeOrigin)->typedArrayStructure(
+                node->typedArrayType()));
+        m_state.setHaveStructures(true);
+        break;
             
     case NewRegexp:
         forNode(node).set(m_graph, m_graph.globalObjectFor(node->codeOrigin)->regExpStructure());
index 2d4894e..effc320 100644 (file)
@@ -324,6 +324,14 @@ private:
             break;
         }
             
+        case NewTypedArray: {
+            // Negative zero is not observable. NaN versus undefined are only observable
+            // in that you would get a different exception message. So, like, whatever: we
+            // claim here that NaN v. undefined is observable.
+            node->child1()->mergeFlags(NodeUsedAsInt | NodeUsedAsNumber | NodeUsedAsOther);
+            break;
+        }
+            
         case StringCharAt: {
             node->child1()->mergeFlags(NodeUsedAsValue);
             node->child2()->mergeFlags(NodeUsedAsValue | NodeUsedAsInt);
index 0977c04..9d11850 100644 (file)
@@ -168,6 +168,7 @@ private:
     bool handleInlining(Node* callTargetNode, int resultOperand, const CallLinkStatus&, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, CodeSpecializationKind);
     // Handle intrinsic functions. Return true if it succeeded, false if we need to plant a call.
     bool handleIntrinsic(int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction);
+    bool handleTypedArrayConstructor(int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, TypedArrayType);
     bool handleConstantInternalFunction(int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, CodeSpecializationKind);
     Node* handlePutByOffset(Node* base, unsigned identifier, PropertyOffset, Node* value);
     Node* handleGetByOffset(SpeculatedType, Node* base, unsigned identifierNumber, PropertyOffset);
@@ -1588,6 +1589,58 @@ bool ByteCodeParser::handleIntrinsic(int resultOperand, Intrinsic intrinsic, int
     }
 }
 
+bool ByteCodeParser::handleTypedArrayConstructor(
+    int resultOperand, InternalFunction* function, int registerOffset,
+    int argumentCountIncludingThis, TypedArrayType type)
+{
+    if (!isTypedView(type))
+        return false;
+    
+    if (function->classInfo() != constructorClassInfoForType(type))
+        return false;
+    
+    if (function->globalObject() != m_inlineStackTop->m_codeBlock->globalObject())
+        return false;
+    
+    // We only have an intrinsic for the case where you say:
+    //
+    // new FooArray(blah);
+    //
+    // Of course, 'blah' could be any of the following:
+    //
+    // - Integer, indicating that you want to allocate an array of that length.
+    //   This is the thing we're hoping for, and what we can actually do meaningful
+    //   optimizations for.
+    //
+    // - Array buffer, indicating that you want to create a view onto that _entire_
+    //   buffer.
+    //
+    // - Non-buffer object, indicating that you want to create a copy of that
+    //   object by pretending that it quacks like an array.
+    //
+    // - Anything else, indicating that you want to have an exception thrown at
+    //   you.
+    //
+    // The intrinsic, NewTypedArray, will behave as if it could do any of these
+    // things up until we do Fixup. Thereafter, if child1 (i.e. 'blah') is
+    // predicted Int32, then we lock it in as a normal typed array allocation.
+    // Otherwise, NewTypedArray turns into a totally opaque function call that
+    // may clobber the world - by virtue of it accessing properties on what could
+    // be an object.
+    //
+    // Note that although the generic form of NewTypedArray sounds sort of awful,
+    // it is actually quite likely to be more efficient than a fully generic
+    // Construct. So, we might want to think about making NewTypedArray variadic,
+    // or else making Construct not super slow.
+    
+    if (argumentCountIncludingThis != 2)
+        return false;
+    
+    set(resultOperand,
+        addToGraph(NewTypedArray, OpInfo(type), get(registerOffset + argumentToOperand(1))));
+    return true;
+}
+
 bool ByteCodeParser::handleConstantInternalFunction(
     int resultOperand, InternalFunction* function, int registerOffset,
     int argumentCountIncludingThis, SpeculatedType prediction, CodeSpecializationKind kind)
@@ -1616,7 +1669,9 @@ bool ByteCodeParser::handleConstantInternalFunction(
         set(resultOperand,
             addToGraph(Node::VarArg, NewArray, OpInfo(ArrayWithUndecided), OpInfo(0)));
         return true;
-    } else if (function->classInfo() == StringConstructor::info()) {
+    }
+    
+    if (function->classInfo() == StringConstructor::info()) {
         Node* result;
         
         if (argumentCountIncludingThis <= 1)
@@ -1631,6 +1686,14 @@ bool ByteCodeParser::handleConstantInternalFunction(
         return true;
     }
     
+    for (unsigned typeIndex = 0; typeIndex < NUMBER_OF_TYPED_ARRAY_TYPES; ++typeIndex) {
+        bool result = handleTypedArrayConstructor(
+            resultOperand, function, registerOffset, argumentCountIncludingThis,
+            indexToTypedArrayType(typeIndex));
+        if (result)
+            return true;
+    }
+    
     return false;
 }
 
index 93c8386..c777b67 100644 (file)
@@ -228,6 +228,15 @@ public:
         addCallArgument(arg3);
     }
 
+    ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, GPRReg arg2, GPRReg arg3)
+    {
+        resetCallArguments();
+        addCallArgument(GPRInfo::callFrameRegister);
+        addCallArgument(arg1);
+        addCallArgument(arg2);
+        addCallArgument(arg3);
+    }
+
     ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, TrustedImmPtr arg2, TrustedImmPtr arg3)
     {
         resetCallArguments();
@@ -847,6 +856,13 @@ public:
         move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
     }
 
+    ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, GPRReg arg2, GPRReg arg3)
+    {
+        setupTwoStubArgs<GPRInfo::argumentGPR2, GPRInfo::argumentGPR3>(arg2, arg3);
+        move(arg1, GPRInfo::argumentGPR1);
+        move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+    }
+
     ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, TrustedImmPtr arg2, TrustedImmPtr arg3)
     {
         move(arg1, GPRInfo::argumentGPR1);
index d51ca8e..b0c12c4 100644 (file)
@@ -585,6 +585,7 @@ private:
             case ToString:
             case NewStringObject:
             case MakeRope:
+            case NewTypedArray:
                 return 0;
                 
             // This either exits, causes a GC (lazy string allocation), or clobbers
index 5efd6ca..0ed6490 100644 (file)
@@ -519,6 +519,21 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
         write(GCState);
         return;
         
+    case NewTypedArray:
+        switch (node->child1().useKind()) {
+        case Int32Use:
+            read(GCState);
+            write(GCState);
+            return;
+        case UntypedUse:
+            read(World);
+            write(World);
+            return;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            return;
+        }
+        
     case RegExpExec:
     case RegExpTest:
         read(RegExpState);
index 49ee963..ddaa642 100644 (file)
@@ -673,6 +673,15 @@ private:
             break;
         }
             
+        case NewTypedArray: {
+            if (node->child1()->shouldSpeculateInteger()) {
+                setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
+                node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
+                break;
+            }
+            break;
+        }
+            
         case NewArrayWithSize: {
             setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
             break;
index 25af440..8baa03c 100644 (file)
@@ -246,6 +246,8 @@ void Graph::dump(PrintStream& out, const char* prefix, Node* node, DumpContext*
     }
     if (node->hasIndexingType())
         out.print(comma, IndexingTypeDump(node->indexingType()));
+    if (node->hasTypedArrayType())
+        out.print(comma, node->typedArrayType());
     if (node->hasPhi())
         out.print(comma, "^", node->phi()->index());
     if (node->hasExecutionCounter())
index a99a8f0..d898b70 100644 (file)
@@ -635,6 +635,24 @@ struct Node {
         return m_opInfo;
     }
     
+    bool hasTypedArrayType()
+    {
+        switch (op()) {
+        case NewTypedArray:
+            return true;
+        default:
+            return false;
+        }
+    }
+    
+    TypedArrayType typedArrayType()
+    {
+        ASSERT(hasTypedArrayType());
+        TypedArrayType result = static_cast<TypedArrayType>(m_opInfo);
+        ASSERT(isTypedView(result));
+        return result;
+    }
+    
     bool hasInlineCapacity()
     {
         return op() == CreateThis;
index 9e3616b..6f6a462 100644 (file)
@@ -202,6 +202,7 @@ namespace JSC { namespace DFG {
     macro(NewArray, NodeResultJS | NodeHasVarArgs) \
     macro(NewArrayWithSize, NodeResultJS) \
     macro(NewArrayBuffer, NodeResultJS) \
+    macro(NewTypedArray, NodeResultJS | NodeClobbersWorld | NodeMustGenerate) \
     macro(NewRegexp, NodeResultJS) \
     \
     /* Nodes for misc operations. */\
index 39516de..df37f1b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -46,6 +46,7 @@
 #include "ObjectConstructor.h"
 #include "Operations.h"
 #include "StringConstructor.h"
+#include "TypedArrayInlines.h"
 #include <wtf/InlineASM.h>
 
 #if ENABLE(JIT)
@@ -387,6 +388,76 @@ ALWAYS_INLINE static void DFG_OPERATION operationPutByValInternal(ExecState* exe
     }
 }
 
+template<typename ViewClass>
+char* newTypedArrayWithSize(ExecState* exec, Structure* structure, int32_t size)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    if (size < 0) {
+        throwError(exec, createRangeError(exec, "Requested length is negative"));
+        return 0;
+    }
+    return bitwise_cast<char*>(ViewClass::create(exec, structure, size));
+}
+
+template<typename ViewClass>
+char* newTypedArrayWithOneArgument(
+    ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    
+    JSValue value = JSValue::decode(encodedValue);
+    
+    if (JSArrayBuffer* jsBuffer = jsDynamicCast<JSArrayBuffer*>(value)) {
+        RefPtr<ArrayBuffer> buffer = jsBuffer->impl();
+        
+        if (buffer->byteLength() % ViewClass::elementSize) {
+            throwError(exec, createRangeError(exec, "ArrayBuffer length minus the byteOffset is not a multiple of the element size"));
+            return 0;
+        }
+        return bitwise_cast<char*>(
+            ViewClass::create(
+                exec, structure, buffer, 0, buffer->byteLength() / ViewClass::elementSize));
+    }
+    
+    if (JSObject* object = jsDynamicCast<JSObject*>(value)) {
+        unsigned length = object->get(exec, vm.propertyNames->length).toUInt32(exec);
+        if (exec->hadException())
+            return 0;
+        
+        ViewClass* result = ViewClass::createUninitialized(exec, structure, length);
+        if (!result)
+            return 0;
+        
+        if (!result->set(exec, object, 0, length))
+            return 0;
+        
+        return bitwise_cast<char*>(result);
+    }
+    
+    int length;
+    if (value.isInt32())
+        length = value.asInt32();
+    else if (!value.isNumber()) {
+        throwError(exec, createTypeError(exec, "Invalid array length argument"));
+        return 0;
+    } else {
+        length = static_cast<int>(value.asNumber());
+        if (length != value.asNumber()) {
+            throwError(exec, createTypeError(exec, "Invalid array length argument (fractional lengths not allowed)"));
+            return 0;
+        }
+    }
+    
+    if (length < 0) {
+        throwError(exec, createRangeError(exec, "Requested length is negative"));
+        return 0;
+    }
+    
+    return bitwise_cast<char*>(ViewClass::create(exec, structure, length));
+}
+
 extern "C" {
 
 EncodedJSValue DFG_OPERATION operationToThis(ExecState* exec, EncodedJSValue encodedOp)
@@ -1366,6 +1437,114 @@ char* DFG_OPERATION operationNewArrayBuffer(ExecState* exec, Structure* arrayStr
     return bitwise_cast<char*>(constructArray(exec, arrayStructure, exec->codeBlock()->constantBuffer(start), size));
 }
 
+char* DFG_OPERATION operationNewInt8ArrayWithSize(
+    ExecState* exec, Structure* structure, int32_t length)
+{
+    return newTypedArrayWithSize<JSInt8Array>(exec, structure, length);
+}
+
+char* DFG_OPERATION operationNewInt8ArrayWithOneArgument(
+    ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
+{
+    return newTypedArrayWithOneArgument<JSInt8Array>(exec, structure, encodedValue);
+}
+
+char* DFG_OPERATION operationNewInt16ArrayWithSize(
+    ExecState* exec, Structure* structure, int32_t length)
+{
+    return newTypedArrayWithSize<JSInt16Array>(exec, structure, length);
+}
+
+char* DFG_OPERATION operationNewInt16ArrayWithOneArgument(
+    ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
+{
+    return newTypedArrayWithOneArgument<JSInt16Array>(exec, structure, encodedValue);
+}
+
+char* DFG_OPERATION operationNewInt32ArrayWithSize(
+    ExecState* exec, Structure* structure, int32_t length)
+{
+    return newTypedArrayWithSize<JSInt32Array>(exec, structure, length);
+}
+
+char* DFG_OPERATION operationNewInt32ArrayWithOneArgument(
+    ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
+{
+    return newTypedArrayWithOneArgument<JSInt32Array>(exec, structure, encodedValue);
+}
+
+char* DFG_OPERATION operationNewUint8ArrayWithSize(
+    ExecState* exec, Structure* structure, int32_t length)
+{
+    return newTypedArrayWithSize<JSUint8Array>(exec, structure, length);
+}
+
+char* DFG_OPERATION operationNewUint8ArrayWithOneArgument(
+    ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
+{
+    return newTypedArrayWithOneArgument<JSUint8Array>(exec, structure, encodedValue);
+}
+
+char* DFG_OPERATION operationNewUint8ClampedArrayWithSize(
+    ExecState* exec, Structure* structure, int32_t length)
+{
+    return newTypedArrayWithSize<JSUint8ClampedArray>(exec, structure, length);
+}
+
+char* DFG_OPERATION operationNewUint8ClampedArrayWithOneArgument(
+    ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
+{
+    return newTypedArrayWithOneArgument<JSUint8ClampedArray>(exec, structure, encodedValue);
+}
+
+char* DFG_OPERATION operationNewUint16ArrayWithSize(
+    ExecState* exec, Structure* structure, int32_t length)
+{
+    return newTypedArrayWithSize<JSUint16Array>(exec, structure, length);
+}
+
+char* DFG_OPERATION operationNewUint16ArrayWithOneArgument(
+    ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
+{
+    return newTypedArrayWithOneArgument<JSUint16Array>(exec, structure, encodedValue);
+}
+
+char* DFG_OPERATION operationNewUint32ArrayWithSize(
+    ExecState* exec, Structure* structure, int32_t length)
+{
+    return newTypedArrayWithSize<JSUint32Array>(exec, structure, length);
+}
+
+char* DFG_OPERATION operationNewUint32ArrayWithOneArgument(
+    ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
+{
+    return newTypedArrayWithOneArgument<JSUint32Array>(exec, structure, encodedValue);
+}
+
+char* DFG_OPERATION operationNewFloat32ArrayWithSize(
+    ExecState* exec, Structure* structure, int32_t length)
+{
+    return newTypedArrayWithSize<JSFloat32Array>(exec, structure, length);
+}
+
+char* DFG_OPERATION operationNewFloat32ArrayWithOneArgument(
+    ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
+{
+    return newTypedArrayWithOneArgument<JSFloat32Array>(exec, structure, encodedValue);
+}
+
+char* DFG_OPERATION operationNewFloat64ArrayWithSize(
+    ExecState* exec, Structure* structure, int32_t length)
+{
+    return newTypedArrayWithSize<JSFloat64Array>(exec, structure, length);
+}
+
+char* DFG_OPERATION operationNewFloat64ArrayWithOneArgument(
+    ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
+{
+    return newTypedArrayWithOneArgument<JSFloat64Array>(exec, structure, encodedValue);
+}
+
 EncodedJSValue DFG_OPERATION operationNewRegexp(ExecState* exec, void* regexpPtr)
 {
     VM& vm = exec->vm();
index 444fd4b..c9d35a3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -122,6 +122,7 @@ typedef char* DFG_OPERATION (*P_DFGOperation_EPS)(ExecState*, void*, size_t);
 typedef char* DFG_OPERATION (*P_DFGOperation_ES)(ExecState*, size_t);
 typedef char* DFG_OPERATION (*P_DFGOperation_ESJss)(ExecState*, size_t, JSString*);
 typedef char* DFG_OPERATION (*P_DFGOperation_ESt)(ExecState*, Structure*);
+typedef char* DFG_OPERATION (*P_DFGOperation_EStJ)(ExecState*, Structure*, EncodedJSValue);
 typedef char* DFG_OPERATION (*P_DFGOperation_EStPS)(ExecState*, Structure*, void*, size_t);
 typedef char* DFG_OPERATION (*P_DFGOperation_EStSS)(ExecState*, Structure*, size_t, size_t);
 typedef char* DFG_OPERATION (*P_DFGOperation_EStZ)(ExecState*, Structure*, int32_t);
@@ -152,6 +153,24 @@ char* DFG_OPERATION operationNewArray(ExecState*, Structure*, void*, size_t) WTF
 char* DFG_OPERATION operationNewArrayBuffer(ExecState*, Structure*, size_t, size_t) WTF_INTERNAL;
 char* DFG_OPERATION operationNewEmptyArray(ExecState*, Structure*) WTF_INTERNAL;
 char* DFG_OPERATION operationNewArrayWithSize(ExecState*, Structure*, int32_t) WTF_INTERNAL;
+char* DFG_OPERATION operationNewInt8ArrayWithSize(ExecState*, Structure*, int32_t) WTF_INTERNAL;
+char* DFG_OPERATION operationNewInt8ArrayWithOneArgument(ExecState*, Structure*, EncodedJSValue) WTF_INTERNAL;
+char* DFG_OPERATION operationNewInt16ArrayWithSize(ExecState*, Structure*, int32_t) WTF_INTERNAL;
+char* DFG_OPERATION operationNewInt16ArrayWithOneArgument(ExecState*, Structure*, EncodedJSValue) WTF_INTERNAL;
+char* DFG_OPERATION operationNewInt32ArrayWithSize(ExecState*, Structure*, int32_t) WTF_INTERNAL;
+char* DFG_OPERATION operationNewInt32ArrayWithOneArgument(ExecState*, Structure*, EncodedJSValue) WTF_INTERNAL;
+char* DFG_OPERATION operationNewUint8ArrayWithSize(ExecState*, Structure*, int32_t) WTF_INTERNAL;
+char* DFG_OPERATION operationNewUint8ArrayWithOneArgument(ExecState*, Structure*, EncodedJSValue) WTF_INTERNAL;
+char* DFG_OPERATION operationNewUint8ClampedArrayWithSize(ExecState*, Structure*, int32_t) WTF_INTERNAL;
+char* DFG_OPERATION operationNewUint8ClampedArrayWithOneArgument(ExecState*, Structure*, EncodedJSValue) WTF_INTERNAL;
+char* DFG_OPERATION operationNewUint16ArrayWithSize(ExecState*, Structure*, int32_t) WTF_INTERNAL;
+char* DFG_OPERATION operationNewUint16ArrayWithOneArgument(ExecState*, Structure*, EncodedJSValue) WTF_INTERNAL;
+char* DFG_OPERATION operationNewUint32ArrayWithSize(ExecState*, Structure*, int32_t) WTF_INTERNAL;
+char* DFG_OPERATION operationNewUint32ArrayWithOneArgument(ExecState*, Structure*, EncodedJSValue) WTF_INTERNAL;
+char* DFG_OPERATION operationNewFloat32ArrayWithSize(ExecState*, Structure*, int32_t) WTF_INTERNAL;
+char* DFG_OPERATION operationNewFloat32ArrayWithOneArgument(ExecState*, Structure*, EncodedJSValue) WTF_INTERNAL;
+char* DFG_OPERATION operationNewFloat64ArrayWithSize(ExecState*, Structure*, int32_t) WTF_INTERNAL;
+char* DFG_OPERATION operationNewFloat64ArrayWithOneArgument(ExecState*, Structure*, EncodedJSValue) WTF_INTERNAL;
 EncodedJSValue DFG_OPERATION operationNewRegexp(ExecState*, void*) WTF_INTERNAL;
 void DFG_OPERATION operationPutByValStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL;
 void DFG_OPERATION operationPutByValNonStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL;
@@ -284,6 +303,65 @@ void DFG_OPERATION debugOperationPrintSpeculationFailure(ExecState*, void*, void
 void DFG_OPERATION triggerReoptimizationNow(CodeBlock*) WTF_INTERNAL;
 
 } // extern "C"
+
+inline P_DFGOperation_EStZ operationNewTypedArrayWithSizeForType(TypedArrayType type)
+{
+    switch (type) {
+    case TypeInt8:
+        return operationNewInt8ArrayWithSize;
+    case TypeInt16:
+        return operationNewInt16ArrayWithSize;
+    case TypeInt32:
+        return operationNewInt32ArrayWithSize;
+    case TypeUint8:
+        return operationNewUint8ArrayWithSize;
+    case TypeUint8Clamped:
+        return operationNewUint8ClampedArrayWithSize;
+    case TypeUint16:
+        return operationNewUint16ArrayWithSize;
+    case TypeUint32:
+        return operationNewUint32ArrayWithSize;
+    case TypeFloat32:
+        return operationNewFloat32ArrayWithSize;
+    case TypeFloat64:
+        return operationNewFloat64ArrayWithSize;
+    case NotTypedArray:
+    case TypeDataView:
+        break;
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+    return 0;
+}
+
+inline P_DFGOperation_EStJ operationNewTypedArrayWithOneArgumentForType(TypedArrayType type)
+{
+    switch (type) {
+    case TypeInt8:
+        return operationNewInt8ArrayWithOneArgument;
+    case TypeInt16:
+        return operationNewInt16ArrayWithOneArgument;
+    case TypeInt32:
+        return operationNewInt32ArrayWithOneArgument;
+    case TypeUint8:
+        return operationNewUint8ArrayWithOneArgument;
+    case TypeUint8Clamped:
+        return operationNewUint8ClampedArrayWithOneArgument;
+    case TypeUint16:
+        return operationNewUint16ArrayWithOneArgument;
+    case TypeUint32:
+        return operationNewUint32ArrayWithOneArgument;
+    case TypeFloat32:
+        return operationNewFloat32ArrayWithOneArgument;
+    case TypeFloat64:
+        return operationNewFloat64ArrayWithOneArgument;
+    case NotTypedArray:
+    case TypeDataView:
+        break;
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+    return 0;
+}
+
 } } // namespace JSC::DFG
 
 #endif
index cacdd7c..cad4c7a 100644 (file)
@@ -414,6 +414,11 @@ private:
             break;
         }
             
+        case NewTypedArray: {
+            changed |= setPrediction(speculationFromTypedArrayType(node->typedArrayType()));
+            break;
+        }
+            
         case NewRegexp:
         case CreateActivation: {
             changed |= setPrediction(SpecObjectOther);
index 39e55ab..bf99b12 100644 (file)
@@ -231,6 +231,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case ForceOSRExit:
     case CheckWatchdogTimer:
     case StringFromCharCode:
+    case NewTypedArray:
     case Unreachable:
         return true;
         
index d615a4e..cea4c6e 100644 (file)
@@ -4476,6 +4476,83 @@ void SpeculativeJIT::compileNewStringObject(Node* node)
     cellResult(resultGPR, node);
 }
 
+void SpeculativeJIT::compileNewTypedArray(Node* node)
+{
+    JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->codeOrigin);
+    TypedArrayType type = node->typedArrayType();
+    Structure* structure = globalObject->typedArrayStructure(type);
+    
+    SpeculateIntegerOperand size(this, node->child1());
+    GPRReg sizeGPR = size.gpr();
+    
+    GPRTemporary result(this);
+    GPRTemporary storage(this);
+    GPRTemporary scratch(this);
+    GPRTemporary scratch2(this);
+    GPRReg resultGPR = result.gpr();
+    GPRReg storageGPR = storage.gpr();
+    GPRReg scratchGPR = scratch.gpr();
+    GPRReg scratchGPR2 = scratch2.gpr();
+    
+    JITCompiler::JumpList slowCases;
+
+    slowCases.append(m_jit.branch32(
+        MacroAssembler::Above, sizeGPR, TrustedImm32(JSArrayBufferView::fastSizeLimit)));
+    
+    m_jit.move(sizeGPR, scratchGPR);
+    m_jit.lshift32(TrustedImm32(logElementSize(type)), scratchGPR);
+    if (elementSize(type) < 8) {
+        m_jit.add32(TrustedImm32(7), scratchGPR);
+        m_jit.and32(TrustedImm32(~7), scratchGPR);
+    }
+    slowCases.append(
+        emitAllocateBasicStorage(scratchGPR, storageGPR));
+    
+    m_jit.subPtr(scratchGPR, storageGPR);
+    
+    emitAllocateJSObject<JSArrayBufferView>(
+        resultGPR, TrustedImmPtr(structure), TrustedImmPtr(0), scratchGPR, scratchGPR2,
+        slowCases);
+    
+    m_jit.storePtr(
+        storageGPR,
+        MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfVector()));
+    m_jit.store32(
+        sizeGPR,
+        MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfLength()));
+    m_jit.store32(
+        TrustedImm32(FastTypedArray),
+        MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfMode()));
+    
+#if USE(JSVALUE32_64)
+    MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, sizeGPR);
+    m_jit.move(sizeGPR, scratchGPR);
+    if (elementSize(type) != 4) {
+        if (elementSize(type) > 4)
+            m_jit.lshift32(TrustedImm32(logElementSize(type) - 2), scratchGPR);
+        else {
+            if (elementSize(type) > 1)
+                m_jit.lshift32(TrustedImm32(logElementSize(type)), scratchGPR);
+            m_jit.add32(TrustedImm32(3), scratchGPR);
+            m_jit.urshift32(TrustedImm32(2), scratchGPR);
+        }
+    }
+    MacroAssembler::Label loop = m_jit.label();
+    m_jit.sub32(TrustedImm32(1), scratchGPR);
+    m_jit.store32(
+        TrustedImm32(0),
+        MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesFour));
+    m_jit.branchTest32(MacroAssembler::NonZero, scratchGPR).linkTo(loop, &m_jit);
+    done.link(&m_jit);
+#endif // USE(JSVALUE32_64)
+    
+    addSlowPathGenerator(slowPathCall(
+        slowCases, this, operationNewTypedArrayWithSizeForType(type),
+        resultGPR, structure, sizeGPR));
+    
+    cellResult(resultGPR, node);
+}
+
 void SpeculativeJIT::speculateInt32(Edge edge)
 {
     if (!needsTypeCheck(edge, SpecInt32))
index d87efe0..2c4dcd7 100644 (file)
@@ -1241,6 +1241,12 @@ public:
         return appendCallSetResult(operation, result);
     }
 
+    JITCompiler::Call callOperation(P_DFGOperation_EStJ operation, GPRReg result, Structure* structure, GPRReg arg2)
+    {
+        m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), arg2);
+        return appendCallWithExceptionCheckSetResult(operation, result);
+    }
+
     JITCompiler::Call callOperation(C_DFGOperation_EJ operation, GPRReg result, GPRReg arg1)
     {
         m_jit.setupArgumentsWithExecState(arg1);
@@ -1495,6 +1501,12 @@ public:
         return appendCallSetResult(operation, result);
     }
 
+    JITCompiler::Call callOperation(P_DFGOperation_EStJ operation, GPRReg result, Structure* structure, GPRReg arg2Tag, GPRReg arg2Payload)
+    {
+        m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), arg2Payload, arg2Tag);
+        return appendCallWithExceptionCheckSetResult(operation, result);
+    }
+
     JITCompiler::Call callOperation(C_DFGOperation_EJ operation, GPRReg result, GPRReg arg1Tag, GPRReg arg1Payload)
     {
         m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag);
@@ -1925,6 +1937,8 @@ public:
     void compileToStringOnCell(Node*);
     void compileNewStringObject(Node*);
     
+    void compileNewTypedArray(Node*);
+    
     void compileIntegerCompare(Node*, MacroAssembler::RelationalCondition);
     void compileBooleanCompare(Node*, MacroAssembler::RelationalCondition);
     void compileDoubleCompare(Node*, MacroAssembler::DoubleCondition);
index b45c618..957c180 100644 (file)
@@ -3604,6 +3604,37 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
         
+    case NewTypedArray: {
+        switch (node->child1().useKind()) {
+        case Int32Use:
+            compileNewTypedArray(node);
+            break;
+        case UntypedUse: {
+            JSValueOperand argument(this, node->child1());
+            GPRReg argumentTagGPR = argument.tagGPR();
+            GPRReg argumentPayloadGPR = argument.payloadGPR();
+            
+            flushRegisters();
+            
+            GPRResult result(this);
+            GPRReg resultGPR = result.gpr();
+            
+            JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->codeOrigin);
+            callOperation(
+                operationNewTypedArrayWithOneArgumentForType(node->typedArrayType()),
+                resultGPR, globalObject->typedArrayStructure(node->typedArrayType()),
+                argumentTagGPR, argumentPayloadGPR);
+            
+            cellResult(resultGPR, node);
+            break;
+        }
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+        }
+        break;
+    }
+        
     case NewRegexp: {
         flushRegisters();
         GPRResult resultPayload(this);
@@ -3685,7 +3716,7 @@ void SpeculativeJIT::compile(Node* node)
         MacroAssembler::JumpList slowPath;
         
         Structure* structure = node->structure();
-        size_t allocationSize = JSObject::allocationSize(structure->inlineCapacity());
+        size_t allocationSize = JSFinalObject::allocationSize(structure->inlineCapacity());
         MarkedAllocator* allocatorPtr = &m_jit.vm()->heap.allocatorForObjectWithoutDestructor(allocationSize);
 
         m_jit.move(TrustedImmPtr(allocatorPtr), allocatorGPR);
index 3364f09..d30a7bc 100644 (file)
@@ -3527,6 +3527,36 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
         
+    case NewTypedArray: {
+        switch (node->child1().useKind()) {
+        case Int32Use:
+            compileNewTypedArray(node);
+            break;
+        case UntypedUse: {
+            JSValueOperand argument(this, node->child1());
+            GPRReg argumentGPR = argument.gpr();
+            
+            flushRegisters();
+            
+            GPRResult result(this);
+            GPRReg resultGPR = result.gpr();
+            
+            JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->codeOrigin);
+            callOperation(
+                operationNewTypedArrayWithOneArgumentForType(node->typedArrayType()),
+                resultGPR, globalObject->typedArrayStructure(node->typedArrayType()),
+                argumentGPR);
+            
+            cellResult(resultGPR, node);
+            break;
+        }
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+        }
+        break;
+    }
+        
     case NewRegexp: {
         flushRegisters();
         GPRResult result(this);
@@ -3603,7 +3633,7 @@ void SpeculativeJIT::compile(Node* node)
         MacroAssembler::JumpList slowPath;
 
         Structure* structure = node->structure();
-        size_t allocationSize = JSObject::allocationSize(structure->inlineCapacity());
+        size_t allocationSize = JSFinalObject::allocationSize(structure->inlineCapacity());
         MarkedAllocator* allocatorPtr = &m_jit.vm()->heap.allocatorForObjectWithoutDestructor(allocationSize);
 
         m_jit.move(TrustedImmPtr(allocatorPtr), allocatorGPR);
index 9110c8f..929b9a7 100644 (file)
@@ -97,7 +97,7 @@ void JIT::emit_op_jmp(Instruction* currentInstruction)
 void JIT::emit_op_new_object(Instruction* currentInstruction)
 {
     Structure* structure = currentInstruction[3].u.objectAllocationProfile->structure();
-    size_t allocationSize = JSObject::allocationSize(structure->inlineCapacity());
+    size_t allocationSize = JSFinalObject::allocationSize(structure->inlineCapacity());
     MarkedAllocator* allocator = &m_vm->heap.allocatorForObjectWithoutDestructor(allocationSize);
 
     RegisterID resultReg = regT0;
index 04cc625..051ead9 100644 (file)
@@ -211,7 +211,7 @@ void JIT::emit_op_jmp(Instruction* currentInstruction)
 void JIT::emit_op_new_object(Instruction* currentInstruction)
 {
     Structure* structure = currentInstruction[3].u.objectAllocationProfile->structure();
-    size_t allocationSize = JSObject::allocationSize(structure->inlineCapacity());
+    size_t allocationSize = JSFinalObject::allocationSize(structure->inlineCapacity());
     MarkedAllocator* allocator = &m_vm->heap.allocatorForObjectWithoutDestructor(allocationSize);
 
     RegisterID resultReg = regT0;
index 63f8a15..d788fa9 100644 (file)
@@ -38,6 +38,12 @@ class JSArray : public JSNonFinalObject {
 public:
     typedef JSNonFinalObject Base;
 
+    static size_t allocationSize(size_t inlineCapacity)
+    {
+        ASSERT_UNUSED(inlineCapacity, !inlineCapacity);
+        return sizeof(JSArray);
+    }
+        
 protected:
     explicit JSArray(VM& vm, Structure* structure, Butterfly* butterfly)
         : JSNonFinalObject(vm, structure, butterfly)
index 2b72b51..68b6e7c 100644 (file)
@@ -91,6 +91,12 @@ public:
             & ~(sizeof(EncodedJSValue) - 1);
     }
 
+    static size_t allocationSize(size_t inlineCapacity)
+    {
+        ASSERT_UNUSED(inlineCapacity, !inlineCapacity);
+        return sizeof(JSArrayBufferView);
+    }
+        
 protected:
     class ConstructionContext {
         WTF_MAKE_NONCOPYABLE(ConstructionContext);
index 91897a1..481b899 100644 (file)
@@ -100,7 +100,7 @@ static EncodedJSValue JSC_HOST_CALL constructGenericTypedArrayView(ExecState* ex
                 return JSValue::encode(jsUndefined());
         } else {
             if ((buffer->byteLength() - offset) % ViewClass::elementSize)
-                return throwVMError(exec, createRangeError(exec, "ArrayBuffer length minus the byteOffset is not a multiple of the element size."));
+                return throwVMError(exec, createRangeError(exec, "ArrayBuffer length minus the byteOffset is not a multiple of the element size"));
             length = (buffer->byteLength() - offset) / ViewClass::elementSize;
         }
         return JSValue::encode(ViewClass::create(exec, structure, buffer, offset, length));
@@ -135,15 +135,15 @@ static EncodedJSValue JSC_HOST_CALL constructGenericTypedArrayView(ExecState* ex
     if (exec->argument(0).isInt32())
         length = exec->argument(0).asInt32();
     else if (!exec->argument(0).isNumber())
-        return throwVMError(exec, createTypeError(exec, "Invalid array length argument."));
+        return throwVMError(exec, createTypeError(exec, "Invalid array length argument"));
     else {
         length = static_cast<int>(exec->argument(0).asNumber());
         if (length != exec->argument(0).asNumber())
-            return throwVMError(exec, createTypeError(exec, "Invalid array length argument (fractional lengths not allowed)."));
+            return throwVMError(exec, createTypeError(exec, "Invalid array length argument (fractional lengths not allowed)"));
     }
 
     if (length < 0)
-        return throwVMError(exec, createRangeError(exec, "Requested length is negative."));
+        return throwVMError(exec, createRangeError(exec, "Requested length is negative"));
     return JSValue::encode(ViewClass::create(exec, structure, length));
 }
 
index b1991a7..819cdc0 100644 (file)
@@ -98,11 +98,6 @@ class JSObject : public JSCell {
 public:
     typedef JSCell Base;
         
-    static size_t allocationSize(size_t inlineCapacity)
-    {
-        return sizeof(JSObject) + inlineCapacity * sizeof(WriteBarrierBase<Unknown>);
-    }
-        
     JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
     JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
 
@@ -1017,6 +1012,11 @@ class JSFinalObject : public JSObject {
 public:
     typedef JSObject Base;
 
+    static size_t allocationSize(size_t inlineCapacity)
+    {
+        return sizeof(JSObject) + inlineCapacity * sizeof(WriteBarrierBase<Unknown>);
+    }
+        
     static const unsigned defaultSize = 64;
     static inline unsigned defaultInlineCapacity()
     {
index f764513..46d5051 100644 (file)
@@ -27,6 +27,7 @@
 #include "TypedArrayType.h"
 
 #include "JSDataView.h"
+#include "JSTypedArrayConstructors.h"
 #include "JSTypedArrays.h"
 
 namespace JSC {
@@ -61,6 +62,36 @@ const ClassInfo* classInfoForType(TypedArrayType type)
     return 0;
 }
 
+const ClassInfo* constructorClassInfoForType(TypedArrayType type)
+{
+    switch (type) {
+    case NotTypedArray:
+        return 0;
+    case TypeInt8:
+        return JSInt8ArrayConstructor::info();
+    case TypeUint8:
+        return JSUint8ArrayConstructor::info();
+    case TypeUint8Clamped:
+        return JSUint8ClampedArrayConstructor::info();
+    case TypeInt16:
+        return JSInt16ArrayConstructor::info();
+    case TypeUint16:
+        return JSUint16ArrayConstructor::info();
+    case TypeInt32:
+        return JSInt32ArrayConstructor::info();
+    case TypeUint32:
+        return JSUint32ArrayConstructor::info();
+    case TypeFloat32:
+        return JSFloat32ArrayConstructor::info();
+    case TypeFloat64:
+        return JSFloat64ArrayConstructor::info();
+    case TypeDataView:
+        return JSDataViewConstructor::info();
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+    return 0;
+}
+
 } // namespace JSC
 
 namespace WTF {
index 4063e6d..ae3e5a8 100644 (file)
@@ -53,6 +53,13 @@ inline unsigned toIndex(TypedArrayType type)
     return static_cast<unsigned>(type) - 1;
 }
 
+inline TypedArrayType indexToTypedArrayType(unsigned index)
+{
+    TypedArrayType result = static_cast<TypedArrayType>(index + 1);
+    ASSERT(result >= TypeInt8 && result <= TypeDataView);
+    return result;
+}
+
 inline bool isTypedView(TypedArrayType type)
 {
     switch (type) {
@@ -94,6 +101,7 @@ inline size_t elementSize(TypedArrayType type)
 }
 
 const ClassInfo* classInfoForType(TypedArrayType);
+const ClassInfo* constructorClassInfoForType(TypedArrayType);
 
 inline bool isInt(TypedArrayType type)
 {