Commit 21701297 authored by bmeurer's avatar bmeurer Committed by Commit Bot

[turbofan] Introduce new JSConstructWithArrayLike operator.

Add a new JSConstructWithArrayLike operator that is backed by the
ConstructWithArrayLike builtin (similar to what was done before
for the JSCallWithArrayLike operator), and use that operator to
optimize Reflect.construct inlining in TurboFan. This is handled
uniformly with JSConstructWithSpread in the JSCallReducer.

Also add missing test coverage for Reflect.construct in optimized
code, especially for some interesting corner cases.

R=petermarshall@chromium.org
BUG=v8:4587,v8:5269

Review-Url: https://codereview.chromium.org/2949813002
Cr-Commit-Position: refs/heads/master@{#46087}
parent 72a597fa
......@@ -2070,39 +2070,17 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
// -- sp[0] : receiver (undefined)
// -----------------------------------
// 2. Make sure the target is actually a constructor.
Label target_not_constructor;
__ JumpIfSmi(r1, &target_not_constructor);
__ ldr(r4, FieldMemOperand(r1, HeapObject::kMapOffset));
__ ldrb(r4, FieldMemOperand(r4, Map::kBitFieldOffset));
__ tst(r4, Operand(1 << Map::kIsConstructor));
__ b(eq, &target_not_constructor);
// 2. We don't need to check explicitly for constructor target here,
// since that's the first thing the Construct/ConstructWithArrayLike
// builtins will do.
// 3. Make sure the target is actually a constructor.
Label new_target_not_constructor;
__ JumpIfSmi(r3, &new_target_not_constructor);
__ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
__ ldrb(r4, FieldMemOperand(r4, Map::kBitFieldOffset));
__ tst(r4, Operand(1 << Map::kIsConstructor));
__ b(eq, &new_target_not_constructor);
// 3. We don't need to check explicitly for constructor new.target here,
// since that's the second thing the Construct/ConstructWithArrayLike
// builtins will do.
// 4a. Construct the target with the given new.target and argumentsList.
// 4. Construct the target with the given new.target and argumentsList.
__ Jump(masm->isolate()->builtins()->ConstructWithArrayLike(),
RelocInfo::CODE_TARGET);
// 4b. The target is not a constructor, throw an appropriate TypeError.
__ bind(&target_not_constructor);
{
__ str(r1, MemOperand(sp, 0));
__ TailCallRuntime(Runtime::kThrowNotConstructor);
}
// 4c. The new.target is not a constructor, throw an appropriate TypeError.
__ bind(&new_target_not_constructor);
{
__ str(r3, MemOperand(sp, 0));
__ TailCallRuntime(Runtime::kThrowNotConstructor);
}
}
static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
......
......@@ -2175,39 +2175,17 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
// -- jssp[0] : receiver (undefined)
// -----------------------------------
// 2. Make sure the target is actually a constructor.
Label target_not_constructor;
__ JumpIfSmi(target, &target_not_constructor);
__ Ldr(x10, FieldMemOperand(target, HeapObject::kMapOffset));
__ Ldrb(x10, FieldMemOperand(x10, Map::kBitFieldOffset));
__ TestAndBranchIfAllClear(x10, 1 << Map::kIsConstructor,
&target_not_constructor);
// 3. Make sure the new.target is actually a constructor.
Label new_target_not_constructor;
__ JumpIfSmi(new_target, &new_target_not_constructor);
__ Ldr(x10, FieldMemOperand(new_target, HeapObject::kMapOffset));
__ Ldrb(x10, FieldMemOperand(x10, Map::kBitFieldOffset));
__ TestAndBranchIfAllClear(x10, 1 << Map::kIsConstructor,
&new_target_not_constructor);
// 4a. Construct the target with the given new.target and argumentsList.
__ Jump(masm->isolate()->builtins()->ConstructWithArrayLike(),
RelocInfo::CODE_TARGET);
// 2. We don't need to check explicitly for constructor target here,
// since that's the first thing the Construct/ConstructWithArrayLike
// builtins will do.
// 4b. The target is not a constructor, throw an appropriate TypeError.
__ Bind(&target_not_constructor);
{
__ Poke(target, 0);
__ TailCallRuntime(Runtime::kThrowNotConstructor);
}
// 3. We don't need to check explicitly for constructor new.target here,
// since that's the second thing the Construct/ConstructWithArrayLike
// builtins will do.
// 4c. The new.target is not a constructor, throw an appropriate TypeError.
__ Bind(&new_target_not_constructor);
{
__ Poke(new_target, 0);
__ TailCallRuntime(Runtime::kThrowNotConstructor);
}
// 4. Construct the target with the given new.target and argumentsList.
__ Jump(masm->isolate()->builtins()->ConstructWithArrayLike(),
RelocInfo::CODE_TARGET);
}
static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
......
......@@ -120,6 +120,32 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike(
Unreachable();
}
BIND(&if_target_callable);
} else {
// Check that {target} is a Constructor.
Label if_target_constructor(this),
if_target_not_constructor(this, Label::kDeferred);
GotoIf(TaggedIsSmi(target), &if_target_not_constructor);
Branch(IsConstructor(target), &if_target_constructor,
&if_target_not_constructor);
BIND(&if_target_not_constructor);
{
CallRuntime(Runtime::kThrowNotConstructor, context, target);
Unreachable();
}
BIND(&if_target_constructor);
// Check that {new_target} is a Constructor.
Label if_new_target_constructor(this),
if_new_target_not_constructor(this, Label::kDeferred);
GotoIf(TaggedIsSmi(new_target), &if_new_target_not_constructor);
Branch(IsConstructor(new_target), &if_new_target_constructor,
&if_new_target_not_constructor);
BIND(&if_new_target_not_constructor);
{
CallRuntime(Runtime::kThrowNotConstructor, context, new_target);
Unreachable();
}
BIND(&if_new_target_constructor);
}
GotoIf(TaggedIsSmi(arguments_list), &if_runtime);
......
......@@ -1858,39 +1858,17 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
// -- esp[4] : receiver (undefined)
// -----------------------------------
// 2. Make sure the target is actually a constructor.
Label target_not_constructor;
__ JumpIfSmi(edi, &target_not_constructor, Label::kNear);
__ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
__ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
Immediate(1 << Map::kIsConstructor));
__ j(zero, &target_not_constructor, Label::kNear);
// 2. We don't need to check explicitly for constructor target here,
// since that's the first thing the Construct/ConstructWithArrayLike
// builtins will do.
// 3. Make sure the target is actually a constructor.
Label new_target_not_constructor;
__ JumpIfSmi(edx, &new_target_not_constructor, Label::kNear);
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
__ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
Immediate(1 << Map::kIsConstructor));
__ j(zero, &new_target_not_constructor, Label::kNear);
// 3. We don't need to check explicitly for constructor new.target here,
// since that's the second thing the Construct/ConstructWithArrayLike
// builtins will do.
// 4a. Construct the target with the given new.target and argumentsList.
// 4. Construct the target with the given new.target and argumentsList.
__ Jump(masm->isolate()->builtins()->ConstructWithArrayLike(),
RelocInfo::CODE_TARGET);
// 4b. The target is not a constructor, throw an appropriate TypeError.
__ bind(&target_not_constructor);
{
__ mov(Operand(esp, kPointerSize), edi);
__ TailCallRuntime(Runtime::kThrowNotConstructor);
}
// 4c. The new.target is not a constructor, throw an appropriate TypeError.
__ bind(&new_target_not_constructor);
{
__ mov(Operand(esp, kPointerSize), edx);
__ TailCallRuntime(Runtime::kThrowNotConstructor);
}
}
void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
......
......@@ -2085,39 +2085,17 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
// -- sp[0] : receiver (undefined)
// -----------------------------------
// 2. Make sure the target is actually a constructor.
Label target_not_constructor;
__ JumpIfSmi(a1, &target_not_constructor);
__ lw(t0, FieldMemOperand(a1, HeapObject::kMapOffset));
__ lbu(t0, FieldMemOperand(t0, Map::kBitFieldOffset));
__ And(t0, t0, Operand(1 << Map::kIsConstructor));
__ Branch(&target_not_constructor, eq, t0, Operand(zero_reg));
// 3. Make sure the target is actually a constructor.
Label new_target_not_constructor;
__ JumpIfSmi(a3, &new_target_not_constructor);
__ lw(t0, FieldMemOperand(a3, HeapObject::kMapOffset));
__ lbu(t0, FieldMemOperand(t0, Map::kBitFieldOffset));
__ And(t0, t0, Operand(1 << Map::kIsConstructor));
__ Branch(&new_target_not_constructor, eq, t0, Operand(zero_reg));
// 4a. Construct the target with the given new.target and argumentsList.
__ Jump(masm->isolate()->builtins()->ConstructWithArrayLike(),
RelocInfo::CODE_TARGET);
// 2. We don't need to check explicitly for constructor target here,
// since that's the first thing the Construct/ConstructWithArrayLike
// builtins will do.
// 4b. The target is not a constructor, throw an appropriate TypeError.
__ bind(&target_not_constructor);
{
__ sw(a1, MemOperand(sp));
__ TailCallRuntime(Runtime::kThrowNotConstructor);
}
// 3. We don't need to check explicitly for constructor new.target here,
// since that's the second thing the Construct/ConstructWithArrayLike
// builtins will do.
// 4c. The new.target is not a constructor, throw an appropriate TypeError.
__ bind(&new_target_not_constructor);
{
__ sw(a3, MemOperand(sp));
__ TailCallRuntime(Runtime::kThrowNotConstructor);
}
// 4. Construct the target with the given new.target and argumentsList.
__ Jump(masm->isolate()->builtins()->ConstructWithArrayLike(),
RelocInfo::CODE_TARGET);
}
static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
......
......@@ -2101,39 +2101,17 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
// -- sp[0] : receiver (undefined)
// -----------------------------------
// 2. Make sure the target is actually a constructor.
Label target_not_constructor;
__ JumpIfSmi(target, &target_not_constructor);
__ Ld(a4, FieldMemOperand(target, HeapObject::kMapOffset));
__ Lbu(a4, FieldMemOperand(a4, Map::kBitFieldOffset));
__ And(a4, a4, Operand(1 << Map::kIsConstructor));
__ Branch(&target_not_constructor, eq, a4, Operand(zero_reg));
// 3. Make sure the target is actually a constructor.
Label new_target_not_constructor;
__ JumpIfSmi(new_target, &new_target_not_constructor);
__ Ld(a4, FieldMemOperand(new_target, HeapObject::kMapOffset));
__ Lbu(a4, FieldMemOperand(a4, Map::kBitFieldOffset));
__ And(a4, a4, Operand(1 << Map::kIsConstructor));
__ Branch(&new_target_not_constructor, eq, a4, Operand(zero_reg));
// 4a. Construct the target with the given new.target and argumentsList.
__ Jump(masm->isolate()->builtins()->ConstructWithArrayLike(),
RelocInfo::CODE_TARGET);
// 2. We don't need to check explicitly for constructor target here,
// since that's the first thing the Construct/ConstructWithArrayLike
// builtins will do.
// 4b. The target is not a constructor, throw an appropriate TypeError.
__ bind(&target_not_constructor);
{
__ Sd(target, MemOperand(sp));
__ TailCallRuntime(Runtime::kThrowNotConstructor);
}
// 3. We don't need to check explicitly for constructor new.target here,
// since that's the second thing the Construct/ConstructWithArrayLike
// builtins will do.
// 4c. The new.target is not a constructor, throw an appropriate TypeError.
__ bind(&new_target_not_constructor);
{
__ Sd(new_target, MemOperand(sp));
__ TailCallRuntime(Runtime::kThrowNotConstructor);
}
// 4. Construct the target with the given new.target and argumentsList.
__ Jump(masm->isolate()->builtins()->ConstructWithArrayLike(),
RelocInfo::CODE_TARGET);
}
static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
......
......@@ -1839,41 +1839,17 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
// -- rsp[8] : receiver (undefined)
// -----------------------------------
// 2. Make sure the target is actually a constructor.
Label target_not_constructor;
__ JumpIfSmi(rdi, &target_not_constructor, Label::kNear);
__ movp(rcx, FieldOperand(rdi, HeapObject::kMapOffset));
__ testb(FieldOperand(rcx, Map::kBitFieldOffset),
Immediate(1 << Map::kIsConstructor));
__ j(zero, &target_not_constructor, Label::kNear);
// 2. We don't need to check explicitly for constructor target here,
// since that's the first thing the Construct/ConstructWithArrayLike
// builtins will do.
// 3. Make sure the target is actually a constructor.
Label new_target_not_constructor;
__ JumpIfSmi(rdx, &new_target_not_constructor, Label::kNear);
__ movp(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
__ testb(FieldOperand(rcx, Map::kBitFieldOffset),
Immediate(1 << Map::kIsConstructor));
__ j(zero, &new_target_not_constructor, Label::kNear);
// 3. We don't need to check explicitly for constructor new.target here,
// since that's the second thing the Construct/ConstructWithArrayLike
// builtins will do.
// 4a. Construct the target with the given new.target and argumentsList.
// 4. Construct the target with the given new.target and argumentsList.
__ Jump(masm->isolate()->builtins()->ConstructWithArrayLike(),
RelocInfo::CODE_TARGET);
// 4b. The target is not a constructor, throw an appropriate TypeError.
__ bind(&target_not_constructor);
{
StackArgumentsAccessor args(rsp, 0);
__ movp(args.GetReceiverOperand(), rdi);
__ TailCallRuntime(Runtime::kThrowNotConstructor);
}
// 4c. The new.target is not a constructor, throw an appropriate TypeError.
__ bind(&new_target_not_constructor);
{
StackArgumentsAccessor args(rsp, 0);
__ movp(args.GetReceiverOperand(), rdx);
__ TailCallRuntime(Runtime::kThrowNotConstructor);
}
}
void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
......
......@@ -3204,6 +3204,10 @@ Node* CodeStubAssembler::IsConstructorMap(Node* map) {
return IsSetWord32(LoadMapBitField(map), 1 << Map::kIsConstructor);
}
Node* CodeStubAssembler::IsConstructor(Node* object) {
return IsConstructorMap(LoadMap(object));
}
Node* CodeStubAssembler::IsSpecialReceiverInstanceType(Node* instance_type) {
STATIC_ASSERT(JS_GLOBAL_OBJECT_TYPE <= LAST_SPECIAL_RECEIVER_TYPE);
return Int32LessThanOrEqual(instance_type,
......
......@@ -774,6 +774,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* IsCallable(Node* object);
Node* IsConsStringInstanceType(Node* instance_type);
Node* IsConstructorMap(Node* map);
Node* IsConstructor(Node* object);
Node* IsDeprecatedMap(Node* map);
Node* IsDictionary(Node* object);
Node* IsExternalStringInstanceType(Node* instance_type);
......
......@@ -24,6 +24,8 @@ Reduction JSCallReducer::Reduce(Node* node) {
switch (node->opcode()) {
case IrOpcode::kJSConstruct:
return ReduceJSConstruct(node);
case IrOpcode::kJSConstructWithArrayLike:
return ReduceJSConstructWithArrayLike(node);
case IrOpcode::kJSConstructWithSpread:
return ReduceJSConstructWithSpread(node);
case IrOpcode::kJSCall:
......@@ -436,6 +438,30 @@ Reduction JSCallReducer::ReduceReflectApply(Node* node) {
return reduction.Changed() ? reduction : Changed(node);
}
// ES6 section 26.1.2 Reflect.construct ( target, argumentsList [, newTarget] )
Reduction JSCallReducer::ReduceReflectConstruct(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
int arity = static_cast<int>(p.arity() - 2);
DCHECK_LE(0, arity);
// Massage value inputs appropriately.
node->RemoveInput(0);
node->RemoveInput(0);
while (arity < 2) {
node->InsertInput(graph()->zone(), arity++, jsgraph()->UndefinedConstant());
}
if (arity < 3) {
node->InsertInput(graph()->zone(), arity++, node->InputAt(0));
}
while (arity-- > 3) {
node->RemoveInput(arity);
}
NodeProperties::ChangeOp(node,
javascript()->ConstructWithArrayLike(p.frequency()));
Reduction const reduction = ReduceJSConstructWithArrayLike(node);
return reduction.Changed() ? reduction : Changed(node);
}
// ES6 section 26.1.7 Reflect.getPrototypeOf ( target )
Reduction JSCallReducer::ReduceReflectGetPrototypeOf(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
......@@ -664,6 +690,7 @@ Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
Node* node, int arity, CallFrequency const& frequency) {
DCHECK(node->opcode() == IrOpcode::kJSCallWithArrayLike ||
node->opcode() == IrOpcode::kJSCallWithSpread ||
node->opcode() == IrOpcode::kJSConstructWithArrayLike ||
node->opcode() == IrOpcode::kJSConstructWithSpread);
// In case of a call/construct with spread, we need to
......@@ -855,6 +882,8 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
return ReduceObjectPrototypeIsPrototypeOf(node);
case Builtins::kReflectApply:
return ReduceReflectApply(node);
case Builtins::kReflectConstruct:
return ReduceReflectConstruct(node);
case Builtins::kReflectGetPrototypeOf:
return ReduceReflectGetPrototypeOf(node);
case Builtins::kArrayForEach:
......@@ -1118,6 +1147,12 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
return NoChange();
}
Reduction JSCallReducer::ReduceJSConstructWithArrayLike(Node* node) {
DCHECK_EQ(IrOpcode::kJSConstructWithArrayLike, node->opcode());
CallFrequency frequency = CallFrequencyOf(node->op());
return ReduceCallOrConstructWithArrayLikeOrSpread(node, 1, frequency);
}
Reduction JSCallReducer::ReduceJSConstructWithSpread(Node* node) {
DCHECK_EQ(IrOpcode::kJSConstructWithSpread, node->opcode());
SpreadWithArityParameter const& p = SpreadWithArityParameterOf(node->op());
......
......@@ -52,11 +52,13 @@ class JSCallReducer final : public AdvancedReducer {
Reduction ReduceObjectPrototypeGetProto(Node* node);
Reduction ReduceObjectPrototypeIsPrototypeOf(Node* node);
Reduction ReduceReflectApply(Node* node);
Reduction ReduceReflectConstruct(Node* node);
Reduction ReduceReflectGetPrototypeOf(Node* node);
Reduction ReduceArrayForEach(Handle<JSFunction> function, Node* node);
Reduction ReduceCallOrConstructWithArrayLikeOrSpread(
Node* node, int arity, CallFrequency const& frequency);
Reduction ReduceJSConstruct(Node* node);
Reduction ReduceJSConstructWithArrayLike(Node* node);
Reduction ReduceJSConstructWithSpread(Node* node);
Reduction ReduceJSCall(Node* node);
Reduction ReduceJSCallWithArrayLike(Node* node);
......
......@@ -589,6 +589,23 @@ void JSGenericLowering::LowerJSConstruct(Node* node) {
NodeProperties::ChangeOp(node, common()->Call(desc));
}
void JSGenericLowering::LowerJSConstructWithArrayLike(Node* node) {
Callable callable =
Builtins::CallableFor(isolate(), Builtins::kConstructWithArrayLike);
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), zone(), callable.descriptor(), 1, flags);
Node* stub_code = jsgraph()->HeapConstant(callable.code());
Node* receiver = jsgraph()->UndefinedConstant();
Node* arguments_list = node->InputAt(1);
Node* new_target = node->InputAt(2);
node->InsertInput(zone(), 0, stub_code);
node->ReplaceInput(2, new_target);
node->ReplaceInput(3, arguments_list);
node->InsertInput(zone(), 4, receiver);
NodeProperties::ChangeOp(node, common()->Call(desc));
}
void JSGenericLowering::LowerJSConstructWithSpread(Node* node) {
SpreadWithArityParameter const& p = SpreadWithArityParameterOf(node->op());
int const arg_count = static_cast<int>(p.arity() - 2);
......
......@@ -23,7 +23,8 @@ std::ostream& operator<<(std::ostream& os, CallFrequency f) {
}
CallFrequency CallFrequencyOf(Operator const* op) {
DCHECK_EQ(IrOpcode::kJSCallWithArrayLike, op->opcode());
DCHECK(op->opcode() == IrOpcode::kJSCallWithArrayLike ||
op->opcode() == IrOpcode::kJSConstructWithArrayLike);
return OpParameter<CallFrequency>(op);
}
......@@ -888,6 +889,16 @@ const Operator* JSOperatorBuilder::Construct(uint32_t arity,
parameters); // parameter
}
const Operator* JSOperatorBuilder::ConstructWithArrayLike(
CallFrequency frequency) {
return new (zone()) Operator1<CallFrequency>( // --
IrOpcode::kJSConstructWithArrayLike, // opcode
Operator::kNoProperties, // properties
"JSConstructWithArrayLike", // name
3, 1, 1, 1, 1, 2, // counts
frequency); // parameter
}
const Operator* JSOperatorBuilder::ConstructWithSpread(uint32_t arity) {
SpreadWithArityParameter parameters(arity);
return new (zone()) Operator1<SpreadWithArityParameter>( // --
......
......@@ -743,6 +743,7 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* Construct(uint32_t arity,
CallFrequency frequency = CallFrequency(),
VectorSlotPair const& feedback = VectorSlotPair());
const Operator* ConstructWithArrayLike(CallFrequency frequency);
const Operator* ConstructWithSpread(uint32_t arity);
const Operator* ConvertReceiver(ConvertReceiverMode convert_mode);
......
......@@ -163,6 +163,7 @@
#define JS_OTHER_OP_LIST(V) \
V(JSConstructForwardVarargs) \
V(JSConstruct) \
V(JSConstructWithArrayLike) \
V(JSConstructWithSpread) \
V(JSCallForwardVarargs) \
V(JSCall) \
......
......@@ -100,6 +100,7 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
// Call operations
case IrOpcode::kJSConstructForwardVarargs:
case IrOpcode::kJSConstruct:
case IrOpcode::kJSConstructWithArrayLike:
case IrOpcode::kJSConstructWithSpread:
case IrOpcode::kJSCallForwardVarargs:
case IrOpcode::kJSCall:
......
......@@ -1342,6 +1342,10 @@ Type* Typer::Visitor::TypeJSConstructForwardVarargs(Node* node) {
Type* Typer::Visitor::TypeJSConstruct(Node* node) { return Type::Receiver(); }
Type* Typer::Visitor::TypeJSConstructWithArrayLike(Node* node) {
return Type::Receiver();
}
Type* Typer::Visitor::TypeJSConstructWithSpread(Node* node) {
return Type::Receiver();
}
......
......@@ -714,6 +714,7 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kJSConstructForwardVarargs:
case IrOpcode::kJSConstruct:
case IrOpcode::kJSConstructWithArrayLike:
case IrOpcode::kJSConstructWithSpread:
case IrOpcode::kJSConvertReceiver:
// Type is Receiver.
......
// Copyright 2017 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
// Test Reflect.construct with wrong number of arguments.
(function() {
"use strict";
function A() {}
function foo() { return Reflect.construct(A); }
assertThrows(foo);
assertThrows(foo);
%OptimizeFunctionOnNextCall(foo);
assertThrows(foo);
})();
(function() {
"use strict";
function A(x) { this.x = x; }
function foo() { return Reflect.construct(A, arguments); }
assertInstanceof(foo(), A);
assertInstanceof(foo(), A);
assertEquals(1, foo(1).x);
%OptimizeFunctionOnNextCall(foo);
assertInstanceof(foo(), A);
assertEquals(1, foo(1).x);
})();
(function() {
"use strict";
function A(x) { this.x = x; }
function foo() { return Reflect.construct(A, arguments, A, A); }
assertInstanceof(foo(), A);
assertInstanceof(foo(), A);
assertEquals(1, foo(1).x);
%OptimizeFunctionOnNextCall(foo);
assertInstanceof(foo(), A);
assertEquals(1, foo(1).x);
})();
// Test Reflect.construct within try/catch.
(function() {
"use strict";
function foo(bar) {
try {
return Reflect.construct(bar, arguments, bar);
} catch (e) {
return 1;
}
}
assertEquals(1, foo());
assertEquals(1, foo());
%OptimizeFunctionOnNextCall(foo);
assertEquals(1, foo());
})();
(function() {
"use strict";
function foo(bar) {
try {
return Reflect.construct(bar, bar, bar);
} catch (e) {
return 1;
}
}
assertEquals(1, foo());
assertEquals(1, foo());
%OptimizeFunctionOnNextCall(foo);
assertEquals(1, foo());
})();
// Test proper order of constructor check(s) and array-like iteration.
(function() {
var dummy_length_counter = 0;
var dummy = { get length() { ++dummy_length_counter; return 0; } };
function foo() {
return Reflect.construct(undefined, dummy, undefined);
}
assertThrows(foo, TypeError);
assertThrows(foo, TypeError);
%OptimizeFunctionOnNextCall(foo);
assertThrows(foo, TypeError);
assertEquals(0, dummy_length_counter);
})();
(function() {
var dummy_length_counter = 0;
var dummy = { get length() { ++dummy_length_counter; return 0; } };
function foo() {
return Reflect.construct(undefined, dummy);
}
assertThrows(foo, TypeError);
assertThrows(foo, TypeError);
%OptimizeFunctionOnNextCall(foo);
assertThrows(foo, TypeError);
assertEquals(0, dummy_length_counter);
})();
(function() {
var dummy_length_counter = 0;
var dummy = { get length() { ++dummy_length_counter; return 0; } };
function foo() {
return Reflect.construct(null, dummy, null);
}
assertThrows(foo, TypeError);
assertThrows(foo, TypeError);
%OptimizeFunctionOnNextCall(foo);
assertThrows(foo, TypeError);
assertEquals(0, dummy_length_counter);
})();(function() {
var dummy_length_counter = 0;
var dummy = { get length() { ++dummy_length_counter; return 0; } };
function foo() {
return Reflect.construct(null, dummy);
}
assertThrows(foo, TypeError);
assertThrows(foo, TypeError);
%OptimizeFunctionOnNextCall(foo);
assertThrows(foo, TypeError);
assertEquals(0, dummy_length_counter);
})();
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