Commit 372fa82b authored by fpizlo@apple.com's avatar fpizlo@apple.com

DFG should inline new typedArray()

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: http://svn.webkit.org/repository/webkit/trunk@154403 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 5e1de64f
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
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
<!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>
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
<!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>
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
<!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>
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, ",");
}
}
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, ",");
}
}
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, ",");
}
}
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, ",");
}
}
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.
......
......@@ -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;
......
......@@ -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
......
......@@ -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());
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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
......
......@@ -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);
......
......@@ -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;
......
......@@ -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())
......
......@@ -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;
......
......@@ -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. */\
......
/*
* 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)
{