Commit 0875778f authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[turbofan] Teach TurboFan about the TypedArray constructor.

This introduces a new JSCreateTypedArray operator, backed by a dedicated
CreateTypedArray builtin, and adds support to lowering new TypedArray
calls to this operator. This way we avoid the overhead of going through
the generic construct stub machinery for hot code. This not only
recovers the performance regression on the typed array constructor
benchmarks, but even improves slightly beyond what we had in 6.6.

We might in the future try to fully inline the TypedArray constructor
into optimized code for certain cases.

Bug: chromium:820726, v8:7503, v8:7518
Change-Id: Ied465924d5695db576d533792f1db68456b9b5ea
Reviewed-on: https://chromium-review.googlesource.com/959010
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarPeter Marshall <petermarshall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51973}
parent bed02764
...@@ -1095,6 +1095,9 @@ namespace internal { ...@@ -1095,6 +1095,9 @@ namespace internal {
TFS(TypedArrayInitialize, kHolder, kLength, kElementSize, kInitialize) \ TFS(TypedArrayInitialize, kHolder, kLength, kElementSize, kInitialize) \
TFS(TypedArrayInitializeWithBuffer, kHolder, kLength, kBuffer, kElementSize, \ TFS(TypedArrayInitializeWithBuffer, kHolder, kLength, kBuffer, kElementSize, \
kByteOffset) \ kByteOffset) \
/* ES #sec-typedarray-constructors */ \
TFS(CreateTypedArray, kTarget, kNewTarget, kArg1, kArg2, kArg3) \
TFJ(TypedArrayConstructorLazyDeoptContinuation, 1, kResult) \
TFJ(TypedArrayConstructor, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \ TFJ(TypedArrayConstructor, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
CPP(TypedArrayPrototypeBuffer) \ CPP(TypedArrayPrototypeBuffer) \
/* ES6 #sec-get-%typedarray%.prototype.bytelength */ \ /* ES6 #sec-get-%typedarray%.prototype.bytelength */ \
......
...@@ -630,107 +630,126 @@ void TypedArrayBuiltinsAssembler::ConstructByIterable( ...@@ -630,107 +630,126 @@ void TypedArrayBuiltinsAssembler::ConstructByIterable(
element_size); element_size);
} }
TF_BUILTIN(TypedArrayConstructor, TypedArrayBuiltinsAssembler) { // ES #sec-typedarray-constructors
TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext)); TF_BUILTIN(CreateTypedArray, TypedArrayBuiltinsAssembler) {
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<JSFunction> target = CAST(Parameter(Descriptor::kTarget));
TNode<JSReceiver> new_target = CAST(Parameter(Descriptor::kNewTarget));
TNode<Object> arg1 = CAST(Parameter(Descriptor::kArg1));
TNode<Object> arg2 = CAST(Parameter(Descriptor::kArg2));
TNode<Object> arg3 = CAST(Parameter(Descriptor::kArg3));
// If NewTarget is undefined, throw a TypeError exception. CSA_ASSERT(this, IsConstructor(target));
// All the TypedArray constructors have this as the first step: CSA_ASSERT(this, IsJSReceiver(new_target));
// https://tc39.github.io/ecma262/#sec-typedarray-constructors
Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
MachineType::TaggedPointer());
Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
Label throwtypeerror(this, Label::kDeferred), createtypedarray(this);
Branch(IsUndefined(new_target), &throwtypeerror, &createtypedarray);
BIND(&throwtypeerror); Label if_arg1isbuffer(this), if_arg1istypedarray(this),
if_arg1isreceiver(this), if_arg1isnumber(this), return_result(this);
ConstructorBuiltinsAssembler constructor_assembler(this->state());
TNode<JSTypedArray> result = CAST(
constructor_assembler.EmitFastNewObject(context, target, new_target));
TNode<Smi> element_size =
SmiTag(GetTypedArrayElementSize(LoadElementsKind(result)));
GotoIf(TaggedIsSmi(arg1), &if_arg1isnumber);
GotoIf(IsJSArrayBuffer(arg1), &if_arg1isbuffer);
GotoIf(IsJSTypedArray(arg1), &if_arg1istypedarray);
GotoIf(IsJSReceiver(arg1), &if_arg1isreceiver);
Goto(&if_arg1isnumber);
// https://tc39.github.io/ecma262/#sec-typedarray-buffer-byteoffset-length
BIND(&if_arg1isbuffer);
{ {
Node* shared = ConstructByArrayBuffer(context, result, CAST(arg1), arg2, arg3,
LoadObjectField(target, JSFunction::kSharedFunctionInfoOffset); element_size);
Node* name = LoadObjectField(shared, SharedFunctionInfo::kNameOffset); Goto(&return_result);
ThrowTypeError(context, MessageTemplate::kConstructorNotFunction, name);
} }
BIND(&createtypedarray); // https://tc39.github.io/ecma262/#sec-typedarray-typedarray
BIND(&if_arg1istypedarray);
{ {
Label if_arg1isbuffer(this), if_arg1istypedarray(this), TNode<JSTypedArray> typed_array = CAST(arg1);
if_arg1isreceiver(this), if_arg1isnumber(this), done(this); ConstructByTypedArray(context, result, typed_array, element_size);
Goto(&return_result);
Node* argc = }
ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
CodeStubArguments args(this, argc);
TNode<Object> arg1 = args.GetOptionalArgumentValue(0);
TNode<Object> arg2 = args.GetOptionalArgumentValue(1);
TNode<Object> arg3 = args.GetOptionalArgumentValue(2);
ConstructorBuiltinsAssembler constructor_assembler(this->state());
TNode<JSTypedArray> holder = CAST(
constructor_assembler.EmitFastNewObject(context, target, new_target));
TNode<Smi> element_size =
SmiTag(GetTypedArrayElementSize(LoadElementsKind(holder)));
GotoIf(TaggedIsSmi(arg1), &if_arg1isnumber);
GotoIf(IsJSArrayBuffer(arg1), &if_arg1isbuffer);
GotoIf(IsJSTypedArray(arg1), &if_arg1istypedarray);
GotoIf(IsJSReceiver(arg1), &if_arg1isreceiver);
Goto(&if_arg1isnumber);
// https://tc39.github.io/ecma262/#sec-typedarray-buffer-byteoffset-length
BIND(&if_arg1isbuffer);
{
ConstructByArrayBuffer(context, holder, CAST(arg1), arg2, arg3,
element_size);
Goto(&done);
}
// https://tc39.github.io/ecma262/#sec-typedarray-typedarray // https://tc39.github.io/ecma262/#sec-typedarray-object
BIND(&if_arg1istypedarray); BIND(&if_arg1isreceiver);
{
Label if_iteratorundefined(this), if_iteratornotcallable(this);
// Get iterator symbol
TNode<Object> iteratorFn =
CAST(GetMethod(context, arg1, isolate()->factory()->iterator_symbol(),
&if_iteratorundefined));
GotoIf(TaggedIsSmi(iteratorFn), &if_iteratornotcallable);
GotoIfNot(IsCallable(iteratorFn), &if_iteratornotcallable);
ConstructByIterable(context, result, CAST(arg1), iteratorFn, element_size);
Goto(&return_result);
BIND(&if_iteratorundefined);
{ {
TNode<JSTypedArray> typed_array = CAST(arg1); TNode<HeapObject> array_like = CAST(arg1);
ConstructByTypedArray(context, holder, typed_array, element_size); TNode<Object> initial_length =
Goto(&done); GetProperty(context, arg1, LengthStringConstant());
}
// https://tc39.github.io/ecma262/#sec-typedarray-object ConstructByArrayLike(context, result, array_like, initial_length,
BIND(&if_arg1isreceiver); element_size);
{ Goto(&return_result);
Label if_iteratorundefined(this), if_iteratornotcallable(this);
// Get iterator symbol
TNode<Object> iteratorFn =
CAST(GetMethod(context, arg1, isolate()->factory()->iterator_symbol(),
&if_iteratorundefined));
GotoIf(TaggedIsSmi(iteratorFn), &if_iteratornotcallable);
GotoIfNot(IsCallable(iteratorFn), &if_iteratornotcallable);
ConstructByIterable(context, holder, CAST(arg1), iteratorFn,
element_size);
Goto(&done);
BIND(&if_iteratorundefined);
{
TNode<HeapObject> array_like = CAST(arg1);
TNode<Object> initial_length =
GetProperty(context, arg1, LengthStringConstant());
ConstructByArrayLike(context, holder, array_like, initial_length,
element_size);
Goto(&done);
}
BIND(&if_iteratornotcallable);
{ ThrowTypeError(context, MessageTemplate::kIteratorSymbolNonCallable); }
} }
// The first argument was a number or fell through and is treated as BIND(&if_iteratornotcallable);
// a number. https://tc39.github.io/ecma262/#sec-typedarray-length { ThrowTypeError(context, MessageTemplate::kIteratorSymbolNonCallable); }
BIND(&if_arg1isnumber); }
{
ConstructByLength(context, holder, arg1, element_size);
Goto(&done);
}
BIND(&done); // The first argument was a number or fell through and is treated as
{ args.PopAndReturn(holder); } // a number. https://tc39.github.io/ecma262/#sec-typedarray-length
BIND(&if_arg1isnumber);
{
ConstructByLength(context, result, arg1, element_size);
Goto(&return_result);
}
BIND(&return_result);
Return(result);
}
TF_BUILTIN(TypedArrayConstructorLazyDeoptContinuation,
TypedArrayBuiltinsAssembler) {
Node* result = Parameter(Descriptor::kResult);
Return(result);
}
// ES #sec-typedarray-constructors
TF_BUILTIN(TypedArrayConstructor, TypedArrayBuiltinsAssembler) {
Node* context = Parameter(BuiltinDescriptor::kContext);
Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
MachineType::TaggedPointer());
Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
Node* argc =
ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
CodeStubArguments args(this, argc);
Node* arg1 = args.GetOptionalArgumentValue(0);
Node* arg2 = args.GetOptionalArgumentValue(1);
Node* arg3 = args.GetOptionalArgumentValue(2);
// If NewTarget is undefined, throw a TypeError exception.
// All the TypedArray constructors have this as the first step:
// https://tc39.github.io/ecma262/#sec-typedarray-constructors
Label throwtypeerror(this, Label::kDeferred);
GotoIf(IsUndefined(new_target), &throwtypeerror);
Node* result = CallBuiltin(Builtins::kCreateTypedArray, context, target,
new_target, arg1, arg2, arg3);
args.PopAndReturn(result);
BIND(&throwtypeerror);
{
Node* shared =
LoadObjectField(target, JSFunction::kSharedFunctionInfoOffset);
Node* name = LoadObjectField(shared, SharedFunctionInfo::kNameOffset);
ThrowTypeError(context, MessageTemplate::kConstructorNotFunction, name);
} }
} }
......
...@@ -3611,44 +3611,48 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) { ...@@ -3611,44 +3611,48 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
// Don't inline cross native context. // Don't inline cross native context.
if (function->native_context() != *native_context()) return NoChange(); if (function->native_context() != *native_context()) return NoChange();
// Check for the ArrayConstructor. // Check for known builtin functions.
if (*function == function->native_context()->array_function()) { switch (function->shared()->code()->builtin_index()) {
// TODO(bmeurer): Deal with Array subclasses here. case Builtins::kArrayConstructor: {
Handle<AllocationSite> site; // TODO(bmeurer): Deal with Array subclasses here.
// Turn the {node} into a {JSCreateArray} call. Handle<AllocationSite> site;
for (int i = arity; i > 0; --i) { // Turn the {node} into a {JSCreateArray} call.
NodeProperties::ReplaceValueInput( for (int i = arity; i > 0; --i) {
node, NodeProperties::GetValueInput(node, i), i + 1); NodeProperties::ReplaceValueInput(
} node, NodeProperties::GetValueInput(node, i), i + 1);
NodeProperties::ReplaceValueInput(node, new_target, 1); }
NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site)); NodeProperties::ReplaceValueInput(node, new_target, 1);
return Changed(node); NodeProperties::ChangeOp(node,
} javascript()->CreateArray(arity, site));
// Check for the ObjectConstructor.
if (*function == function->native_context()->object_function()) {
// If no value is passed, we can immediately lower to a simple
// JSCreate and don't need to do any massaging of the {node}.
if (arity == 0) {
NodeProperties::ChangeOp(node, javascript()->Create());
return Changed(node); return Changed(node);
} }
case Builtins::kObjectConstructor: {
// Otherwise we can only lower to JSCreate if we know that // If no value is passed, we can immediately lower to a simple
// the value parameter is ignored, which is only the case if // JSCreate and don't need to do any massaging of the {node}.
// the {new_target} and {target} are definitely not identical. if (arity == 0) {
HeapObjectMatcher mnew_target(new_target); NodeProperties::ChangeOp(node, javascript()->Create());
if (mnew_target.HasValue() && *mnew_target.Value() != *function) { return Changed(node);
// Drop the value inputs. }
for (int i = arity; i > 0; --i) node->RemoveInput(i);
NodeProperties::ChangeOp(node, javascript()->Create()); // Otherwise we can only lower to JSCreate if we know that
return Changed(node); // the value parameter is ignored, which is only the case if
// the {new_target} and {target} are definitely not identical.
HeapObjectMatcher mnew_target(new_target);
if (mnew_target.HasValue() && *mnew_target.Value() != *function) {
// Drop the value inputs.
for (int i = arity; i > 0; --i) node->RemoveInput(i);
NodeProperties::ChangeOp(node, javascript()->Create());
return Changed(node);
}
break;
} }
} case Builtins::kPromiseConstructor:
return ReducePromiseConstructor(node);
// Check for the PromiseConstructor case Builtins::kTypedArrayConstructor:
if (*function == function->native_context()->promise_function()) { return ReduceTypedArrayConstructor(
return ReducePromiseConstructor(node); node, handle(function->shared(), isolate()));
default:
break;
} }
} else if (m.Value()->IsJSBoundFunction()) { } else if (m.Value()->IsJSBoundFunction()) {
Handle<JSBoundFunction> function = Handle<JSBoundFunction> function =
...@@ -5832,6 +5836,47 @@ Reduction JSCallReducer::ReducePromiseResolveTrampoline(Node* node) { ...@@ -5832,6 +5836,47 @@ Reduction JSCallReducer::ReducePromiseResolveTrampoline(Node* node) {
return Changed(node); return Changed(node);
} }
// ES #sec-typedarray-constructors
Reduction JSCallReducer::ReduceTypedArrayConstructor(
Node* node, Handle<SharedFunctionInfo> shared) {
DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode());
ConstructParameters const& p = ConstructParametersOf(node->op());
int arity = static_cast<int>(p.arity() - 2);
Node* target = NodeProperties::GetValueInput(node, 0);
Node* arg1 = (arity >= 1) ? NodeProperties::GetValueInput(node, 1)
: jsgraph()->UndefinedConstant();
Node* arg2 = (arity >= 2) ? NodeProperties::GetValueInput(node, 2)
: jsgraph()->UndefinedConstant();
Node* arg3 = (arity >= 3) ? NodeProperties::GetValueInput(node, 3)
: jsgraph()->UndefinedConstant();
Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
Node* context = NodeProperties::GetContextInput(node);
Node* frame_state = NodeProperties::GetFrameStateInput(node);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// Insert a construct stub frame into the chain of frame states. This will
// reconstruct the proper frame when deoptimizing within the constructor.
frame_state = CreateArtificialFrameState(
node, frame_state, arity, BailoutId::ConstructStubInvoke(),
FrameStateType::kConstructStub, shared);
// This continuation just returns the newly created JSTypedArray. We
// pass the_hole as the receiver, just like the builtin construct stub
// does in this case.
Node* const parameters[] = {jsgraph()->TheHoleConstant()};
int const num_parameters = static_cast<int>(arraysize(parameters));
frame_state = CreateJavaScriptBuiltinContinuationFrameState(
jsgraph(), shared, Builtins::kTypedArrayConstructorLazyDeoptContinuation,
target, context, parameters, num_parameters, frame_state,
ContinuationFrameStateMode::LAZY);
Node* result =
graph()->NewNode(javascript()->CreateTypedArray(), target, new_target,
arg1, arg2, arg3, context, frame_state, effect, control);
return Replace(result);
}
Graph* JSCallReducer::graph() const { return jsgraph()->graph(); } Graph* JSCallReducer::graph() const { return jsgraph()->graph(); }
Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); } Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); }
......
...@@ -92,12 +92,9 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer { ...@@ -92,12 +92,9 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
Reduction ReduceArrayPrototypeShift(Node* node); Reduction ReduceArrayPrototypeShift(Node* node);
enum class ArrayIteratorKind { kArray, kTypedArray }; enum class ArrayIteratorKind { kArray, kTypedArray };
Reduction ReduceArrayIterator(Node* node, IterationKind kind); Reduction ReduceArrayIterator(Node* node, IterationKind kind);
Reduction ReduceTypedArrayIterator(Node* node, IterationKind kind);
Reduction ReduceArrayIteratorPrototypeNext(Node* node); Reduction ReduceArrayIteratorPrototypeNext(Node* node);
Reduction ReduceFastArrayIteratorNext(InstanceType type, Node* node, Reduction ReduceFastArrayIteratorNext(InstanceType type, Node* node,
IterationKind kind); IterationKind kind);
Reduction ReduceTypedArrayIteratorNext(InstanceType type, Node* node,
IterationKind kind);
Reduction ReduceCallOrConstructWithArrayLikeOrSpread( Reduction ReduceCallOrConstructWithArrayLikeOrSpread(
Node* node, int arity, CallFrequency const& frequency, Node* node, int arity, CallFrequency const& frequency,
...@@ -142,6 +139,9 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer { ...@@ -142,6 +139,9 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
Reduction ReducePromisePrototypeThen(Node* node); Reduction ReducePromisePrototypeThen(Node* node);
Reduction ReducePromiseResolveTrampoline(Node* node); Reduction ReducePromiseResolveTrampoline(Node* node);
Reduction ReduceTypedArrayConstructor(Node* node,
Handle<SharedFunctionInfo> shared);
Reduction ReduceSoftDeoptimize(Node* node, DeoptimizeReason reason); Reduction ReduceSoftDeoptimize(Node* node, DeoptimizeReason reason);
Reduction ReduceMathUnary(Node* node, const Operator* op); Reduction ReduceMathUnary(Node* node, const Operator* op);
......
...@@ -446,6 +446,13 @@ void JSGenericLowering::LowerJSCreatePromise(Node* node) { ...@@ -446,6 +446,13 @@ void JSGenericLowering::LowerJSCreatePromise(Node* node) {
UNREACHABLE(); // Eliminated in typed lowering. UNREACHABLE(); // Eliminated in typed lowering.
} }
void JSGenericLowering::LowerJSCreateTypedArray(Node* node) {
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
Callable callable =
Builtins::CallableFor(isolate(), Builtins::kCreateTypedArray);
ReplaceWithStubCall(node, callable, flags);
}
void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) { void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) {
CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
CallDescriptor::Flags flags = FrameStateFlagForCall(node); CallDescriptor::Flags flags = FrameStateFlagForCall(node);
......
...@@ -598,6 +598,7 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) { ...@@ -598,6 +598,7 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) {
V(CreateStringIterator, Operator::kEliminatable, 1, 1) \ V(CreateStringIterator, Operator::kEliminatable, 1, 1) \
V(CreateKeyValueArray, Operator::kEliminatable, 2, 1) \ V(CreateKeyValueArray, Operator::kEliminatable, 2, 1) \
V(CreatePromise, Operator::kEliminatable, 0, 1) \ V(CreatePromise, Operator::kEliminatable, 0, 1) \
V(CreateTypedArray, Operator::kNoProperties, 5, 1) \
V(HasProperty, Operator::kNoProperties, 2, 1) \ V(HasProperty, Operator::kNoProperties, 2, 1) \
V(HasInPrototypeChain, Operator::kNoProperties, 2, 1) \ V(HasInPrototypeChain, Operator::kNoProperties, 2, 1) \
V(OrdinaryHasInstance, Operator::kNoProperties, 2, 1) \ V(OrdinaryHasInstance, Operator::kNoProperties, 2, 1) \
......
...@@ -695,6 +695,7 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final ...@@ -695,6 +695,7 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* CreateStringIterator(); const Operator* CreateStringIterator();
const Operator* CreateKeyValueArray(); const Operator* CreateKeyValueArray();
const Operator* CreatePromise(); const Operator* CreatePromise();
const Operator* CreateTypedArray();
const Operator* CreateLiteralArray(Handle<ConstantElementsPair> constant, const Operator* CreateLiteralArray(Handle<ConstantElementsPair> constant,
VectorSlotPair const& feedback, VectorSlotPair const& feedback,
int literal_flags, int number_of_elements); int literal_flags, int number_of_elements);
......
...@@ -144,6 +144,7 @@ ...@@ -144,6 +144,7 @@
V(JSCreateStringIterator) \ V(JSCreateStringIterator) \
V(JSCreateKeyValueArray) \ V(JSCreateKeyValueArray) \
V(JSCreatePromise) \ V(JSCreatePromise) \
V(JSCreateTypedArray) \
V(JSCreateLiteralArray) \ V(JSCreateLiteralArray) \
V(JSCreateEmptyLiteralArray) \ V(JSCreateEmptyLiteralArray) \
V(JSCreateLiteralObject) \ V(JSCreateLiteralObject) \
......
...@@ -71,6 +71,7 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) { ...@@ -71,6 +71,7 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
case IrOpcode::kJSCreate: case IrOpcode::kJSCreate:
case IrOpcode::kJSCreateArguments: case IrOpcode::kJSCreateArguments:
case IrOpcode::kJSCreateArray: case IrOpcode::kJSCreateArray:
case IrOpcode::kJSCreateTypedArray:
case IrOpcode::kJSCreateLiteralArray: case IrOpcode::kJSCreateLiteralArray:
case IrOpcode::kJSCreateLiteralObject: case IrOpcode::kJSCreateLiteralObject:
case IrOpcode::kJSCreateLiteralRegExp: case IrOpcode::kJSCreateLiteralRegExp:
......
...@@ -1241,6 +1241,10 @@ Type* Typer::Visitor::TypeJSCreatePromise(Node* node) { ...@@ -1241,6 +1241,10 @@ Type* Typer::Visitor::TypeJSCreatePromise(Node* node) {
return Type::OtherObject(); return Type::OtherObject();
} }
Type* Typer::Visitor::TypeJSCreateTypedArray(Node* node) {
return Type::OtherObject();
}
Type* Typer::Visitor::TypeJSCreateLiteralArray(Node* node) { Type* Typer::Visitor::TypeJSCreateLiteralArray(Node* node) {
return Type::Array(); return Type::Array();
} }
......
...@@ -693,6 +693,10 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) { ...@@ -693,6 +693,10 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
// Type is OtherObject. // Type is OtherObject.
CheckTypeIs(node, Type::OtherObject()); CheckTypeIs(node, Type::OtherObject());
break; break;
case IrOpcode::kJSCreateTypedArray:
// Type is OtherObject.
CheckTypeIs(node, Type::OtherObject());
break;
case IrOpcode::kJSCreateLiteralArray: case IrOpcode::kJSCreateLiteralArray:
// Type is Array. // Type is Array.
CheckTypeIs(node, Type::Array()); CheckTypeIs(node, Type::Array());
......
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-bigint
const limit = %MaxSmi() + 1;
(function() {
function foo() {
try { new Int8Array(limit); } catch (e) { return e.stack; }
}
assertTrue(/new Int8Array/.test(foo()));
assertTrue(/new Int8Array/.test(foo()));
%OptimizeFunctionOnNextCall(foo);
assertTrue(/new Int8Array/.test(foo()));
})();
(function() {
function foo() {
try { new Uint8Array(limit); } catch (e) { return e.stack; }
}
assertTrue(/new Uint8Array/.test(foo()));
assertTrue(/new Uint8Array/.test(foo()));
%OptimizeFunctionOnNextCall(foo);
assertTrue(/new Uint8Array/.test(foo()));
})();
(function() {
function foo() {
try { new Uint8ClampedArray(limit); } catch (e) { return e.stack; }
}
assertTrue(/new Uint8ClampedArray/.test(foo()));
assertTrue(/new Uint8ClampedArray/.test(foo()));
%OptimizeFunctionOnNextCall(foo);
assertTrue(/new Uint8ClampedArray/.test(foo()));
})();
(function() {
function foo() {
try { new Int16Array(limit); } catch (e) { return e.stack; }
}
assertTrue(/new Int16Array/.test(foo()));
assertTrue(/new Int16Array/.test(foo()));
%OptimizeFunctionOnNextCall(foo);
assertTrue(/new Int16Array/.test(foo()));
})();
(function() {
function foo() {
try { new Uint16Array(limit); } catch (e) { return e.stack; }
}
assertTrue(/new Uint16Array/.test(foo()));
assertTrue(/new Uint16Array/.test(foo()));
%OptimizeFunctionOnNextCall(foo);
assertTrue(/new Uint16Array/.test(foo()));
})();
(function() {
function foo() {
try { new Int32Array(limit); } catch (e) { return e.stack; }
}
assertTrue(/new Int32Array/.test(foo()));
assertTrue(/new Int32Array/.test(foo()));
%OptimizeFunctionOnNextCall(foo);
assertTrue(/new Int32Array/.test(foo()));
})();
(function() {
function foo() {
try { new Uint32Array(limit); } catch (e) { return e.stack; }
}
assertTrue(/new Uint32Array/.test(foo()));
assertTrue(/new Uint32Array/.test(foo()));
%OptimizeFunctionOnNextCall(foo);
assertTrue(/new Uint32Array/.test(foo()));
})();
(function() {
function foo() {
try { new Float32Array(limit); } catch (e) { return e.stack; }
}
assertTrue(/new Float32Array/.test(foo()));
assertTrue(/new Float32Array/.test(foo()));
%OptimizeFunctionOnNextCall(foo);
assertTrue(/new Float32Array/.test(foo()));
})();
(function() {
function foo() {
try { new Float64Array(limit); } catch (e) { return e.stack; }
}
assertTrue(/new Float64Array/.test(foo()));
assertTrue(/new Float64Array/.test(foo()));
%OptimizeFunctionOnNextCall(foo);
assertTrue(/new Float64Array/.test(foo()));
})();
(function() {
function foo() {
try { new BigInt64Array(limit); } catch (e) { return e.stack; }
}
assertTrue(/new BigInt64Array/.test(foo()));
assertTrue(/new BigInt64Array/.test(foo()));
%OptimizeFunctionOnNextCall(foo);
assertTrue(/new BigInt64Array/.test(foo()));
})();
(function() {
function foo() {
try { new BigUint64Array(limit); } catch (e) { return e.stack; }
}
assertTrue(/new BigUint64Array/.test(foo()));
assertTrue(/new BigUint64Array/.test(foo()));
%OptimizeFunctionOnNextCall(foo);
assertTrue(/new BigUint64Array/.test(foo()));
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment