Commit 796fdcd0 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[nci] Modify Construct node layouts

Prior to this CL, the construct node layout was:

 {target, args..., new_target}

The new layout is:

 {target, new_target, args..., feedback_vector}

Having new_target at index 1 brings it closer to call node layout,
which is now identical except that it has receiver at index 1. The new
feedback vector input will be needed for NCI code.

Affected node kinds are:

- JSConstruct
- JSConstructWithArrayLike
- JSConstructWithSpread
- JSConstructForwardVarargs (just the new_target position change)

Bug: v8:8888
Change-Id: I4c68a0901d01e8862fd276c8a858799d5f4ff024
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2278475
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68692}
parent 97bde191
...@@ -2587,10 +2587,12 @@ Node* const* BytecodeGraphBuilder::GetConstructArgumentsFromRegister( ...@@ -2587,10 +2587,12 @@ Node* const* BytecodeGraphBuilder::GetConstructArgumentsFromRegister(
int cursor = 0; int cursor = 0;
STATIC_ASSERT(JSConstructNode::TargetIndex() == 0); STATIC_ASSERT(JSConstructNode::TargetIndex() == 0);
STATIC_ASSERT(JSConstructNode::FirstArgumentIndex() == 1); STATIC_ASSERT(JSConstructNode::NewTargetIndex() == 1);
STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput); STATIC_ASSERT(JSConstructNode::FirstArgumentIndex() == 2);
STATIC_ASSERT(JSConstructNode::kFeedbackVectorIsLastInput);
all[cursor++] = target; all[cursor++] = target;
all[cursor++] = new_target;
// The function arguments are in consecutive registers. // The function arguments are in consecutive registers.
int arg_base = first_arg.index(); int arg_base = first_arg.index();
...@@ -2599,7 +2601,7 @@ Node* const* BytecodeGraphBuilder::GetConstructArgumentsFromRegister( ...@@ -2599,7 +2601,7 @@ Node* const* BytecodeGraphBuilder::GetConstructArgumentsFromRegister(
environment()->LookupRegister(interpreter::Register(arg_base + i)); environment()->LookupRegister(interpreter::Register(arg_base + i));
} }
all[cursor++] = new_target; all[cursor++] = feedback_vector_node();
DCHECK_EQ(cursor, arity); DCHECK_EQ(cursor, arity);
return all; return all;
......
This diff is collapsed.
...@@ -737,6 +737,7 @@ bool CollectCallAndConstructFeedback(JSHeapBroker* broker) { ...@@ -737,6 +737,7 @@ bool CollectCallAndConstructFeedback(JSHeapBroker* broker) {
} // namespace } // namespace
// TODO(jgruber,v8:8888): Should this collect feedback?
void JSGenericLowering::LowerJSConstructForwardVarargs(Node* node) { void JSGenericLowering::LowerJSConstructForwardVarargs(Node* node) {
ConstructForwardVarargsParameters p = ConstructForwardVarargsParameters p =
ConstructForwardVarargsParametersOf(node->op()); ConstructForwardVarargsParametersOf(node->op());
...@@ -748,11 +749,8 @@ void JSGenericLowering::LowerJSConstructForwardVarargs(Node* node) { ...@@ -748,11 +749,8 @@ void JSGenericLowering::LowerJSConstructForwardVarargs(Node* node) {
Node* stub_code = jsgraph()->HeapConstant(callable.code()); Node* stub_code = jsgraph()->HeapConstant(callable.code());
Node* stub_arity = jsgraph()->Int32Constant(arg_count); Node* stub_arity = jsgraph()->Int32Constant(arg_count);
Node* start_index = jsgraph()->Uint32Constant(p.start_index()); Node* start_index = jsgraph()->Uint32Constant(p.start_index());
Node* new_target = node->InputAt(arg_count + 1);
Node* receiver = jsgraph()->UndefinedConstant(); Node* receiver = jsgraph()->UndefinedConstant();
node->RemoveInput(arg_count + 1); // Drop new target.
node->InsertInput(zone(), 0, stub_code); node->InsertInput(zone(), 0, stub_code);
node->InsertInput(zone(), 2, new_target);
node->InsertInput(zone(), 3, stub_arity); node->InsertInput(zone(), 3, stub_arity);
node->InsertInput(zone(), 4, start_index); node->InsertInput(zone(), 4, start_index);
node->InsertInput(zone(), 5, receiver); node->InsertInput(zone(), 5, receiver);
...@@ -776,22 +774,16 @@ void JSGenericLowering::LowerJSConstruct(Node* node) { ...@@ -776,22 +774,16 @@ void JSGenericLowering::LowerJSConstruct(Node* node) {
Builtins::CallableFor(isolate(), Builtins::kConstruct_WithFeedback); Builtins::CallableFor(isolate(), Builtins::kConstruct_WithFeedback);
auto call_descriptor = Linkage::GetStubCallDescriptor( auto call_descriptor = Linkage::GetStubCallDescriptor(
zone(), callable.descriptor(), stack_argument_count, flags); zone(), callable.descriptor(), stack_argument_count, flags);
STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput);
Node* feedback_vector = jsgraph()->HeapConstant(p.feedback().vector);
Node* stub_code = jsgraph()->HeapConstant(callable.code()); Node* stub_code = jsgraph()->HeapConstant(callable.code());
Node* new_target = n.new_target();
Node* stub_arity = jsgraph()->Int32Constant(arg_count); Node* stub_arity = jsgraph()->Int32Constant(arg_count);
Node* slot = jsgraph()->Int32Constant(p.feedback().index()); Node* slot = jsgraph()->Int32Constant(p.feedback().index());
Node* receiver = jsgraph()->UndefinedConstant(); Node* receiver = jsgraph()->UndefinedConstant();
node->RemoveInput(n.NewTargetIndex());
// Register argument inputs are followed by stack argument inputs (such as // Register argument inputs are followed by stack argument inputs (such as
// feedback_vector). Both are listed in ascending order. Note that // feedback_vector). Both are listed in ascending order. Note that
// the receiver is implicitly placed on the stack and is thus inserted // the receiver is implicitly placed on the stack and is thus inserted
// between explicitly-specified register and stack arguments. // between explicitly-specified register and stack arguments.
// TODO(jgruber): Implement a simpler way to specify these mutations. // TODO(jgruber): Implement a simpler way to specify these mutations.
node->InsertInput(zone(), arg_count + 1, feedback_vector);
node->InsertInput(zone(), 0, stub_code); node->InsertInput(zone(), 0, stub_code);
node->InsertInput(zone(), 2, new_target);
node->InsertInput(zone(), 3, stub_arity); node->InsertInput(zone(), 3, stub_arity);
node->InsertInput(zone(), 4, slot); node->InsertInput(zone(), 4, slot);
node->InsertInput(zone(), 5, receiver); node->InsertInput(zone(), 5, receiver);
...@@ -807,11 +799,9 @@ void JSGenericLowering::LowerJSConstruct(Node* node) { ...@@ -807,11 +799,9 @@ void JSGenericLowering::LowerJSConstruct(Node* node) {
zone(), callable.descriptor(), stack_argument_count, flags); zone(), callable.descriptor(), stack_argument_count, flags);
Node* stub_code = jsgraph()->HeapConstant(callable.code()); Node* stub_code = jsgraph()->HeapConstant(callable.code());
Node* stub_arity = jsgraph()->Int32Constant(arg_count); Node* stub_arity = jsgraph()->Int32Constant(arg_count);
Node* new_target = n.new_target();
Node* receiver = jsgraph()->UndefinedConstant(); Node* receiver = jsgraph()->UndefinedConstant();
node->RemoveInput(n.NewTargetIndex()); node->RemoveInput(n.FeedbackVectorIndex());
node->InsertInput(zone(), 0, stub_code); node->InsertInput(zone(), 0, stub_code);
node->InsertInput(zone(), 2, new_target);
node->InsertInput(zone(), 3, stub_arity); node->InsertInput(zone(), 3, stub_arity);
node->InsertInput(zone(), 4, receiver); node->InsertInput(zone(), 4, receiver);
...@@ -842,23 +832,16 @@ void JSGenericLowering::LowerJSConstructWithArrayLike(Node* node) { ...@@ -842,23 +832,16 @@ void JSGenericLowering::LowerJSConstructWithArrayLike(Node* node) {
zone(), callable.descriptor(), stack_argument_count, flags); zone(), callable.descriptor(), stack_argument_count, flags);
Node* stub_code = jsgraph()->HeapConstant(callable.code()); Node* stub_code = jsgraph()->HeapConstant(callable.code());
Node* receiver = jsgraph()->UndefinedConstant(); Node* receiver = jsgraph()->UndefinedConstant();
Node* arguments_list = n.Argument(0);
Node* new_target = n.new_target();
STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput);
Node* feedback_vector = jsgraph()->HeapConstant(p.feedback().vector);
Node* slot = jsgraph()->Int32Constant(p.feedback().index()); Node* slot = jsgraph()->Int32Constant(p.feedback().index());
node->InsertInput(zone(), 0, stub_code);
node->ReplaceInput(2, new_target);
node->ReplaceInput(3, arguments_list);
// Register argument inputs are followed by stack argument inputs (such as // Register argument inputs are followed by stack argument inputs (such as
// feedback_vector). Both are listed in ascending order. Note that // feedback_vector). Both are listed in ascending order. Note that
// the receiver is implicitly placed on the stack and is thus inserted // the receiver is implicitly placed on the stack and is thus inserted
// between explicitly-specified register and stack arguments. // between explicitly-specified register and stack arguments.
// TODO(jgruber): Implement a simpler way to specify these mutations. // TODO(jgruber): Implement a simpler way to specify these mutations.
node->InsertInput(zone(), 0, stub_code);
node->InsertInput(zone(), 4, slot); node->InsertInput(zone(), 4, slot);
node->InsertInput(zone(), 5, receiver); node->InsertInput(zone(), 5, receiver);
node->InsertInput(zone(), 6, feedback_vector);
// After: {code, target, new_target, arguments_list, slot, receiver, // After: {code, target, new_target, arguments_list, slot, receiver,
// vector}. // vector}.
...@@ -872,11 +855,8 @@ void JSGenericLowering::LowerJSConstructWithArrayLike(Node* node) { ...@@ -872,11 +855,8 @@ void JSGenericLowering::LowerJSConstructWithArrayLike(Node* node) {
zone(), callable.descriptor(), stack_argument_count, flags); zone(), callable.descriptor(), stack_argument_count, flags);
Node* stub_code = jsgraph()->HeapConstant(callable.code()); Node* stub_code = jsgraph()->HeapConstant(callable.code());
Node* receiver = jsgraph()->UndefinedConstant(); Node* receiver = jsgraph()->UndefinedConstant();
Node* arguments_list = n.Argument(0); node->RemoveInput(n.FeedbackVectorIndex());
Node* new_target = n.new_target();
node->InsertInput(zone(), 0, stub_code); node->InsertInput(zone(), 0, stub_code);
node->ReplaceInput(2, new_target);
node->ReplaceInput(3, arguments_list);
node->InsertInput(zone(), 4, receiver); node->InsertInput(zone(), 4, receiver);
// After: {code, target, new_target, arguments_list, receiver}. // After: {code, target, new_target, arguments_list, receiver}.
...@@ -905,14 +885,11 @@ void JSGenericLowering::LowerJSConstructWithSpread(Node* node) { ...@@ -905,14 +885,11 @@ void JSGenericLowering::LowerJSConstructWithSpread(Node* node) {
auto call_descriptor = Linkage::GetStubCallDescriptor( auto call_descriptor = Linkage::GetStubCallDescriptor(
zone(), callable.descriptor(), stack_argument_count, flags); zone(), callable.descriptor(), stack_argument_count, flags);
Node* stub_code = jsgraph()->HeapConstant(callable.code()); Node* stub_code = jsgraph()->HeapConstant(callable.code());
STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput);
Node* feedback_vector = jsgraph()->HeapConstant(p.feedback().vector);
Node* slot = jsgraph()->Int32Constant(p.feedback().index()); Node* slot = jsgraph()->Int32Constant(p.feedback().index());
// The single available register is needed for `slot`, thus `spread` remains // The single available register is needed for `slot`, thus `spread` remains
// on the stack here. // on the stack here.
Node* stub_arity = jsgraph()->Int32Constant(arg_count - kTheSpread); Node* stub_arity = jsgraph()->Int32Constant(arg_count - kTheSpread);
Node* new_target = node->RemoveInput(n.NewTargetIndex());
Node* receiver = jsgraph()->UndefinedConstant(); Node* receiver = jsgraph()->UndefinedConstant();
// Register argument inputs are followed by stack argument inputs (such as // Register argument inputs are followed by stack argument inputs (such as
...@@ -920,9 +897,7 @@ void JSGenericLowering::LowerJSConstructWithSpread(Node* node) { ...@@ -920,9 +897,7 @@ void JSGenericLowering::LowerJSConstructWithSpread(Node* node) {
// the receiver is implicitly placed on the stack and is thus inserted // the receiver is implicitly placed on the stack and is thus inserted
// between explicitly-specified register and stack arguments. // between explicitly-specified register and stack arguments.
// TODO(jgruber): Implement a simpler way to specify these mutations. // TODO(jgruber): Implement a simpler way to specify these mutations.
node->InsertInput(zone(), arg_count + 1, feedback_vector);
node->InsertInput(zone(), 0, stub_code); node->InsertInput(zone(), 0, stub_code);
node->InsertInput(zone(), 2, new_target);
node->InsertInput(zone(), 3, stub_arity); node->InsertInput(zone(), 3, stub_arity);
node->InsertInput(zone(), 4, slot); node->InsertInput(zone(), 4, slot);
node->InsertInput(zone(), 5, receiver); node->InsertInput(zone(), 5, receiver);
...@@ -941,13 +916,11 @@ void JSGenericLowering::LowerJSConstructWithSpread(Node* node) { ...@@ -941,13 +916,11 @@ void JSGenericLowering::LowerJSConstructWithSpread(Node* node) {
// We pass the spread in a register, not on the stack. // We pass the spread in a register, not on the stack.
Node* stub_arity = jsgraph()->Int32Constant(arg_count - kTheSpread); Node* stub_arity = jsgraph()->Int32Constant(arg_count - kTheSpread);
Node* receiver = jsgraph()->UndefinedConstant(); Node* receiver = jsgraph()->UndefinedConstant();
STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput); DCHECK(n.FeedbackVectorIndex() > n.LastArgumentIndex());
DCHECK(n.NewTargetIndex() > n.LastArgumentIndex()); node->RemoveInput(n.FeedbackVectorIndex());
Node* new_target = node->RemoveInput(n.NewTargetIndex());
Node* spread = node->RemoveInput(n.LastArgumentIndex()); Node* spread = node->RemoveInput(n.LastArgumentIndex());
node->InsertInput(zone(), 0, stub_code); node->InsertInput(zone(), 0, stub_code);
node->InsertInput(zone(), 2, new_target);
node->InsertInput(zone(), 3, stub_arity); node->InsertInput(zone(), 3, stub_arity);
node->InsertInput(zone(), 4, spread); node->InsertInput(zone(), 4, spread);
node->InsertInput(zone(), 5, receiver); node->InsertInput(zone(), 5, receiver);
......
...@@ -629,6 +629,8 @@ void JSInliningHeuristic::CreateOrReuseDispatch(Node* node, Node* callee, ...@@ -629,6 +629,8 @@ void JSInliningHeuristic::CreateOrReuseDispatch(Node* node, Node* callee,
return; return;
} }
STATIC_ASSERT(JSCallOrConstructNode::kHaveIdenticalLayouts);
Node* fallthrough_control = NodeProperties::GetControlInput(node); Node* fallthrough_control = NodeProperties::GetControlInput(node);
int const num_calls = candidate.num_functions; int const num_calls = candidate.num_functions;
...@@ -655,15 +657,13 @@ void JSInliningHeuristic::CreateOrReuseDispatch(Node* node, Node* callee, ...@@ -655,15 +657,13 @@ void JSInliningHeuristic::CreateOrReuseDispatch(Node* node, Node* callee,
// to the same node as the {node}'s target input, so that we can later // to the same node as the {node}'s target input, so that we can later
// properly inline the JSCreate operations. // properly inline the JSCreate operations.
if (node->opcode() == IrOpcode::kJSConstruct) { if (node->opcode() == IrOpcode::kJSConstruct) {
UNREACHABLE(); // https://crbug.com/v8/10675. // TODO(jgruber, v8:10675): This branch seems unreachable.
} JSConstructNode n(node);
if (node->opcode() == IrOpcode::kJSConstruct && inputs[0] == inputs[1]) { if (inputs[n.TargetIndex()] == inputs[n.NewTargetIndex()]) {
// TODO(jgruber): Is this correct? JSConstruct nodes have the new_target inputs[n.NewTargetIndex()] = target;
// at the last index, not at index 1. }
STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput);
inputs[1] = target;
} }
inputs[0] = target; inputs[JSCallOrConstructNode::TargetIndex()] = target;
inputs[input_count - 1] = if_successes[i]; inputs[input_count - 1] = if_successes[i];
calls[i] = if_successes[i] = calls[i] = if_successes[i] =
graph()->NewNode(node->op(), input_count, inputs); graph()->NewNode(node->op(), input_count, inputs);
......
...@@ -51,8 +51,7 @@ class JSCallAccessor { ...@@ -51,8 +51,7 @@ class JSCallAccessor {
} }
Node* target() const { Node* target() const {
STATIC_ASSERT(JSCallNode::TargetIndex() == JSConstructNode::TargetIndex()); return call_->InputAt(JSCallOrConstructNode::TargetIndex());
return call_->InputAt(JSCallNode::TargetIndex());
} }
Node* receiver() const { Node* receiver() const {
...@@ -65,7 +64,7 @@ class JSCallAccessor { ...@@ -65,7 +64,7 @@ class JSCallAccessor {
return NodeProperties::GetFrameStateInput(call_); return NodeProperties::GetFrameStateInput(call_);
} }
int formal_arguments() const { int argument_count() const {
return (call_->opcode() == IrOpcode::kJSCall) return (call_->opcode() == IrOpcode::kJSCall)
? JSCallNode{call_}.ArgumentCount() ? JSCallNode{call_}.ArgumentCount()
: JSConstructNode{call_}.ArgumentCount(); : JSConstructNode{call_}.ArgumentCount();
...@@ -85,6 +84,8 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context, ...@@ -85,6 +84,8 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context,
Node* frame_state, Node* start, Node* end, Node* frame_state, Node* start, Node* end,
Node* exception_target, Node* exception_target,
const NodeVector& uncaught_subcalls) { const NodeVector& uncaught_subcalls) {
JSCallAccessor c(call);
// The scheduler is smart enough to place our code; we just ensure {control} // The scheduler is smart enough to place our code; we just ensure {control}
// becomes the control input of the start of the inlinee, and {effect} becomes // becomes the control input of the start of the inlinee, and {effect} becomes
// the effect input of the start of the inlinee. // the effect input of the start of the inlinee.
...@@ -98,16 +99,11 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context, ...@@ -98,16 +99,11 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context,
int const inlinee_context_index = int const inlinee_context_index =
static_cast<int>(start->op()->ValueOutputCount()) - 1; static_cast<int>(start->op()->ValueOutputCount()) - 1;
// {inliner_inputs} counts JSFunction, receiver, arguments, but not // {inliner_inputs} counts the target, receiver/new_target, and arguments; but
// new target value, argument count, context, effect or control. // not feedback vector, context, effect or control.
// TODO(jgruber): Refactor this once JSConstructNode is implemented. const int inliner_inputs = c.argument_count() +
STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput); JSCallOrConstructNode::kExtraInputCount -
STATIC_ASSERT(JSConstructNode::kExtraInputCount == 2); JSCallOrConstructNode::kFeedbackVectorInputCount;
const bool inliner_is_call = call->opcode() == IrOpcode::kJSCall;
const int inliner_inputs = inliner_is_call
? call->op()->ValueInputCount() -
JSCallNode::kFeedbackVectorInputCount
: call->op()->ValueInputCount();
// Iterate over all uses of the start node. // Iterate over all uses of the start node.
for (Edge edge : start->use_edges()) { for (Edge edge : start->use_edges()) {
Node* use = edge.from(); Node* use = edge.from();
...@@ -124,10 +120,7 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context, ...@@ -124,10 +120,7 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context,
Replace(use, new_target); Replace(use, new_target);
} else if (index == inlinee_arity_index) { } else if (index == inlinee_arity_index) {
// The projection is requesting the number of arguments. // The projection is requesting the number of arguments.
STATIC_ASSERT(JSCallNode::kExtraInputCount == Replace(use, jsgraph()->Constant(c.argument_count()));
JSCallNode::kFeedbackVectorInputCount + 2);
STATIC_ASSERT(JSConstructNode::kExtraInputCount == 2);
Replace(use, jsgraph()->Constant(inliner_inputs - 2));
} else if (index == inlinee_context_index) { } else if (index == inlinee_context_index) {
// The projection is requesting the inlinee function context. // The projection is requesting the inlinee function context.
Replace(use, context); Replace(use, context);
...@@ -245,7 +238,7 @@ Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state, ...@@ -245,7 +238,7 @@ Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state,
SharedFunctionInfoRef shared, SharedFunctionInfoRef shared,
Node* context) { Node* context) {
const int parameter_count_with_receiver = const int parameter_count_with_receiver =
parameter_count + JSCallNode::kReceiverInputCount; parameter_count + JSCallOrConstructNode::kReceiverOrNewTargetInputCount;
const FrameStateFunctionInfo* state_info = const FrameStateFunctionInfo* state_info =
common()->CreateFrameStateFunctionInfo( common()->CreateFrameStateFunctionInfo(
frame_state_type, parameter_count_with_receiver, 0, shared.object()); frame_state_type, parameter_count_with_receiver, 0, shared.object());
...@@ -255,17 +248,11 @@ Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state, ...@@ -255,17 +248,11 @@ Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state,
const Operator* op0 = common()->StateValues(0, SparseInputMask::Dense()); const Operator* op0 = common()->StateValues(0, SparseInputMask::Dense());
Node* node0 = graph()->NewNode(op0); Node* node0 = graph()->NewNode(op0);
// Note how we refer to 'receiver' even though `node` may be a
// JSConstruct node. That's because the layout of construct nodes
// has been modified to look like call nodes in `ReduceJSCall`; the
// `new_target` has been put into the receiver slot.
// TODO(jgruber): Either unify the layout of these two nodes, or
// refactor this to be more expected in some way.
STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput);
NodeVector params(local_zone_); NodeVector params(local_zone_);
params.push_back(node->InputAt(JSCallNode::ReceiverIndex())); params.push_back(
node->InputAt(JSCallOrConstructNode::ReceiverOrNewTargetIndex()));
for (int i = 0; i < parameter_count; i++) { for (int i = 0; i < parameter_count; i++) {
params.push_back(node->InputAt(JSCallNode::ArgumentIndex(i))); params.push_back(node->InputAt(JSCallOrConstructNode::ArgumentIndex(i)));
} }
const Operator* op_param = common()->StateValues( const Operator* op_param = common()->StateValues(
static_cast<int>(params.size()), SparseInputMask::Dense()); static_cast<int>(params.size()), SparseInputMask::Dense());
...@@ -273,7 +260,7 @@ Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state, ...@@ -273,7 +260,7 @@ Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state,
op_param, static_cast<int>(params.size()), &params.front()); op_param, static_cast<int>(params.size()), &params.front());
if (context == nullptr) context = jsgraph()->UndefinedConstant(); if (context == nullptr) context = jsgraph()->UndefinedConstant();
return graph()->NewNode(op, params_node, node0, node0, context, return graph()->NewNode(op, params_node, node0, node0, context,
node->InputAt(JSCallNode::TargetIndex()), node->InputAt(JSCallOrConstructNode::TargetIndex()),
outer_frame_state); outer_frame_state);
} }
...@@ -293,13 +280,12 @@ bool NeedsImplicitReceiver(SharedFunctionInfoRef shared_info) { ...@@ -293,13 +280,12 @@ bool NeedsImplicitReceiver(SharedFunctionInfoRef shared_info) {
base::Optional<SharedFunctionInfoRef> JSInliner::DetermineCallTarget( base::Optional<SharedFunctionInfoRef> JSInliner::DetermineCallTarget(
Node* node) { Node* node) {
DCHECK(IrOpcode::IsInlineeOpcode(node->opcode())); DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
HeapObjectMatcher match(node->InputAt(JSCallNode::TargetIndex())); HeapObjectMatcher match(node->InputAt(JSCallOrConstructNode::TargetIndex()));
// This reducer can handle both normal function calls as well a constructor // This reducer can handle both normal function calls as well a constructor
// calls whenever the target is a constant function object, as follows: // calls whenever the target is a constant function object, as follows:
// - JSCall(target:constant, receiver, args...) // - JSCall(target:constant, receiver, args..., vector)
// - JSConstruct(target:constant, args..., new.target) // - JSConstruct(target:constant, new.target, args..., vector)
STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput);
if (match.HasValue() && match.Ref(broker()).IsJSFunction()) { if (match.HasValue() && match.Ref(broker()).IsJSFunction()) {
JSFunctionRef function = match.Ref(broker()).AsJSFunction(); JSFunctionRef function = match.Ref(broker()).AsJSFunction();
...@@ -325,9 +311,9 @@ base::Optional<SharedFunctionInfoRef> JSInliner::DetermineCallTarget( ...@@ -325,9 +311,9 @@ base::Optional<SharedFunctionInfoRef> JSInliner::DetermineCallTarget(
// This reducer can also handle calls where the target is statically known to // This reducer can also handle calls where the target is statically known to
// be the result of a closure instantiation operation, as follows: // be the result of a closure instantiation operation, as follows:
// - JSCall(JSCreateClosure[shared](context), receiver, args...) // - JSCall(JSCreateClosure[shared](context), receiver, args..., vector)
// - JSConstruct(JSCreateClosure[shared](context), args..., new.target) // - JSConstruct(JSCreateClosure[shared](context),
STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput); // new.target, args..., vector)
if (match.IsJSCreateClosure()) { if (match.IsJSCreateClosure()) {
CreateClosureParameters const& p = CreateClosureParametersOf(match.op()); CreateClosureParameters const& p = CreateClosureParametersOf(match.op());
FeedbackCellRef cell(broker(), p.feedback_cell()); FeedbackCellRef cell(broker(), p.feedback_cell());
...@@ -348,7 +334,7 @@ base::Optional<SharedFunctionInfoRef> JSInliner::DetermineCallTarget( ...@@ -348,7 +334,7 @@ base::Optional<SharedFunctionInfoRef> JSInliner::DetermineCallTarget(
FeedbackVectorRef JSInliner::DetermineCallContext(Node* node, FeedbackVectorRef JSInliner::DetermineCallContext(Node* node,
Node** context_out) { Node** context_out) {
DCHECK(IrOpcode::IsInlineeOpcode(node->opcode())); DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
HeapObjectMatcher match(node->InputAt(JSCallNode::TargetIndex())); HeapObjectMatcher match(node->InputAt(JSCallOrConstructNode::TargetIndex()));
if (match.HasValue() && match.Ref(broker()).IsJSFunction()) { if (match.HasValue() && match.Ref(broker()).IsJSFunction()) {
JSFunctionRef function = match.Ref(broker()).AsJSFunction(); JSFunctionRef function = match.Ref(broker()).AsJSFunction();
...@@ -515,13 +501,10 @@ Reduction JSInliner::ReduceJSCall(Node* node) { ...@@ -515,13 +501,10 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
// Inline {JSConstruct} requires some additional magic. // Inline {JSConstruct} requires some additional magic.
if (node->opcode() == IrOpcode::kJSConstruct) { if (node->opcode() == IrOpcode::kJSConstruct) {
STATIC_ASSERT(JSCallOrConstructNode::kHaveIdenticalLayouts);
JSConstructNode n(node); JSConstructNode n(node);
// Swizzle the inputs of the {JSConstruct} node to look like inputs to a
// normal {JSCall} node so that the rest of the inlining machinery new_target = n.new_target();
// behaves as if we were dealing with a regular function invocation.
STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput);
new_target = node->RemoveInput(n.NewTargetIndex());
node->InsertInput(graph()->zone(), JSCallNode::ReceiverIndex(), new_target);
// Insert nodes around the call that model the behavior required for a // Insert nodes around the call that model the behavior required for a
// constructor dispatch (allocate implicit receiver and check return value). // constructor dispatch (allocate implicit receiver and check return value).
...@@ -620,9 +603,9 @@ Reduction JSInliner::ReduceJSCall(Node* node) { ...@@ -620,9 +603,9 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
// to the call. // to the call.
int parameter_count = shared_info->internal_formal_parameter_count(); int parameter_count = shared_info->internal_formal_parameter_count();
DCHECK_EQ(parameter_count, start->op()->ValueOutputCount() - 5); DCHECK_EQ(parameter_count, start->op()->ValueOutputCount() - 5);
if (call.formal_arguments() != parameter_count) { if (call.argument_count() != parameter_count) {
frame_state = CreateArtificialFrameState( frame_state = CreateArtificialFrameState(
node, frame_state, call.formal_arguments(), BailoutId::None(), node, frame_state, call.argument_count(), BailoutId::None(),
FrameStateType::kArgumentsAdaptor, *shared_info); FrameStateType::kArgumentsAdaptor, *shared_info);
} }
......
...@@ -864,8 +864,10 @@ const Operator* JSOperatorBuilder::Construct(uint32_t arity, ...@@ -864,8 +864,10 @@ const Operator* JSOperatorBuilder::Construct(uint32_t arity,
const Operator* JSOperatorBuilder::ConstructWithArrayLike( const Operator* JSOperatorBuilder::ConstructWithArrayLike(
CallFrequency const& frequency, FeedbackSource const& feedback) { CallFrequency const& frequency, FeedbackSource const& feedback) {
static constexpr uint32_t arity = 3; static constexpr int kTheArrayLikeObject = 1;
ConstructParameters parameters(arity, frequency, feedback); ConstructParameters parameters(
JSConstructWithArrayLikeNode::ArityForArgc(kTheArrayLikeObject),
frequency, feedback);
return new (zone()) Operator1<ConstructParameters>( // -- return new (zone()) Operator1<ConstructParameters>( // --
IrOpcode::kJSConstructWithArrayLike, // opcode IrOpcode::kJSConstructWithArrayLike, // opcode
Operator::kNoProperties, // properties Operator::kNoProperties, // properties
......
...@@ -147,7 +147,7 @@ class ConstructParameters final { ...@@ -147,7 +147,7 @@ class ConstructParameters final {
public: public:
// A separate declaration to get around circular declaration dependencies. // A separate declaration to get around circular declaration dependencies.
// Checked to equal JSConstructNode::kExtraInputCount below. // Checked to equal JSConstructNode::kExtraInputCount below.
static constexpr int kExtraConstructInputCount = 2; static constexpr int kExtraConstructInputCount = 3;
ConstructParameters(uint32_t arity, CallFrequency const& frequency, ConstructParameters(uint32_t arity, CallFrequency const& frequency,
FeedbackSource const& feedback) FeedbackSource const& feedback)
...@@ -1222,44 +1222,56 @@ namespace js_node_wrapper_utils { ...@@ -1222,44 +1222,56 @@ namespace js_node_wrapper_utils {
TNode<Oddball> UndefinedConstant(JSGraph* jsgraph); TNode<Oddball> UndefinedConstant(JSGraph* jsgraph);
} // namespace js_node_wrapper_utils } // namespace js_node_wrapper_utils
template <int kOpcode> class JSCallOrConstructNode : public JSNodeWrapperBase {
class JSCallNodeBase final : public JSNodeWrapperBase {
public: public:
explicit constexpr JSCallNodeBase(Node* node) : JSNodeWrapperBase(node) { explicit constexpr JSCallOrConstructNode(Node* node)
CONSTEXPR_DCHECK(node->opcode() == kOpcode); : JSNodeWrapperBase(node) {
} CONSTEXPR_DCHECK(node->opcode() == IrOpcode::kJSCall ||
node->opcode() == IrOpcode::kJSCallWithArrayLike ||
const CallParameters& Parameters() const { node->opcode() == IrOpcode::kJSCallWithSpread ||
return CallParametersOf(node()->op()); node->opcode() == IrOpcode::kJSConstruct ||
node->opcode() == IrOpcode::kJSConstructWithArrayLike ||
node->opcode() == IrOpcode::kJSConstructWithSpread);
} }
#define INPUTS(V) \ #define INPUTS(V) \
V(Target, target, 0, Object) \ V(Target, target, 0, Object) \
V(Receiver, receiver, 1, Object) V(ReceiverOrNewTarget, receiver_or_new_target, 1, Object)
INPUTS(DEFINE_INPUT_ACCESSORS) INPUTS(DEFINE_INPUT_ACCESSORS)
#undef INPUTS #undef INPUTS
// Besides actual arguments, JSCall nodes (and variants) also take the // Besides actual arguments, JSCall nodes (and variants) also take the
// following. Note that we rely on the fact that all variants (JSCall, // following. Note that we rely on the fact that all variants (JSCall,
// JSCallWithArrayLike, JSCallWithSpread) have the same underlying node // JSCallWithArrayLike, JSCallWithSpread, JSConstruct,
// layout. // JSConstructWithArrayLike, JSConstructWithSpread) have the same underlying
// node layout.
static constexpr int kTargetInputCount = 1; static constexpr int kTargetInputCount = 1;
static constexpr int kReceiverInputCount = 1; static constexpr int kReceiverOrNewTargetInputCount = 1;
static constexpr int kFeedbackVectorInputCount = 1; static constexpr int kFeedbackVectorInputCount = 1;
static constexpr int kExtraInputCount = static constexpr int kExtraInputCount = kTargetInputCount +
kTargetInputCount + kReceiverInputCount + kFeedbackVectorInputCount; kReceiverOrNewTargetInputCount +
kFeedbackVectorInputCount;
STATIC_ASSERT(kExtraInputCount == CallParameters::kExtraCallInputCount); STATIC_ASSERT(kExtraInputCount == CallParameters::kExtraCallInputCount);
STATIC_ASSERT(kExtraInputCount ==
ConstructParameters::kExtraConstructInputCount);
// Just for static asserts for spots that rely on node layout. // Just for static asserts for spots that rely on node layout.
static constexpr bool kFeedbackVectorIsLastInput = true; static constexpr bool kFeedbackVectorIsLastInput = true;
// This is the arity fed into CallArguments. // Some spots rely on the fact that call and construct variants have the same
// layout.
static constexpr bool kHaveIdenticalLayouts = true;
// This is the arity fed into Call/ConstructArguments.
static constexpr int ArityForArgc(int parameters) { static constexpr int ArityForArgc(int parameters) {
return parameters + kExtraInputCount; return parameters + kExtraInputCount;
} }
static constexpr int FirstArgumentIndex() { return ReceiverIndex() + 1; } static constexpr int FirstArgumentIndex() {
return ReceiverOrNewTargetIndex() + 1;
}
static constexpr int ArgumentIndex(int i) { return FirstArgumentIndex() + i; } static constexpr int ArgumentIndex(int i) { return FirstArgumentIndex() + i; }
TNode<Object> Argument(int i) const { TNode<Object> Argument(int i) const {
DCHECK_LT(i, ArgumentCount()); DCHECK_LT(i, ArgumentCount());
return TNode<Object>::UncheckedCast( return TNode<Object>::UncheckedCast(
...@@ -1280,13 +1292,9 @@ class JSCallNodeBase final : public JSNodeWrapperBase { ...@@ -1280,13 +1292,9 @@ class JSCallNodeBase final : public JSNodeWrapperBase {
TNode<Object> ArgumentOrUndefined(int i, JSGraph* jsgraph) const { TNode<Object> ArgumentOrUndefined(int i, JSGraph* jsgraph) const {
return ArgumentOr(i, js_node_wrapper_utils::UndefinedConstant(jsgraph)); return ArgumentOr(i, js_node_wrapper_utils::UndefinedConstant(jsgraph));
} }
int ArgumentCount() const { virtual int ArgumentCount() const = 0;
// Note: The count reported by this function depends only on the parameter,
// thus adding/removing inputs will not affect it.
return Parameters().arity_without_implicit_args();
}
static int FeedbackVectorIndexForArgc(int argc) { static constexpr int FeedbackVectorIndexForArgc(int argc) {
STATIC_ASSERT(kFeedbackVectorIsLastInput); STATIC_ASSERT(kFeedbackVectorIsLastInput);
return ArgumentIndex(argc - 1) + 1; return ArgumentIndex(argc - 1) + 1;
} }
...@@ -1299,14 +1307,43 @@ class JSCallNodeBase final : public JSNodeWrapperBase { ...@@ -1299,14 +1307,43 @@ class JSCallNodeBase final : public JSNodeWrapperBase {
} }
}; };
template <int kOpcode>
class JSCallNodeBase final : public JSCallOrConstructNode {
public:
explicit constexpr JSCallNodeBase(Node* node) : JSCallOrConstructNode(node) {
CONSTEXPR_DCHECK(node->opcode() == kOpcode);
}
const CallParameters& Parameters() const {
return CallParametersOf(node()->op());
}
#define INPUTS(V) \
V(Target, target, 0, Object) \
V(Receiver, receiver, 1, Object)
INPUTS(DEFINE_INPUT_ACCESSORS)
#undef INPUTS
static constexpr int kReceiverInputCount = 1;
STATIC_ASSERT(kReceiverInputCount ==
JSCallOrConstructNode::kReceiverOrNewTargetInputCount);
int ArgumentCount() const override {
// Note: The count reported by this function depends only on the parameter,
// thus adding/removing inputs will not affect it.
return Parameters().arity_without_implicit_args();
}
};
using JSCallNode = JSCallNodeBase<IrOpcode::kJSCall>; using JSCallNode = JSCallNodeBase<IrOpcode::kJSCall>;
using JSCallWithSpreadNode = JSCallNodeBase<IrOpcode::kJSCallWithSpread>; using JSCallWithSpreadNode = JSCallNodeBase<IrOpcode::kJSCallWithSpread>;
using JSCallWithArrayLikeNode = JSCallNodeBase<IrOpcode::kJSCallWithArrayLike>; using JSCallWithArrayLikeNode = JSCallNodeBase<IrOpcode::kJSCallWithArrayLike>;
template <int kOpcode> template <int kOpcode>
class JSConstructNodeBase final : public JSNodeWrapperBase { class JSConstructNodeBase final : public JSCallOrConstructNode {
public: public:
explicit constexpr JSConstructNodeBase(Node* node) : JSNodeWrapperBase(node) { explicit constexpr JSConstructNodeBase(Node* node)
: JSCallOrConstructNode(node) {
CONSTEXPR_DCHECK(node->opcode() == kOpcode); CONSTEXPR_DCHECK(node->opcode() == kOpcode);
} }
...@@ -1314,66 +1351,21 @@ class JSConstructNodeBase final : public JSNodeWrapperBase { ...@@ -1314,66 +1351,21 @@ class JSConstructNodeBase final : public JSNodeWrapperBase {
return ConstructParametersOf(node()->op()); return ConstructParametersOf(node()->op());
} }
#define INPUTS(V) V(Target, target, 0, Object) #define INPUTS(V) \
V(Target, target, 0, Object) \
V(NewTarget, new_target, 1, Object)
INPUTS(DEFINE_INPUT_ACCESSORS) INPUTS(DEFINE_INPUT_ACCESSORS)
#undef INPUTS #undef INPUTS
// Besides actual arguments, JSConstruct nodes (and variants) also take the
// following. Note that we rely on the fact that all variants (JSConstruct,
// JSConstructWithArrayLike, JSConstructWithSpread) have the same underlying
// node layout.
static constexpr int kTargetInputCount = 1;
static constexpr int kNewTargetInputCount = 1; static constexpr int kNewTargetInputCount = 1;
static constexpr int kExtraInputCount = STATIC_ASSERT(kNewTargetInputCount ==
kTargetInputCount + kNewTargetInputCount; JSCallOrConstructNode::kReceiverOrNewTargetInputCount);
STATIC_ASSERT(kExtraInputCount ==
ConstructParameters::kExtraConstructInputCount);
// Just for static asserts for spots that rely on node layout.
static constexpr bool kNewTargetIsLastInput = true;
// This is the arity fed into ConstructArguments.
static constexpr int ArityForArgc(int parameters) {
return parameters + kExtraInputCount;
}
static constexpr int FirstArgumentIndex() { return TargetIndex() + 1; }
static constexpr int ArgumentIndex(int i) { return FirstArgumentIndex() + i; }
TNode<Object> Argument(int i) const {
DCHECK_LT(i, ArgumentCount());
return TNode<Object>::UncheckedCast(
NodeProperties::GetValueInput(node(), ArgumentIndex(i)));
}
int LastArgumentIndex() const {
DCHECK_GT(ArgumentCount(), 0);
return ArgumentIndex(ArgumentCount() - 1);
}
TNode<Object> LastArgument() const {
DCHECK_GT(ArgumentCount(), 0);
return Argument(ArgumentCount() - 1);
}
TNode<Object> ArgumentOr(int i, Node* default_value) const {
return i < ArgumentCount() ? Argument(i)
: TNode<Object>::UncheckedCast(default_value);
}
TNode<Object> ArgumentOrUndefined(int i, JSGraph* jsgraph) const {
return ArgumentOr(i, js_node_wrapper_utils::UndefinedConstant(jsgraph));
}
int ArgumentCount() const { int ArgumentCount() const {
// Note: The count reported by this function remains static even if the node // Note: The count reported by this function depends only on the parameter,
// is currently being modified. // thus adding/removing inputs will not affect it.
return Parameters().arity_without_implicit_args(); return Parameters().arity_without_implicit_args();
} }
static int NewTargetIndexForArgc(int argc) {
STATIC_ASSERT(kNewTargetIsLastInput);
return ArgumentIndex(argc - 1) + 1;
}
int NewTargetIndex() const { return NewTargetIndexForArgc(ArgumentCount()); }
TNode<Object> new_target() const {
return TNode<Object>::UncheckedCast(
NodeProperties::GetValueInput(node(), NewTargetIndex()));
}
}; };
using JSConstructNode = JSConstructNodeBase<IrOpcode::kJSConstruct>; using JSConstructNode = JSConstructNodeBase<IrOpcode::kJSConstruct>;
......
...@@ -1526,20 +1526,23 @@ void ReduceBuiltin(JSGraph* jsgraph, Node* node, int builtin_index, int arity, ...@@ -1526,20 +1526,23 @@ void ReduceBuiltin(JSGraph* jsgraph, Node* node, int builtin_index, int arity,
// The logic contained here is mirrored in Builtins::Generate_Adaptor. // The logic contained here is mirrored in Builtins::Generate_Adaptor.
// Keep these in sync. // Keep these in sync.
STATIC_ASSERT(JSCallNode::TargetIndex() == JSConstructNode::TargetIndex()); Node* target = node->InputAt(JSCallOrConstructNode::TargetIndex());
Node* target = node->InputAt(JSCallNode::TargetIndex());
// Unify representations between construct and call nodes. For construct
// nodes, the receiver is undefined. For call nodes, the new_target is
// undefined.
Node* new_target; Node* new_target;
Zone* zone = jsgraph->zone(); Zone* zone = jsgraph->zone();
if (node->opcode() == IrOpcode::kJSConstruct) { if (node->opcode() == IrOpcode::kJSConstruct) {
// Unify representations between construct and call nodes. STATIC_ASSERT(JSCallNode::ReceiverIndex() ==
// Remove new target and add receiver. JSConstructNode::NewTargetIndex());
STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput); new_target = JSConstructNode{node}.new_target();
new_target = node->RemoveInput(JSConstructNode{node}.NewTargetIndex()); node->ReplaceInput(JSConstructNode::NewTargetIndex(),
node->InsertInput(zone, JSCallNode::ReceiverIndex(), jsgraph->UndefinedConstant());
jsgraph->UndefinedConstant()); node->RemoveInput(JSConstructNode{node}.FeedbackVectorIndex());
} else { } else {
new_target = jsgraph->UndefinedConstant(); new_target = jsgraph->UndefinedConstant();
node->RemoveInput(JSCallNode{node}.FeedbackVectorIndex());
} }
// CPP builtins are implemented in C++, and we can inline it. // CPP builtins are implemented in C++, and we can inline it.
...@@ -1603,7 +1606,6 @@ Reduction JSTypedLowering::ReduceJSConstructForwardVarargs(Node* node) { ...@@ -1603,7 +1606,6 @@ Reduction JSTypedLowering::ReduceJSConstructForwardVarargs(Node* node) {
int const start_index = static_cast<int>(p.start_index()); int const start_index = static_cast<int>(p.start_index());
Node* target = NodeProperties::GetValueInput(node, 0); Node* target = NodeProperties::GetValueInput(node, 0);
Type target_type = NodeProperties::GetType(target); Type target_type = NodeProperties::GetType(target);
Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
// Check if {target} is a JSFunction. // Check if {target} is a JSFunction.
if (target_type.IsHeapConstant() && if (target_type.IsHeapConstant() &&
...@@ -1613,10 +1615,8 @@ Reduction JSTypedLowering::ReduceJSConstructForwardVarargs(Node* node) { ...@@ -1613,10 +1615,8 @@ Reduction JSTypedLowering::ReduceJSConstructForwardVarargs(Node* node) {
if (!function.map().is_constructor()) return NoChange(); if (!function.map().is_constructor()) return NoChange();
// Patch {node} to an indirect call via ConstructFunctionForwardVarargs. // Patch {node} to an indirect call via ConstructFunctionForwardVarargs.
Callable callable = CodeFactory::ConstructFunctionForwardVarargs(isolate()); Callable callable = CodeFactory::ConstructFunctionForwardVarargs(isolate());
node->RemoveInput(arity + 1);
node->InsertInput(graph()->zone(), 0, node->InsertInput(graph()->zone(), 0,
jsgraph()->HeapConstant(callable.code())); jsgraph()->HeapConstant(callable.code()));
node->InsertInput(graph()->zone(), 2, new_target);
node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity)); node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
node->InsertInput(graph()->zone(), 4, jsgraph()->Constant(start_index)); node->InsertInput(graph()->zone(), 4, jsgraph()->Constant(start_index));
node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant()); node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant());
...@@ -1636,7 +1636,6 @@ Reduction JSTypedLowering::ReduceJSConstruct(Node* node) { ...@@ -1636,7 +1636,6 @@ Reduction JSTypedLowering::ReduceJSConstruct(Node* node) {
int const arity = p.arity_without_implicit_args(); int const arity = p.arity_without_implicit_args();
Node* target = n.target(); Node* target = n.target();
Type target_type = NodeProperties::GetType(target); Type target_type = NodeProperties::GetType(target);
Node* new_target = n.new_target();
// Check if {target} is a known JSFunction. // Check if {target} is a known JSFunction.
if (target_type.IsHeapConstant() && if (target_type.IsHeapConstant() &&
...@@ -1657,10 +1656,10 @@ Reduction JSTypedLowering::ReduceJSConstruct(Node* node) { ...@@ -1657,10 +1656,10 @@ Reduction JSTypedLowering::ReduceJSConstruct(Node* node) {
use_builtin_construct_stub use_builtin_construct_stub
? BUILTIN_CODE(isolate(), JSBuiltinsConstructStub) ? BUILTIN_CODE(isolate(), JSBuiltinsConstructStub)
: BUILTIN_CODE(isolate(), JSConstructStubGeneric)); : BUILTIN_CODE(isolate(), JSConstructStubGeneric));
STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput); STATIC_ASSERT(JSConstructNode::TargetIndex() == 0);
node->RemoveInput(n.NewTargetIndex()); STATIC_ASSERT(JSConstructNode::NewTargetIndex() == 1);
node->RemoveInput(n.FeedbackVectorIndex());
node->InsertInput(graph()->zone(), 0, jsgraph()->Constant(code)); node->InsertInput(graph()->zone(), 0, jsgraph()->Constant(code));
node->InsertInput(graph()->zone(), 2, new_target);
node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity)); node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant()); node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant()); node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant());
...@@ -1780,10 +1779,9 @@ Reduction JSTypedLowering::ReduceJSCall(Node* node) { ...@@ -1780,10 +1779,9 @@ Reduction JSTypedLowering::ReduceJSCall(Node* node) {
CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState; CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
Node* new_target = jsgraph()->UndefinedConstant(); Node* new_target = jsgraph()->UndefinedConstant();
// The node will change operators, remove the feedback vector.
node->RemoveInput(n.FeedbackVectorIndex());
if (NeedsArgumentAdaptorFrame(*shared, arity)) { if (NeedsArgumentAdaptorFrame(*shared, arity)) {
node->RemoveInput(n.FeedbackVectorIndex());
// Check if it's safe to skip the arguments adaptor for {shared}, // Check if it's safe to skip the arguments adaptor for {shared},
// that is whether the target function anyways cannot observe the // that is whether the target function anyways cannot observe the
// actual arguments. Details can be found in this document at // actual arguments. Details can be found in this document at
...@@ -1843,12 +1841,14 @@ Reduction JSTypedLowering::ReduceJSCall(Node* node) { ...@@ -1843,12 +1841,14 @@ Reduction JSTypedLowering::ReduceJSCall(Node* node) {
auto call_descriptor = Linkage::GetStubCallDescriptor( auto call_descriptor = Linkage::GetStubCallDescriptor(
graph()->zone(), descriptor, 1 + arity, flags); graph()->zone(), descriptor, 1 + arity, flags);
Node* stub_code = jsgraph()->HeapConstant(callable.code()); Node* stub_code = jsgraph()->HeapConstant(callable.code());
node->RemoveInput(n.FeedbackVectorIndex());
node->InsertInput(graph()->zone(), 0, stub_code); // Code object. node->InsertInput(graph()->zone(), 0, stub_code); // Code object.
node->InsertInput(graph()->zone(), 2, new_target); node->InsertInput(graph()->zone(), 2, new_target);
node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity)); node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
NodeProperties::ChangeOp(node, common()->Call(call_descriptor)); NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
} else { } else {
// Patch {node} to a direct call. // Patch {node} to a direct call.
node->RemoveInput(n.FeedbackVectorIndex());
node->InsertInput(graph()->zone(), arity + 2, new_target); node->InsertInput(graph()->zone(), arity + 2, new_target);
node->InsertInput(graph()->zone(), arity + 3, jsgraph()->Constant(arity)); node->InsertInput(graph()->zone(), arity + 3, jsgraph()->Constant(arity));
NodeProperties::ChangeOp(node, NodeProperties::ChangeOp(node,
......
...@@ -134,10 +134,11 @@ TEST_F(JSCallReducerTest, PromiseConstructorNoArgs) { ...@@ -134,10 +134,11 @@ TEST_F(JSCallReducerTest, PromiseConstructorNoArgs) {
Node* control = graph()->start(); Node* control = graph()->start();
Node* context = UndefinedConstant(); Node* context = UndefinedConstant();
Node* frame_state = graph()->start(); Node* frame_state = graph()->start();
Node* feedback = UndefinedConstant();
Node* construct = Node* construct = graph()->NewNode(
graph()->NewNode(javascript()->Construct(2), promise, promise, context, javascript()->Construct(JSConstructNode::ArityForArgc(0)), promise,
frame_state, effect, control); promise, feedback, context, frame_state, effect, control);
Reduction r = Reduce(construct); Reduction r = Reduce(construct);
...@@ -153,11 +154,12 @@ TEST_F(JSCallReducerTest, PromiseConstructorSubclass) { ...@@ -153,11 +154,12 @@ TEST_F(JSCallReducerTest, PromiseConstructorSubclass) {
Node* control = graph()->start(); Node* control = graph()->start();
Node* context = UndefinedConstant(); Node* context = UndefinedConstant();
Node* frame_state = graph()->start(); Node* frame_state = graph()->start();
Node* feedback = UndefinedConstant();
Node* executor = UndefinedConstant(); Node* executor = UndefinedConstant();
Node* construct = Node* construct = graph()->NewNode(
graph()->NewNode(javascript()->Construct(3), promise, executor, javascript()->Construct(JSConstructNode::ArityForArgc(1)), promise,
new_target, context, frame_state, effect, control); new_target, executor, feedback, context, frame_state, effect, control);
Reduction r = Reduce(construct); Reduction r = Reduce(construct);
...@@ -171,11 +173,12 @@ TEST_F(JSCallReducerTest, PromiseConstructorBasic) { ...@@ -171,11 +173,12 @@ TEST_F(JSCallReducerTest, PromiseConstructorBasic) {
Node* control = graph()->start(); Node* control = graph()->start();
Node* context = UndefinedConstant(); Node* context = UndefinedConstant();
Node* frame_state = graph()->start(); Node* frame_state = graph()->start();
Node* feedback = UndefinedConstant();
Node* executor = UndefinedConstant(); Node* executor = UndefinedConstant();
Node* construct = Node* construct = graph()->NewNode(
graph()->NewNode(javascript()->Construct(3), promise, executor, promise, javascript()->Construct(JSConstructNode::ArityForArgc(1)), promise,
context, frame_state, effect, control); promise, executor, feedback, context, frame_state, effect, control);
Reduction r = Reduce(construct); Reduction r = Reduce(construct);
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
...@@ -190,11 +193,12 @@ TEST_F(JSCallReducerTest, PromiseConstructorWithHook) { ...@@ -190,11 +193,12 @@ TEST_F(JSCallReducerTest, PromiseConstructorWithHook) {
Node* control = graph()->start(); Node* control = graph()->start();
Node* context = UndefinedConstant(); Node* context = UndefinedConstant();
Node* frame_state = graph()->start(); Node* frame_state = graph()->start();
Node* feedback = UndefinedConstant();
Node* executor = UndefinedConstant(); Node* executor = UndefinedConstant();
Node* construct = Node* construct = graph()->NewNode(
graph()->NewNode(javascript()->Construct(3), promise, executor, promise, javascript()->Construct(JSConstructNode::ArityForArgc(1)), promise,
context, frame_state, effect, control); promise, executor, feedback, context, frame_state, effect, control);
Protectors::InvalidatePromiseHook(isolate()); Protectors::InvalidatePromiseHook(isolate());
......
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