Commit b8fbf8eb authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[nci] Add node wrappers for construct variants

... in preparation for upcoming changes to 1. make construct node
layout more consistent with call nodes by placing new_target
(construct) in the same spot as receiver (call); and 2. adding the
feedback vector input.

Bug: v8:8888
Change-Id: I6cd7f50ed0b029de53af5cd82e7ecf4ba514ef65
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2275963
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68689}
parent 8c0b68e3
...@@ -2582,15 +2582,26 @@ void BytecodeGraphBuilder::VisitCallRuntimeForPair() { ...@@ -2582,15 +2582,26 @@ void BytecodeGraphBuilder::VisitCallRuntimeForPair() {
Node* const* BytecodeGraphBuilder::GetConstructArgumentsFromRegister( Node* const* BytecodeGraphBuilder::GetConstructArgumentsFromRegister(
Node* target, Node* new_target, interpreter::Register first_arg, Node* target, Node* new_target, interpreter::Register first_arg,
int arg_count) { int arg_count) {
int arity = kTargetAndNewTarget + arg_count; const int arity = JSConstructNode::ArityForArgc(arg_count);
Node** all = local_zone()->NewArray<Node*>(static_cast<size_t>(arity)); Node** all = local_zone()->NewArray<Node*>(static_cast<size_t>(arity));
all[0] = target; int cursor = 0;
int first_arg_index = first_arg.index();
STATIC_ASSERT(JSConstructNode::TargetIndex() == 0);
STATIC_ASSERT(JSConstructNode::FirstArgumentIndex() == 1);
STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput);
all[cursor++] = target;
// The function arguments are in consecutive registers.
int arg_base = first_arg.index();
for (int i = 0; i < arg_count; ++i) { for (int i = 0; i < arg_count; ++i) {
all[1 + i] = environment()->LookupRegister( all[cursor++] =
interpreter::Register(first_arg_index + i)); environment()->LookupRegister(interpreter::Register(arg_base + i));
} }
all[arity - 1] = new_target;
all[cursor++] = new_target;
DCHECK_EQ(cursor, arity);
return all; return all;
} }
...@@ -2607,9 +2618,8 @@ void BytecodeGraphBuilder::VisitConstruct() { ...@@ -2607,9 +2618,8 @@ void BytecodeGraphBuilder::VisitConstruct() {
CallFrequency frequency = ComputeCallFrequency(slot_id); CallFrequency frequency = ComputeCallFrequency(slot_id);
const uint32_t arg_count = static_cast<uint32_t>(reg_count); const uint32_t arg_count = static_cast<uint32_t>(reg_count);
const uint32_t arg_count_with_extra_args = kTargetAndNewTarget + arg_count; const uint32_t arity = JSConstructNode::ArityForArgc(arg_count);
const Operator* op = const Operator* op = javascript()->Construct(arity, frequency, feedback);
javascript()->Construct(arg_count_with_extra_args, frequency, feedback);
Node* const* args = GetConstructArgumentsFromRegister(callee, new_target, Node* const* args = GetConstructArgumentsFromRegister(callee, new_target,
first_reg, arg_count); first_reg, arg_count);
JSTypeHintLowering::LoweringResult lowering = TryBuildSimplifiedConstruct( JSTypeHintLowering::LoweringResult lowering = TryBuildSimplifiedConstruct(
...@@ -2621,7 +2631,7 @@ void BytecodeGraphBuilder::VisitConstruct() { ...@@ -2621,7 +2631,7 @@ void BytecodeGraphBuilder::VisitConstruct() {
node = lowering.value(); node = lowering.value();
} else { } else {
DCHECK(!lowering.Changed()); DCHECK(!lowering.Changed());
node = MakeNode(op, arg_count_with_extra_args, args); node = MakeNode(op, arity, args);
} }
environment()->BindAccumulator(node, Environment::kAttachFrameState); environment()->BindAccumulator(node, Environment::kAttachFrameState);
} }
...@@ -2639,9 +2649,9 @@ void BytecodeGraphBuilder::VisitConstructWithSpread() { ...@@ -2639,9 +2649,9 @@ void BytecodeGraphBuilder::VisitConstructWithSpread() {
CallFrequency frequency = ComputeCallFrequency(slot_id); CallFrequency frequency = ComputeCallFrequency(slot_id);
const uint32_t arg_count = static_cast<uint32_t>(reg_count); const uint32_t arg_count = static_cast<uint32_t>(reg_count);
const uint32_t arg_count_with_extra_args = kTargetAndNewTarget + arg_count; const uint32_t arity = JSConstructNode::ArityForArgc(arg_count);
const Operator* op = javascript()->ConstructWithSpread( const Operator* op =
arg_count_with_extra_args, frequency, feedback); javascript()->ConstructWithSpread(arity, frequency, feedback);
Node* const* args = GetConstructArgumentsFromRegister(callee, new_target, Node* const* args = GetConstructArgumentsFromRegister(callee, new_target,
first_reg, arg_count); first_reg, arg_count);
JSTypeHintLowering::LoweringResult lowering = TryBuildSimplifiedConstruct( JSTypeHintLowering::LoweringResult lowering = TryBuildSimplifiedConstruct(
...@@ -2653,7 +2663,7 @@ void BytecodeGraphBuilder::VisitConstructWithSpread() { ...@@ -2653,7 +2663,7 @@ void BytecodeGraphBuilder::VisitConstructWithSpread() {
node = lowering.value(); node = lowering.value();
} else { } else {
DCHECK(!lowering.Changed()); DCHECK(!lowering.Changed());
node = MakeNode(op, arg_count_with_extra_args, args); node = MakeNode(op, arity, args);
} }
environment()->BindAccumulator(node, Environment::kAttachFrameState); environment()->BindAccumulator(node, Environment::kAttachFrameState);
} }
......
...@@ -106,7 +106,7 @@ uint8_t DeoptimizerParameterCountFor(ContinuationFrameStateMode mode) { ...@@ -106,7 +106,7 @@ uint8_t DeoptimizerParameterCountFor(ContinuationFrameStateMode mode) {
UNREACHABLE(); UNREACHABLE();
} }
Node* CreateBuiltinContinuationFrameStateCommon( FrameState CreateBuiltinContinuationFrameStateCommon(
JSGraph* jsgraph, FrameStateType frame_type, Builtins::Name name, JSGraph* jsgraph, FrameStateType frame_type, Builtins::Name name,
Node* closure, Node* context, Node** parameters, int parameter_count, Node* closure, Node* context, Node** parameters, int parameter_count,
Node* outer_frame_state, Node* outer_frame_state,
...@@ -124,14 +124,14 @@ Node* CreateBuiltinContinuationFrameStateCommon( ...@@ -124,14 +124,14 @@ Node* CreateBuiltinContinuationFrameStateCommon(
shared); shared);
const Operator* op = common->FrameState( const Operator* op = common->FrameState(
bailout_id, OutputFrameStateCombine::Ignore(), state_info); bailout_id, OutputFrameStateCombine::Ignore(), state_info);
return graph->NewNode(op, params_node, jsgraph->EmptyStateValues(), return FrameState(graph->NewNode(op, params_node, jsgraph->EmptyStateValues(),
jsgraph->EmptyStateValues(), context, closure, jsgraph->EmptyStateValues(), context,
outer_frame_state); closure, outer_frame_state));
} }
} // namespace } // namespace
Node* CreateStubBuiltinContinuationFrameState( FrameState CreateStubBuiltinContinuationFrameState(
JSGraph* jsgraph, Builtins::Name name, Node* context, JSGraph* jsgraph, Builtins::Name name, Node* context,
Node* const* parameters, int parameter_count, Node* outer_frame_state, Node* const* parameters, int parameter_count, Node* outer_frame_state,
ContinuationFrameStateMode mode) { ContinuationFrameStateMode mode) {
...@@ -169,7 +169,7 @@ Node* CreateStubBuiltinContinuationFrameState( ...@@ -169,7 +169,7 @@ Node* CreateStubBuiltinContinuationFrameState(
static_cast<int>(actual_parameters.size()), outer_frame_state); static_cast<int>(actual_parameters.size()), outer_frame_state);
} }
Node* CreateJavaScriptBuiltinContinuationFrameState( FrameState CreateJavaScriptBuiltinContinuationFrameState(
JSGraph* jsgraph, const SharedFunctionInfoRef& shared, Builtins::Name name, JSGraph* jsgraph, const SharedFunctionInfoRef& shared, Builtins::Name name,
Node* target, Node* context, Node* const* stack_parameters, Node* target, Node* context, Node* const* stack_parameters,
int stack_parameter_count, Node* outer_frame_state, int stack_parameter_count, Node* outer_frame_state,
...@@ -207,7 +207,7 @@ Node* CreateJavaScriptBuiltinContinuationFrameState( ...@@ -207,7 +207,7 @@ Node* CreateJavaScriptBuiltinContinuationFrameState(
shared.object()); shared.object());
} }
Node* CreateGenericLazyDeoptContinuationFrameState( FrameState CreateGenericLazyDeoptContinuationFrameState(
JSGraph* graph, const SharedFunctionInfoRef& shared, Node* target, JSGraph* graph, const SharedFunctionInfoRef& shared, Node* target,
Node* context, Node* receiver, Node* outer_frame_state) { Node* context, Node* receiver, Node* outer_frame_state) {
Node* stack_parameters[]{receiver}; Node* stack_parameters[]{receiver};
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define V8_COMPILER_FRAME_STATES_H_ #define V8_COMPILER_FRAME_STATES_H_
#include "src/builtins/builtins.h" #include "src/builtins/builtins.h"
#include "src/compiler/node.h"
#include "src/handles/handles.h" #include "src/handles/handles.h"
#include "src/objects/shared-function-info.h" #include "src/objects/shared-function-info.h"
#include "src/utils/utils.h" #include "src/utils/utils.h"
...@@ -150,18 +151,18 @@ static constexpr int kFrameStateInputCount = kFrameStateOuterStateInput + 1; ...@@ -150,18 +151,18 @@ static constexpr int kFrameStateInputCount = kFrameStateOuterStateInput + 1;
enum class ContinuationFrameStateMode { EAGER, LAZY, LAZY_WITH_CATCH }; enum class ContinuationFrameStateMode { EAGER, LAZY, LAZY_WITH_CATCH };
Node* CreateStubBuiltinContinuationFrameState( FrameState CreateStubBuiltinContinuationFrameState(
JSGraph* graph, Builtins::Name name, Node* context, Node* const* parameters, JSGraph* graph, Builtins::Name name, Node* context, Node* const* parameters,
int parameter_count, Node* outer_frame_state, int parameter_count, Node* outer_frame_state,
ContinuationFrameStateMode mode); ContinuationFrameStateMode mode);
Node* CreateJavaScriptBuiltinContinuationFrameState( FrameState CreateJavaScriptBuiltinContinuationFrameState(
JSGraph* graph, const SharedFunctionInfoRef& shared, Builtins::Name name, JSGraph* graph, const SharedFunctionInfoRef& shared, Builtins::Name name,
Node* target, Node* context, Node* const* stack_parameters, Node* target, Node* context, Node* const* stack_parameters,
int stack_parameter_count, Node* outer_frame_state, int stack_parameter_count, Node* outer_frame_state,
ContinuationFrameStateMode mode); ContinuationFrameStateMode mode);
Node* CreateGenericLazyDeoptContinuationFrameState( FrameState CreateGenericLazyDeoptContinuationFrameState(
JSGraph* graph, const SharedFunctionInfoRef& shared, Node* target, JSGraph* graph, const SharedFunctionInfoRef& shared, Node* target,
Node* context, Node* receiver, Node* outer_frame_state); Node* context, Node* receiver, Node* outer_frame_state);
......
This diff is collapsed.
...@@ -760,13 +760,11 @@ void JSGenericLowering::LowerJSConstructForwardVarargs(Node* node) { ...@@ -760,13 +760,11 @@ void JSGenericLowering::LowerJSConstructForwardVarargs(Node* node) {
} }
void JSGenericLowering::LowerJSConstruct(Node* node) { void JSGenericLowering::LowerJSConstruct(Node* node) {
ConstructParameters const& p = ConstructParametersOf(node->op()); JSConstructNode n(node);
ConstructParameters const& p = n.Parameters();
int const arg_count = p.arity_without_implicit_args(); int const arg_count = p.arity_without_implicit_args();
CallDescriptor::Flags flags = FrameStateFlagForCall(node); CallDescriptor::Flags flags = FrameStateFlagForCall(node);
// TODO(jgruber): Understand and document how stack_argument_count is
// calculated. I've made some educated guesses below but they should be
// verified and documented in other lowerings as well.
static constexpr int kReceiver = 1; static constexpr int kReceiver = 1;
static constexpr int kMaybeFeedbackVector = 1; static constexpr int kMaybeFeedbackVector = 1;
...@@ -778,13 +776,14 @@ void JSGenericLowering::LowerJSConstruct(Node* node) { ...@@ -778,13 +776,14 @@ 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* feedback_vector = jsgraph()->HeapConstant(p.feedback().vector);
Node* stub_code = jsgraph()->HeapConstant(callable.code()); Node* stub_code = jsgraph()->HeapConstant(callable.code());
Node* new_target = node->InputAt(arg_count + 1); 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(arg_count + 1); // Drop new target. 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
...@@ -796,6 +795,10 @@ void JSGenericLowering::LowerJSConstruct(Node* node) { ...@@ -796,6 +795,10 @@ void JSGenericLowering::LowerJSConstruct(Node* node) {
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);
// After: {code, target, new_target, arity, slot, receiver, ...args,
// vector}.
NodeProperties::ChangeOp(node, common()->Call(call_descriptor)); NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
} else { } else {
const int stack_argument_count = arg_count + kReceiver; const int stack_argument_count = arg_count + kReceiver;
...@@ -804,19 +807,23 @@ void JSGenericLowering::LowerJSConstruct(Node* node) { ...@@ -804,19 +807,23 @@ 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 = node->InputAt(arg_count + 1); Node* new_target = n.new_target();
Node* receiver = jsgraph()->UndefinedConstant(); Node* receiver = jsgraph()->UndefinedConstant();
node->RemoveInput(arg_count + 1); // Drop new target. node->RemoveInput(n.NewTargetIndex());
node->InsertInput(zone(), 0, stub_code); node->InsertInput(zone(), 0, stub_code);
node->InsertInput(zone(), 2, new_target); 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);
// After: {code, target, new_target, arity, receiver, ...args}.
NodeProperties::ChangeOp(node, common()->Call(call_descriptor)); NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
} }
} }
void JSGenericLowering::LowerJSConstructWithArrayLike(Node* node) { void JSGenericLowering::LowerJSConstructWithArrayLike(Node* node) {
ConstructParameters const& p = ConstructParametersOf(node->op()); JSConstructWithArrayLikeNode n(node);
ConstructParameters const& p = n.Parameters();
CallDescriptor::Flags flags = FrameStateFlagForCall(node); CallDescriptor::Flags flags = FrameStateFlagForCall(node);
const int arg_count = p.arity_without_implicit_args(); const int arg_count = p.arity_without_implicit_args();
DCHECK_EQ(arg_count, 1); DCHECK_EQ(arg_count, 1);
...@@ -835,8 +842,9 @@ void JSGenericLowering::LowerJSConstructWithArrayLike(Node* node) { ...@@ -835,8 +842,9 @@ 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 = node->InputAt(1); Node* arguments_list = n.Argument(0);
Node* new_target = node->InputAt(2); Node* new_target = n.new_target();
STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput);
Node* feedback_vector = jsgraph()->HeapConstant(p.feedback().vector); Node* feedback_vector = jsgraph()->HeapConstant(p.feedback().vector);
Node* slot = jsgraph()->Int32Constant(p.feedback().index()); Node* slot = jsgraph()->Int32Constant(p.feedback().index());
...@@ -852,6 +860,9 @@ void JSGenericLowering::LowerJSConstructWithArrayLike(Node* node) { ...@@ -852,6 +860,9 @@ void JSGenericLowering::LowerJSConstructWithArrayLike(Node* node) {
node->InsertInput(zone(), 5, receiver); node->InsertInput(zone(), 5, receiver);
node->InsertInput(zone(), 6, feedback_vector); node->InsertInput(zone(), 6, feedback_vector);
// After: {code, target, new_target, arguments_list, slot, receiver,
// vector}.
NodeProperties::ChangeOp(node, common()->Call(call_descriptor)); NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
} else { } else {
const int stack_argument_count = arg_count - kArgumentList + kReceiver; const int stack_argument_count = arg_count - kArgumentList + kReceiver;
...@@ -861,21 +872,24 @@ void JSGenericLowering::LowerJSConstructWithArrayLike(Node* node) { ...@@ -861,21 +872,24 @@ 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 = node->InputAt(1); Node* arguments_list = n.Argument(0);
Node* new_target = node->InputAt(2); 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(2, new_target);
node->ReplaceInput(3, arguments_list); node->ReplaceInput(3, arguments_list);
node->InsertInput(zone(), 4, receiver); node->InsertInput(zone(), 4, receiver);
// After: {code, target, new_target, arguments_list, receiver}.
NodeProperties::ChangeOp(node, common()->Call(call_descriptor)); NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
} }
} }
void JSGenericLowering::LowerJSConstructWithSpread(Node* node) { void JSGenericLowering::LowerJSConstructWithSpread(Node* node) {
ConstructParameters const& p = ConstructParametersOf(node->op()); JSConstructWithSpreadNode n(node);
ConstructParameters const& p = n.Parameters();
int const arg_count = p.arity_without_implicit_args(); int const arg_count = p.arity_without_implicit_args();
int const spread_index = arg_count; DCHECK_GE(arg_count, 1);
int const new_target_index = arg_count + 1;
CallDescriptor::Flags flags = FrameStateFlagForCall(node); CallDescriptor::Flags flags = FrameStateFlagForCall(node);
static constexpr int kReceiver = 1; static constexpr int kReceiver = 1;
...@@ -891,15 +905,15 @@ void JSGenericLowering::LowerJSConstructWithSpread(Node* node) { ...@@ -891,15 +905,15 @@ 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* 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->InputAt(new_target_index); Node* new_target = node->RemoveInput(n.NewTargetIndex());
Node* receiver = jsgraph()->UndefinedConstant(); Node* receiver = jsgraph()->UndefinedConstant();
node->RemoveInput(new_target_index);
// 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
...@@ -912,6 +926,10 @@ void JSGenericLowering::LowerJSConstructWithSpread(Node* node) { ...@@ -912,6 +926,10 @@ void JSGenericLowering::LowerJSConstructWithSpread(Node* node) {
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);
// After: {code, target, new_target, arity, slot, receiver, ...args, spread,
// vector}.
NodeProperties::ChangeOp(node, common()->Call(call_descriptor)); NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
} else { } else {
const int stack_argument_count = arg_count + kReceiver - kTheSpread; const int stack_argument_count = arg_count + kReceiver - kTheSpread;
...@@ -922,18 +940,20 @@ void JSGenericLowering::LowerJSConstructWithSpread(Node* node) { ...@@ -922,18 +940,20 @@ 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* new_target = node->InputAt(new_target_index);
Node* spread = node->InputAt(spread_index);
Node* receiver = jsgraph()->UndefinedConstant(); Node* receiver = jsgraph()->UndefinedConstant();
DCHECK(new_target_index > spread_index); STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput);
node->RemoveInput(new_target_index); DCHECK(n.NewTargetIndex() > n.LastArgumentIndex());
node->RemoveInput(spread_index); Node* new_target = node->RemoveInput(n.NewTargetIndex());
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(), 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);
// After: {code, target, new_target, arity, spread, receiver, ...args}.
NodeProperties::ChangeOp(node, common()->Call(call_descriptor)); NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
} }
} }
...@@ -998,12 +1018,12 @@ void JSGenericLowering::LowerJSCallWithArrayLike(Node* node) { ...@@ -998,12 +1018,12 @@ void JSGenericLowering::LowerJSCallWithArrayLike(Node* node) {
DCHECK_EQ(arg_count, 1); // The arraylike object. DCHECK_EQ(arg_count, 1); // The arraylike object.
CallDescriptor::Flags flags = FrameStateFlagForCall(node); CallDescriptor::Flags flags = FrameStateFlagForCall(node);
static constexpr int kArrayLikeObject = 1; static constexpr int kArgumentsList = 1;
static constexpr int kReceiver = 1; static constexpr int kReceiver = 1;
if (CollectFeedbackInGenericLowering() && if (CollectFeedbackInGenericLowering() &&
CollectCallAndConstructFeedback(broker()) && p.feedback().IsValid()) { CollectCallAndConstructFeedback(broker()) && p.feedback().IsValid()) {
const int stack_argument_count = arg_count - kArrayLikeObject + kReceiver; const int stack_argument_count = arg_count - kArgumentsList + kReceiver;
Callable callable = Builtins::CallableFor( Callable callable = Builtins::CallableFor(
isolate(), Builtins::kCallWithArrayLike_WithFeedback); isolate(), Builtins::kCallWithArrayLike_WithFeedback);
auto call_descriptor = Linkage::GetStubCallDescriptor( auto call_descriptor = Linkage::GetStubCallDescriptor(
...@@ -1030,7 +1050,7 @@ void JSGenericLowering::LowerJSCallWithArrayLike(Node* node) { ...@@ -1030,7 +1050,7 @@ void JSGenericLowering::LowerJSCallWithArrayLike(Node* node) {
NodeProperties::ChangeOp(node, common()->Call(call_descriptor)); NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
} else { } else {
const int stack_argument_count = arg_count - kArrayLikeObject + kReceiver; const int stack_argument_count = arg_count - kArgumentsList + kReceiver;
Callable callable = CodeFactory::CallWithArrayLike(isolate()); Callable callable = CodeFactory::CallWithArrayLike(isolate());
auto call_descriptor = Linkage::GetStubCallDescriptor( auto call_descriptor = Linkage::GetStubCallDescriptor(
zone(), callable.descriptor(), stack_argument_count, flags); zone(), callable.descriptor(), stack_argument_count, flags);
......
...@@ -654,7 +654,13 @@ void JSInliningHeuristic::CreateOrReuseDispatch(Node* node, Node* callee, ...@@ -654,7 +654,13 @@ void JSInliningHeuristic::CreateOrReuseDispatch(Node* node, Node* callee,
// We also specialize the new.target of JSConstruct {node}s if it refers // We also specialize the new.target of JSConstruct {node}s if it refers
// 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) {
UNREACHABLE(); // https://crbug.com/v8/10675.
}
if (node->opcode() == IrOpcode::kJSConstruct && inputs[0] == inputs[1]) { if (node->opcode() == IrOpcode::kJSConstruct && inputs[0] == inputs[1]) {
// TODO(jgruber): Is this correct? JSConstruct nodes have the new_target
// at the last index, not at index 1.
STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput);
inputs[1] = target; inputs[1] = target;
} }
inputs[0] = target; inputs[0] = target;
......
...@@ -51,44 +51,30 @@ class JSCallAccessor { ...@@ -51,44 +51,30 @@ class JSCallAccessor {
} }
Node* target() const { Node* target() const {
// Both, {JSCall} and {JSConstruct}, have same layout here. STATIC_ASSERT(JSCallNode::TargetIndex() == JSConstructNode::TargetIndex());
return call_->InputAt(0); return call_->InputAt(JSCallNode::TargetIndex());
} }
Node* receiver() const { Node* receiver() const {
DCHECK_EQ(IrOpcode::kJSCall, call_->opcode());
return JSCallNode{call_}.receiver(); return JSCallNode{call_}.receiver();
} }
Node* new_target() const { Node* new_target() const { return JSConstructNode{call_}.new_target(); }
DCHECK_EQ(IrOpcode::kJSConstruct, call_->opcode());
return call_->InputAt(formal_arguments() + 1);
}
Node* argument(int i) const {
// Both, {JSCall} and {JSConstruct}, have same layout here.
static constexpr int kFirstArgumentIndex = 2;
STATIC_ASSERT(kFirstArgumentIndex == JSCallNode::FirstArgumentIndex());
return call_->InputAt(kFirstArgumentIndex + i);
}
Node* frame_state() const { Node* frame_state() const {
// Both, {JSCall} and {JSConstruct}, have frame state.
return NodeProperties::GetFrameStateInput(call_); return NodeProperties::GetFrameStateInput(call_);
} }
int formal_arguments() const { int formal_arguments() const {
// TODO(jgruber): Remove once the JSConstructNode wrapper is
// implemented.
return (call_->opcode() == IrOpcode::kJSCall) return (call_->opcode() == IrOpcode::kJSCall)
? JSCallNode{call_}.ArgumentCount() ? JSCallNode{call_}.ArgumentCount()
: call_->op()->ValueInputCount() - kTargetAndNewTarget; : JSConstructNode{call_}.ArgumentCount();
} }
CallFrequency const& frequency() const { CallFrequency const& frequency() const {
return (call_->opcode() == IrOpcode::kJSCall) return (call_->opcode() == IrOpcode::kJSCall)
? JSCallNode{call_}.Parameters().frequency() ? JSCallNode{call_}.Parameters().frequency()
: ConstructParametersOf(call_->op()).frequency(); : JSConstructNode{call_}.Parameters().frequency();
} }
private: private:
...@@ -115,7 +101,8 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context, ...@@ -115,7 +101,8 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context,
// {inliner_inputs} counts JSFunction, receiver, arguments, but not // {inliner_inputs} counts JSFunction, receiver, arguments, but not
// new target value, argument count, context, effect or control. // new target value, argument count, context, effect or control.
// TODO(jgruber): Refactor this once JSConstructNode is implemented. // TODO(jgruber): Refactor this once JSConstructNode is implemented.
STATIC_ASSERT(kTargetAndNewTarget == 2); STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput);
STATIC_ASSERT(JSConstructNode::kExtraInputCount == 2);
const bool inliner_is_call = call->opcode() == IrOpcode::kJSCall; const bool inliner_is_call = call->opcode() == IrOpcode::kJSCall;
const int inliner_inputs = inliner_is_call const int inliner_inputs = inliner_is_call
? call->op()->ValueInputCount() - ? call->op()->ValueInputCount() -
...@@ -139,7 +126,7 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context, ...@@ -139,7 +126,7 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context,
// The projection is requesting the number of arguments. // The projection is requesting the number of arguments.
STATIC_ASSERT(JSCallNode::kExtraInputCount == STATIC_ASSERT(JSCallNode::kExtraInputCount ==
JSCallNode::kFeedbackVectorInputCount + 2); JSCallNode::kFeedbackVectorInputCount + 2);
STATIC_ASSERT(kTargetAndNewTarget == 2); STATIC_ASSERT(JSConstructNode::kExtraInputCount == 2);
Replace(use, jsgraph()->Constant(inliner_inputs - 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.
...@@ -274,18 +261,19 @@ Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state, ...@@ -274,18 +261,19 @@ Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state,
// `new_target` has been put into the receiver slot. // `new_target` has been put into the receiver slot.
// TODO(jgruber): Either unify the layout of these two nodes, or // TODO(jgruber): Either unify the layout of these two nodes, or
// refactor this to be more expected in some way. // refactor this to be more expected in some way.
JSCallAccessor call(node); STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput);
NodeVector params(local_zone_); NodeVector params(local_zone_);
params.push_back(node->InputAt(JSCallNode::ReceiverIndex())); params.push_back(node->InputAt(JSCallNode::ReceiverIndex()));
for (int i = 0; i < parameter_count; i++) { for (int i = 0; i < parameter_count; i++) {
params.push_back(call.argument(i)); params.push_back(node->InputAt(JSCallNode::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());
Node* params_node = graph()->NewNode( Node* params_node = graph()->NewNode(
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, call.target(), return graph()->NewNode(op, params_node, node0, node0, context,
node->InputAt(JSCallNode::TargetIndex()),
outer_frame_state); outer_frame_state);
} }
...@@ -311,6 +299,7 @@ base::Optional<SharedFunctionInfoRef> JSInliner::DetermineCallTarget( ...@@ -311,6 +299,7 @@ base::Optional<SharedFunctionInfoRef> JSInliner::DetermineCallTarget(
// 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...)
// - JSConstruct(target:constant, args..., new.target) // - JSConstruct(target:constant, args..., new.target)
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();
...@@ -338,6 +327,7 @@ base::Optional<SharedFunctionInfoRef> JSInliner::DetermineCallTarget( ...@@ -338,6 +327,7 @@ base::Optional<SharedFunctionInfoRef> JSInliner::DetermineCallTarget(
// 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...)
// - JSConstruct(JSCreateClosure[shared](context), args..., new.target) // - JSConstruct(JSCreateClosure[shared](context), args..., new.target)
STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput);
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());
...@@ -525,13 +515,12 @@ Reduction JSInliner::ReduceJSCall(Node* node) { ...@@ -525,13 +515,12 @@ 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) {
JSConstructNode n(node);
// Swizzle the inputs of the {JSConstruct} node to look like inputs to a // Swizzle the inputs of the {JSConstruct} node to look like inputs to a
// normal {JSCall} node so that the rest of the inlining machinery // normal {JSCall} node so that the rest of the inlining machinery
// behaves as if we were dealing with a regular function invocation. // behaves as if we were dealing with a regular function invocation.
new_target = call.new_target(); // Retrieve new target value input. STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput);
// TODO(jgruber,v8:8888): Update when JSConstruct nodes also gain a new_target = node->RemoveInput(n.NewTargetIndex());
// feedback vector input.
node->RemoveInput(call.formal_arguments() + 1); // Drop new target.
node->InsertInput(graph()->zone(), JSCallNode::ReceiverIndex(), new_target); 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
...@@ -545,10 +534,10 @@ Reduction JSInliner::ReduceJSCall(Node* node) { ...@@ -545,10 +534,10 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
Node* receiver = jsgraph()->TheHoleConstant(); // Implicit receiver. Node* receiver = jsgraph()->TheHoleConstant(); // Implicit receiver.
Node* context = NodeProperties::GetContextInput(node); Node* context = NodeProperties::GetContextInput(node);
if (NeedsImplicitReceiver(*shared_info)) { if (NeedsImplicitReceiver(*shared_info)) {
Node* effect = NodeProperties::GetEffectInput(node); Effect effect = n.effect();
Node* control = NodeProperties::GetControlInput(node); Control control = n.control();
Node* frame_state_inside = CreateArtificialFrameState( Node* frame_state_inside = CreateArtificialFrameState(
node, frame_state, call.formal_arguments(), node, frame_state, n.ArgumentCount(),
BailoutId::ConstructStubCreate(), FrameStateType::kConstructStub, BailoutId::ConstructStubCreate(), FrameStateType::kConstructStub,
*shared_info, context); *shared_info, context);
Node* create = Node* create =
...@@ -603,9 +592,8 @@ Reduction JSInliner::ReduceJSCall(Node* node) { ...@@ -603,9 +592,8 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
// Insert a construct stub frame into the chain of frame states. This will // Insert a construct stub frame into the chain of frame states. This will
// reconstruct the proper frame when deoptimizing within the constructor. // reconstruct the proper frame when deoptimizing within the constructor.
frame_state = CreateArtificialFrameState( frame_state = CreateArtificialFrameState(
node, frame_state, call.formal_arguments(), node, frame_state, n.ArgumentCount(), BailoutId::ConstructStubInvoke(),
BailoutId::ConstructStubInvoke(), FrameStateType::kConstructStub, FrameStateType::kConstructStub, *shared_info, context);
*shared_info, context);
} }
// Insert a JSConvertReceiver node for sloppy callees. Note that the context // Insert a JSConvertReceiver node for sloppy callees. Note that the context
......
...@@ -28,15 +28,13 @@ constexpr Operator::Properties BinopProperties(Operator::Opcode opcode) { ...@@ -28,15 +28,13 @@ constexpr Operator::Properties BinopProperties(Operator::Opcode opcode) {
} // namespace } // namespace
template <int kOpcode> namespace js_node_wrapper_utils {
TNode<Object> JSCallNodeBase<kOpcode>::ArgumentOrUndefined(
int i, JSGraph* jsgraph) const { TNode<Oddball> UndefinedConstant(JSGraph* jsgraph) {
return ArgumentOr(i, jsgraph->UndefinedConstant()); return TNode<Oddball>::UncheckedCast(jsgraph->UndefinedConstant());
} }
template class JSCallNodeBase<IrOpcode::kJSCall>; } // namespace js_node_wrapper_utils
template class JSCallNodeBase<IrOpcode::kJSCallWithSpread>;
template class JSCallNodeBase<IrOpcode::kJSCallWithArrayLike>;
std::ostream& operator<<(std::ostream& os, CallFrequency const& f) { std::ostream& operator<<(std::ostream& os, CallFrequency const& f) {
if (f.IsUnknown()) return os << "unknown"; if (f.IsUnknown()) return os << "unknown";
......
...@@ -140,18 +140,19 @@ std::ostream& operator<<(std::ostream&, ...@@ -140,18 +140,19 @@ std::ostream& operator<<(std::ostream&,
ConstructForwardVarargsParameters const& ConstructForwardVarargsParametersOf( ConstructForwardVarargsParameters const& ConstructForwardVarargsParametersOf(
Operator const*) V8_WARN_UNUSED_RESULT; Operator const*) V8_WARN_UNUSED_RESULT;
// Part of ConstructParameters::arity.
static constexpr int kTargetAndNewTarget = 2;
// Defines the arity (parameters plus the target and new target) and the // Defines the arity (parameters plus the target and new target) and the
// feedback for a JavaScript constructor call. This is used as a parameter by // feedback for a JavaScript constructor call. This is used as a parameter by
// JSConstruct, JSConstructWithArrayLike, and JSConstructWithSpread operators. // JSConstruct, JSConstructWithArrayLike, and JSConstructWithSpread operators.
class ConstructParameters final { class ConstructParameters final {
public: public:
// A separate declaration to get around circular declaration dependencies.
// Checked to equal JSConstructNode::kExtraInputCount below.
static constexpr int kExtraConstructInputCount = 2;
ConstructParameters(uint32_t arity, CallFrequency const& frequency, ConstructParameters(uint32_t arity, CallFrequency const& frequency,
FeedbackSource const& feedback) FeedbackSource const& feedback)
: arity_(arity), frequency_(frequency), feedback_(feedback) { : arity_(arity), frequency_(frequency), feedback_(feedback) {
DCHECK_GE(arity, kTargetAndNewTarget); DCHECK_GE(arity, kExtraConstructInputCount);
DCHECK(is_int32(arity)); DCHECK(is_int32(arity));
} }
...@@ -163,7 +164,7 @@ class ConstructParameters final { ...@@ -163,7 +164,7 @@ class ConstructParameters final {
// that expect `arity()` to include extra args. // that expect `arity()` to include extra args.
uint32_t arity() const { return arity_; } uint32_t arity() const { return arity_; }
int arity_without_implicit_args() const { int arity_without_implicit_args() const {
return static_cast<int>(arity_ - kTargetAndNewTarget); return static_cast<int>(arity_ - kExtraConstructInputCount);
} }
CallFrequency const& frequency() const { return frequency_; } CallFrequency const& frequency() const { return frequency_; }
...@@ -1216,6 +1217,11 @@ class JSStorePropertyNode final : public JSNodeWrapperBase { ...@@ -1216,6 +1217,11 @@ class JSStorePropertyNode final : public JSNodeWrapperBase {
#undef INPUTS #undef INPUTS
}; };
namespace js_node_wrapper_utils {
// Avoids template definitions in the .cc file.
TNode<Oddball> UndefinedConstant(JSGraph* jsgraph);
} // namespace js_node_wrapper_utils
template <int kOpcode> template <int kOpcode>
class JSCallNodeBase final : public JSNodeWrapperBase { class JSCallNodeBase final : public JSNodeWrapperBase {
public: public:
...@@ -1271,7 +1277,9 @@ class JSCallNodeBase final : public JSNodeWrapperBase { ...@@ -1271,7 +1277,9 @@ class JSCallNodeBase final : public JSNodeWrapperBase {
return i < ArgumentCount() ? Argument(i) return i < ArgumentCount() ? Argument(i)
: TNode<Object>::UncheckedCast(default_value); : TNode<Object>::UncheckedCast(default_value);
} }
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));
}
int ArgumentCount() const { int ArgumentCount() const {
// Note: The count reported by this function depends only on the parameter, // Note: The count reported by this function depends only on the parameter,
// thus adding/removing inputs will not affect it. // thus adding/removing inputs will not affect it.
...@@ -1295,6 +1303,85 @@ using JSCallNode = JSCallNodeBase<IrOpcode::kJSCall>; ...@@ -1295,6 +1303,85 @@ 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>
class JSConstructNodeBase final : public JSNodeWrapperBase {
public:
explicit constexpr JSConstructNodeBase(Node* node) : JSNodeWrapperBase(node) {
CONSTEXPR_DCHECK(node->opcode() == kOpcode);
}
const ConstructParameters& Parameters() const {
return ConstructParametersOf(node()->op());
}
#define INPUTS(V) V(Target, target, 0, Object)
INPUTS(DEFINE_INPUT_ACCESSORS)
#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 kExtraInputCount =
kTargetInputCount + kNewTargetInputCount;
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 {
// Note: The count reported by this function remains static even if the node
// is currently being modified.
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 JSConstructWithSpreadNode =
JSConstructNodeBase<IrOpcode::kJSConstructWithSpread>;
using JSConstructWithArrayLikeNode =
JSConstructNodeBase<IrOpcode::kJSConstructWithArrayLike>;
#undef DEFINE_INPUT_ACCESSORS #undef DEFINE_INPUT_ACCESSORS
} // namespace compiler } // namespace compiler
......
...@@ -1526,12 +1526,21 @@ void ReduceBuiltin(JSGraph* jsgraph, Node* node, int builtin_index, int arity, ...@@ -1526,12 +1526,21 @@ 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.
const bool is_construct = (node->opcode() == IrOpcode::kJSConstruct); STATIC_ASSERT(JSCallNode::TargetIndex() == JSConstructNode::TargetIndex());
Node* target = node->InputAt(JSCallNode::TargetIndex());
Node* target = NodeProperties::GetValueInput(node, 0); Node* new_target;
Node* new_target = is_construct Zone* zone = jsgraph->zone();
? NodeProperties::GetValueInput(node, arity + 1) if (node->opcode() == IrOpcode::kJSConstruct) {
: jsgraph->UndefinedConstant(); // Unify representations between construct and call nodes.
// Remove new target and add receiver.
STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput);
new_target = node->RemoveInput(JSConstructNode{node}.NewTargetIndex());
node->InsertInput(zone, JSCallNode::ReceiverIndex(),
jsgraph->UndefinedConstant());
} else {
new_target = jsgraph->UndefinedConstant();
}
// CPP builtins are implemented in C++, and we can inline it. // CPP builtins are implemented in C++, and we can inline it.
// CPP builtins create a builtin exit frame. // CPP builtins create a builtin exit frame.
...@@ -1542,7 +1551,6 @@ void ReduceBuiltin(JSGraph* jsgraph, Node* node, int builtin_index, int arity, ...@@ -1542,7 +1551,6 @@ void ReduceBuiltin(JSGraph* jsgraph, Node* node, int builtin_index, int arity,
has_builtin_exit_frame); has_builtin_exit_frame);
node->ReplaceInput(0, stub); node->ReplaceInput(0, stub);
Zone* zone = jsgraph->zone();
const int argc = arity + BuiltinArguments::kNumExtraArgsWithReceiver; const int argc = arity + BuiltinArguments::kNumExtraArgsWithReceiver;
Node* argc_node = jsgraph->Constant(argc); Node* argc_node = jsgraph->Constant(argc);
...@@ -1552,24 +1560,8 @@ void ReduceBuiltin(JSGraph* jsgraph, Node* node, int builtin_index, int arity, ...@@ -1552,24 +1560,8 @@ void ReduceBuiltin(JSGraph* jsgraph, Node* node, int builtin_index, int arity,
node->InsertInput(zone, 2, target); node->InsertInput(zone, 2, target);
node->InsertInput(zone, 3, argc_node); node->InsertInput(zone, 3, argc_node);
node->InsertInput(zone, 4, jsgraph->PaddingConstant()); node->InsertInput(zone, 4, jsgraph->PaddingConstant());
if (is_construct) {
// Unify representations between construct and call nodes.
// Remove new target and add receiver as a stack parameter.
Node* receiver = jsgraph->UndefinedConstant();
node->RemoveInput(argc);
node->InsertInput(zone, 5, receiver);
}
int cursor = arity + kStubAndReceiver + BuiltinArguments::kNumExtraArgs; int cursor = arity + kStubAndReceiver + BuiltinArguments::kNumExtraArgs;
#else #else
if (is_construct) {
// Unify representations between construct and call nodes.
// Remove new target and add receiver as a stack parameter.
Node* receiver = jsgraph->UndefinedConstant();
node->RemoveInput(arity + 1);
node->InsertInput(zone, 1, receiver);
}
int cursor = arity + kStubAndReceiver; int cursor = arity + kStubAndReceiver;
node->InsertInput(zone, cursor++, jsgraph->PaddingConstant()); node->InsertInput(zone, cursor++, jsgraph->PaddingConstant());
node->InsertInput(zone, cursor++, argc_node); node->InsertInput(zone, cursor++, argc_node);
...@@ -1639,12 +1631,12 @@ Reduction JSTypedLowering::ReduceJSConstructForwardVarargs(Node* node) { ...@@ -1639,12 +1631,12 @@ Reduction JSTypedLowering::ReduceJSConstructForwardVarargs(Node* node) {
} }
Reduction JSTypedLowering::ReduceJSConstruct(Node* node) { Reduction JSTypedLowering::ReduceJSConstruct(Node* node) {
DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode()); JSConstructNode n(node);
ConstructParameters const& p = ConstructParametersOf(node->op()); ConstructParameters const& p = n.Parameters();
int const arity = p.arity_without_implicit_args(); int const arity = p.arity_without_implicit_args();
Node* target = NodeProperties::GetValueInput(node, 0); Node* target = n.target();
Type target_type = NodeProperties::GetType(target); Type target_type = NodeProperties::GetType(target);
Node* new_target = NodeProperties::GetValueInput(node, arity + 1); 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() &&
...@@ -1665,7 +1657,8 @@ Reduction JSTypedLowering::ReduceJSConstruct(Node* node) { ...@@ -1665,7 +1657,8 @@ 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));
node->RemoveInput(arity + 1); STATIC_ASSERT(JSConstructNode::kNewTargetIsLastInput);
node->RemoveInput(n.NewTargetIndex());
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(), 2, new_target);
node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity)); node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
......
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