Commit 3c869fde authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[compiler] Extend impl and uses of the FrameState node wrapper

Move index constants into the wrapper, add getters, and use the
wrapper in more spots.

Bug: v8:1166136
Change-Id: I3f37a541482fd6b7c604719c759952a72d58bad2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2637218
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarMaya Lekova <mslekova@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72198}
parent f1730ded
......@@ -671,7 +671,7 @@ size_t InstructionSelector::AddInputsToFrameStateDescriptor(
// Returns the number of instruction operands added to inputs.
size_t InstructionSelector::AddInputsToFrameStateDescriptor(
FrameStateDescriptor* descriptor, Node* state, OperandGenerator* g,
FrameStateDescriptor* descriptor, FrameState state, OperandGenerator* g,
StateObjectDeduplicator* deduplicator, InstructionOperandVector* inputs,
FrameStateInputKind kind, Zone* zone) {
DCHECK_EQ(IrOpcode::kFrameState, state->op()->opcode());
......@@ -682,15 +682,15 @@ size_t InstructionSelector::AddInputsToFrameStateDescriptor(
if (descriptor->outer_state()) {
entries += AddInputsToFrameStateDescriptor(
descriptor->outer_state(), state->InputAt(kFrameStateOuterStateInput),
g, deduplicator, inputs, kind, zone);
descriptor->outer_state(), state.outer_frame_state(), g, deduplicator,
inputs, kind, zone);
}
Node* parameters = state->InputAt(kFrameStateParametersInput);
Node* locals = state->InputAt(kFrameStateLocalsInput);
Node* stack = state->InputAt(kFrameStateStackInput);
Node* context = state->InputAt(kFrameStateContextInput);
Node* function = state->InputAt(kFrameStateFunctionInput);
Node* parameters = state.parameters();
Node* locals = state.locals();
Node* stack = state.stack();
Node* context = state.context();
Node* function = state.function();
DCHECK_EQ(descriptor->parameters_count(),
StateValuesAccess(parameters).size());
......@@ -803,7 +803,7 @@ Instruction* InstructionSelector::EmitWithContinuation(
DeoptFrameStateOffsetField::encode(static_cast<int>(input_count));
AppendDeoptimizeArguments(&continuation_inputs_, cont->kind(),
cont->reason(), cont->feedback(),
cont->frame_state());
FrameState{cont->frame_state()});
} else if (cont->IsSet()) {
continuation_outputs_.push_back(g.DefineAsRegister(cont->result()));
} else if (cont->IsTrap()) {
......@@ -828,7 +828,7 @@ Instruction* InstructionSelector::EmitWithContinuation(
void InstructionSelector::AppendDeoptimizeArguments(
InstructionOperandVector* args, DeoptimizeKind kind,
DeoptimizeReason reason, FeedbackSource const& feedback,
Node* frame_state) {
FrameState frame_state) {
OperandGenerator g(this);
FrameStateDescriptor* const descriptor = GetFrameStateDescriptor(frame_state);
DCHECK_NE(DeoptimizeKind::kLazy, kind);
......@@ -1015,20 +1015,21 @@ void InstructionSelector::InitializeCallBuffer(Node* call, CallBuffer* buffer,
size_t frame_state_entries = 0;
USE(frame_state_entries); // frame_state_entries is only used for debug.
if (buffer->frame_state_descriptor != nullptr) {
Node* frame_state =
call->InputAt(static_cast<int>(buffer->descriptor->InputCount()));
FrameState frame_state{
call->InputAt(static_cast<int>(buffer->descriptor->InputCount()))};
// If it was a syntactic tail call we need to drop the current frame and
// all the frames on top of it that are either an arguments adaptor frame
// or a tail caller frame.
if (is_tail_call) {
frame_state = NodeProperties::GetFrameStateInput(frame_state);
frame_state = FrameState{NodeProperties::GetFrameStateInput(frame_state)};
buffer->frame_state_descriptor =
buffer->frame_state_descriptor->outer_state();
while (buffer->frame_state_descriptor != nullptr &&
buffer->frame_state_descriptor->type() ==
FrameStateType::kArgumentsAdaptor) {
frame_state = NodeProperties::GetFrameStateInput(frame_state);
frame_state =
FrameState{NodeProperties::GetFrameStateInput(frame_state)};
buffer->frame_state_descriptor =
buffer->frame_state_descriptor->outer_state();
}
......@@ -1288,7 +1289,7 @@ void InstructionSelector::VisitControl(BasicBlock* block) {
}
case BasicBlock::kDeoptimize: {
DeoptimizeParameters p = DeoptimizeParametersOf(input->op());
Node* value = input->InputAt(0);
FrameState value{input->InputAt(0)};
VisitDeoptimize(p.kind(), p.reason(), p.feedback(), value);
break;
}
......@@ -2939,8 +2940,8 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
FrameStateDescriptor* frame_state_descriptor = nullptr;
if (call_descriptor->NeedsFrameState()) {
frame_state_descriptor = GetFrameStateDescriptor(
node->InputAt(static_cast<int>(call_descriptor->InputCount())));
frame_state_descriptor = GetFrameStateDescriptor(FrameState{
node->InputAt(static_cast<int>(call_descriptor->InputCount()))});
}
CallBuffer buffer(zone(), call_descriptor, frame_state_descriptor);
......@@ -3199,7 +3200,7 @@ void InstructionSelector::EmitIdentity(Node* node) {
void InstructionSelector::VisitDeoptimize(DeoptimizeKind kind,
DeoptimizeReason reason,
FeedbackSource const& feedback,
Node* frame_state) {
FrameState frame_state) {
InstructionOperandVector args(instruction_zone());
AppendDeoptimizeArguments(&args, kind, reason, feedback, frame_state);
Emit(kArchDeoptimize, 0, nullptr, args.size(), &args.front(), 0, nullptr);
......@@ -3315,18 +3316,19 @@ bool InstructionSelector::ZeroExtendsWord32ToWord64(Node* node,
namespace {
FrameStateDescriptor* GetFrameStateDescriptorInternal(Zone* zone, Node* state) {
FrameStateDescriptor* GetFrameStateDescriptorInternal(Zone* zone,
FrameState state) {
DCHECK_EQ(IrOpcode::kFrameState, state->opcode());
DCHECK_EQ(kFrameStateInputCount, state->InputCount());
DCHECK_EQ(FrameState::kFrameStateInputCount, state->InputCount());
const FrameStateInfo& state_info = FrameStateInfoOf(state->op());
int parameters = state_info.parameter_count();
int locals = state_info.local_count();
int stack = state_info.type() == FrameStateType::kInterpretedFunction ? 1 : 0;
FrameStateDescriptor* outer_state = nullptr;
Node* outer_node = state->InputAt(kFrameStateOuterStateInput);
if (outer_node->opcode() == IrOpcode::kFrameState) {
outer_state = GetFrameStateDescriptorInternal(zone, outer_node);
if (state.has_outer_frame_state()) {
outer_state =
GetFrameStateDescriptorInternal(zone, state.outer_frame_state());
}
if (state_info.type() == FrameStateType::kJSToWasmBuiltinContinuation) {
......@@ -3347,7 +3349,7 @@ FrameStateDescriptor* GetFrameStateDescriptorInternal(Zone* zone, Node* state) {
} // namespace
FrameStateDescriptor* InstructionSelector::GetFrameStateDescriptor(
Node* state) {
FrameState state) {
auto* desc = GetFrameStateDescriptorInternal(instruction_zone(), state);
*max_unoptimized_frame_height_ =
std::max(*max_unoptimized_frame_height_,
......
......@@ -491,7 +491,7 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
void AppendDeoptimizeArguments(InstructionOperandVector* args,
DeoptimizeKind kind, DeoptimizeReason reason,
FeedbackSource const& feedback,
Node* frame_state);
FrameState frame_state);
void EmitTableSwitch(const SwitchInfo& sw,
InstructionOperand const& index_operand);
......@@ -564,9 +564,9 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
void UpdateMaxPushedArgumentCount(size_t count);
FrameStateDescriptor* GetFrameStateDescriptor(Node* node);
FrameStateDescriptor* GetFrameStateDescriptor(FrameState node);
size_t AddInputsToFrameStateDescriptor(FrameStateDescriptor* descriptor,
Node* state, OperandGenerator* g,
FrameState state, OperandGenerator* g,
StateObjectDeduplicator* deduplicator,
InstructionOperandVector* inputs,
FrameStateInputKind kind, Zone* zone);
......@@ -627,7 +627,7 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
void VisitBranch(Node* input, BasicBlock* tbranch, BasicBlock* fbranch);
void VisitSwitch(Node* node, const SwitchInfo& sw);
void VisitDeoptimize(DeoptimizeKind kind, DeoptimizeReason reason,
FeedbackSource const& feedback, Node* frame_state);
FeedbackSource const& feedback, FrameState frame_state);
void VisitReturn(Node* ret);
void VisitThrow(Node* node);
void VisitRetain(Node* node);
......
......@@ -601,6 +601,65 @@ class CommonNodeWrapperBase : public NodeWrapper {
NodeProperties::GetValueInput(node(), TheIndex)); \
}
// TODO(jgruber): This class doesn't match the usual OpcodeNode naming
// convention for historical reasons (it was originally a very basic typed node
// wrapper similar to Effect and Control). Consider updating the name, with low
// priority.
class FrameState : public CommonNodeWrapperBase {
public:
explicit constexpr FrameState(Node* node) : CommonNodeWrapperBase(node) {
// TODO(jgruber): Disallow kStart (needed for PromiseConstructorBasic unit
// test, among others). Also, outer_frame_state points at the start node
// for non-inlined functions. This could be avoided by checking
// has_outer_frame_state() before casting to FrameState.
CONSTEXPR_DCHECK(node->opcode() == IrOpcode::kFrameState ||
node->opcode() == IrOpcode::kStart);
}
FrameStateInfo frame_state_info() const {
return FrameStateInfoOf(node()->op());
}
static constexpr int kFrameStateParametersInput = 0;
static constexpr int kFrameStateLocalsInput = 1;
static constexpr int kFrameStateStackInput = 2;
static constexpr int kFrameStateContextInput = 3;
static constexpr int kFrameStateFunctionInput = 4;
static constexpr int kFrameStateOuterStateInput = 5;
static constexpr int kFrameStateInputCount = 6;
// Note: The parameters should be accessed through StateValuesAccess.
Node* parameters() const {
Node* n = node()->InputAt(kFrameStateParametersInput);
DCHECK(n->opcode() == IrOpcode::kStateValues ||
n->opcode() == IrOpcode::kTypedStateValues);
return n;
}
Node* locals() const {
Node* n = node()->InputAt(kFrameStateLocalsInput);
DCHECK(n->opcode() == IrOpcode::kStateValues ||
n->opcode() == IrOpcode::kTypedStateValues);
return n;
}
// TODO(jgruber): Consider renaming this to the more meaningful
// 'accumulator'.
Node* stack() const { return node()->InputAt(kFrameStateStackInput); }
Node* context() const { return node()->InputAt(kFrameStateContextInput); }
Node* function() const { return node()->InputAt(kFrameStateFunctionInput); }
// An outer frame state exists for inlined functions; otherwise it points at
// the start node.
bool has_outer_frame_state() const {
Node* maybe_outer_frame_state = node()->InputAt(kFrameStateOuterStateInput);
DCHECK(maybe_outer_frame_state->opcode() == IrOpcode::kFrameState ||
maybe_outer_frame_state->opcode() == IrOpcode::kStart);
return maybe_outer_frame_state->opcode() == IrOpcode::kFrameState;
}
FrameState outer_frame_state() const {
return FrameState{node()->InputAt(kFrameStateOuterStateInput)};
}
};
class StartNode final : public CommonNodeWrapperBase {
public:
explicit constexpr StartNode(Node* node) : CommonNodeWrapperBase(node) {
......
......@@ -159,9 +159,12 @@ Node* EscapeAnalysisReducer::ReduceDeoptState(Node* node, Node* effect,
// This input order is important to match the DFS traversal used in the
// instruction selector. Otherwise, the instruction selector might find a
// duplicate node before the original one.
for (int input_id : {kFrameStateOuterStateInput, kFrameStateFunctionInput,
kFrameStateParametersInput, kFrameStateContextInput,
kFrameStateLocalsInput, kFrameStateStackInput}) {
for (int input_id : {FrameState::kFrameStateOuterStateInput,
FrameState::kFrameStateFunctionInput,
FrameState::kFrameStateParametersInput,
FrameState::kFrameStateContextInput,
FrameState::kFrameStateLocalsInput,
FrameState::kFrameStateStackInput}) {
Node* input = node->InputAt(input_id);
new_node.ReplaceInput(ReduceDeoptState(input, effect, deduplicator),
input_id);
......
......@@ -17,11 +17,6 @@ namespace v8 {
namespace internal {
namespace compiler {
// Guard equality of these constants. Ideally they should be merged at
// some point.
STATIC_ASSERT(kFrameStateOuterStateInput ==
FrameState::kFrameStateOuterStateInput);
size_t hash_value(OutputFrameStateCombine const& sc) {
return base::hash_value(sc.parameter_);
}
......
......@@ -160,16 +160,10 @@ size_t hash_value(FrameStateInfo const&);
std::ostream& operator<<(std::ostream&, FrameStateInfo const&);
static constexpr int kFrameStateParametersInput = 0;
static constexpr int kFrameStateLocalsInput = 1;
static constexpr int kFrameStateStackInput = 2;
static constexpr int kFrameStateContextInput = 3;
static constexpr int kFrameStateFunctionInput = 4;
static constexpr int kFrameStateOuterStateInput = 5;
static constexpr int kFrameStateInputCount = kFrameStateOuterStateInput + 1;
enum class ContinuationFrameStateMode { EAGER, LAZY, LAZY_WITH_CATCH };
class FrameState;
FrameState CreateStubBuiltinContinuationFrameState(
JSGraph* graph, Builtins::Name name, Node* context, Node* const* parameters,
int parameter_count, Node* outer_frame_state,
......
......@@ -3879,13 +3879,14 @@ Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
// we can only optimize this in case the {node} was already inlined into
// some other function (and same for the {arguments_list}).
CreateArgumentsType const type = CreateArgumentsTypeOf(arguments_list->op());
Node* frame_state = NodeProperties::GetFrameStateInput(arguments_list);
FrameState frame_state =
FrameState{NodeProperties::GetFrameStateInput(arguments_list)};
int start_index = 0;
int formal_parameter_count;
{
Handle<SharedFunctionInfo> shared;
if (!FrameStateInfoOf(frame_state->op()).shared_info().ToHandle(&shared)) {
if (!frame_state.frame_state_info().shared_info().ToHandle(&shared)) {
return NoChange();
}
formal_parameter_count = SharedFunctionInfoRef(broker(), shared)
......@@ -3926,8 +3927,7 @@ Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
arraylike_or_spread_index - JSCallOrConstructNode::FirstArgumentIndex();
// Check if are spreading to inlined arguments or to the arguments of
// the outermost function.
Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
if (outer_state->opcode() != IrOpcode::kFrameState) {
if (!frame_state.has_outer_frame_state()) {
Operator const* op;
if (IsCallWithArrayLikeOrSpread(node)) {
static constexpr int kTargetAndReceiver = 2;
......@@ -3942,21 +3942,20 @@ Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
NodeProperties::ChangeOp(node, op);
return Changed(node);
}
FrameState outer_state = frame_state.outer_frame_state();
// Get to the actual frame state from which to extract the arguments;
// we can only optimize this in case the {node} was already inlined into
// some other function (and same for the {arg_array}).
FrameStateInfo outer_info = FrameStateInfoOf(outer_state->op());
FrameStateInfo outer_info = outer_state.frame_state_info();
if (outer_info.type() == FrameStateType::kArgumentsAdaptor) {
// Need to take the parameters from the arguments adaptor.
frame_state = outer_state;
}
// Add the actual parameters to the {node}, skipping the receiver.
const int argument_count =
FrameStateInfoOf(frame_state->op()).parameter_count() -
1; // Minus receiver.
frame_state.frame_state_info().parameter_count() - 1; // Minus receiver.
if (start_index < argument_count) {
Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
StateValuesAccess parameters_access(parameters);
StateValuesAccess parameters_access(frame_state.parameters());
auto parameters_it = ++parameters_access.begin(); // Skip the receiver.
for (int i = 0; i < start_index; i++) {
// A non-zero start_index implies that there are rest arguments. Skip
......
......@@ -36,10 +36,10 @@ namespace compiler {
namespace {
// Retrieves the frame state holding actual argument values.
Node* GetArgumentsFrameState(Node* frame_state) {
Node* const outer_state = NodeProperties::GetFrameStateInput(frame_state);
FrameStateInfo outer_state_info = FrameStateInfoOf(outer_state->op());
return outer_state_info.type() == FrameStateType::kArgumentsAdaptor
FrameState GetArgumentsFrameState(FrameState frame_state) {
FrameState outer_state{NodeProperties::GetFrameStateInput(frame_state)};
return outer_state.frame_state_info().type() ==
FrameStateType::kArgumentsAdaptor
? outer_state
: frame_state;
}
......@@ -148,16 +148,15 @@ Reduction JSCreateLowering::ReduceJSCreate(Node* node) {
Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
DCHECK_EQ(IrOpcode::kJSCreateArguments, node->opcode());
CreateArgumentsType type = CreateArgumentsTypeOf(node->op());
Node* const frame_state = NodeProperties::GetFrameStateInput(node);
Node* const outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
FrameState frame_state{NodeProperties::GetFrameStateInput(node)};
Node* const control = graph()->start();
FrameStateInfo state_info = FrameStateInfoOf(frame_state->op());
FrameStateInfo state_info = frame_state.frame_state_info();
SharedFunctionInfoRef shared(broker(),
state_info.shared_info().ToHandleChecked());
// Use the ArgumentsAccessStub for materializing both mapped and unmapped
// arguments object, but only for non-inlined (i.e. outermost) frames.
if (outer_state->opcode() != IrOpcode::kFrameState) {
if (!frame_state.has_outer_frame_state()) {
switch (type) {
case CreateArgumentsType::kMappedArguments: {
// TODO(turbofan): Duplicate parameters are not handled yet.
......@@ -263,7 +262,7 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
}
// Use inline allocation for all mapped arguments objects within inlined
// (i.e. non-outermost) frames, independent of the object size.
DCHECK_EQ(outer_state->opcode(), IrOpcode::kFrameState);
DCHECK_EQ(frame_state.outer_frame_state()->opcode(), IrOpcode::kFrameState);
switch (type) {
case CreateArgumentsType::kMappedArguments: {
Node* const callee = NodeProperties::GetValueInput(node, 0);
......@@ -274,15 +273,14 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
// Choose the correct frame state and frame state info depending on
// whether there conceptually is an arguments adaptor frame in the call
// chain.
Node* const args_state = GetArgumentsFrameState(frame_state);
if (args_state->InputAt(kFrameStateParametersInput)->opcode() ==
IrOpcode::kDeadValue) {
FrameState args_state = GetArgumentsFrameState(frame_state);
if (args_state.parameters()->opcode() == IrOpcode::kDeadValue) {
// This protects against an incompletely propagated DeadValue node.
// If the FrameState has a DeadValue input, then this node will be
// pruned anyway.
return NoChange();
}
FrameStateInfo args_state_info = FrameStateInfoOf(args_state->op());
FrameStateInfo args_state_info = args_state.frame_state_info();
int length = args_state_info.parameter_count() - 1; // Minus receiver.
// Check that the array allocated for arguments is not "large".
{
......@@ -319,15 +317,14 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
// Choose the correct frame state and frame state info depending on
// whether there conceptually is an arguments adaptor frame in the call
// chain.
Node* const args_state = GetArgumentsFrameState(frame_state);
if (args_state->InputAt(kFrameStateParametersInput)->opcode() ==
IrOpcode::kDeadValue) {
FrameState args_state = GetArgumentsFrameState(frame_state);
if (args_state.parameters()->opcode() == IrOpcode::kDeadValue) {
// This protects against an incompletely propagated DeadValue node.
// If the FrameState has a DeadValue input, then this node will be
// pruned anyway.
return NoChange();
}
FrameStateInfo args_state_info = FrameStateInfoOf(args_state->op());
FrameStateInfo args_state_info = args_state.frame_state_info();
int length = args_state_info.parameter_count() - 1; // Minus receiver.
// Check that the array allocated for arguments is not "large".
{
......@@ -361,15 +358,14 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
// Choose the correct frame state and frame state info depending on
// whether there conceptually is an arguments adaptor frame in the call
// chain.
Node* const args_state = GetArgumentsFrameState(frame_state);
if (args_state->InputAt(kFrameStateParametersInput)->opcode() ==
IrOpcode::kDeadValue) {
FrameState args_state = GetArgumentsFrameState(frame_state);
if (args_state.parameters()->opcode() == IrOpcode::kDeadValue) {
// This protects against an incompletely propagated DeadValue node.
// If the FrameState has a DeadValue input, then this node will be
// pruned anyway.
return NoChange();
}
FrameStateInfo args_state_info = FrameStateInfoOf(args_state->op());
FrameStateInfo args_state_info = args_state.frame_state_info();
// Prepare element backing store to be used by the rest array.
Node* const elements =
AllocateRestArguments(effect, control, args_state, start_index);
......@@ -1428,13 +1424,13 @@ Reduction JSCreateLowering::ReduceJSCreateObject(Node* node) {
// Helper that allocates a FixedArray holding argument values recorded in the
// given {frame_state}. Serves as backing store for JSCreateArguments nodes.
Node* JSCreateLowering::AllocateArguments(Node* effect, Node* control,
Node* frame_state) {
FrameStateInfo state_info = FrameStateInfoOf(frame_state->op());
FrameState frame_state) {
FrameStateInfo state_info = frame_state.frame_state_info();
int argument_count = state_info.parameter_count() - 1; // Minus receiver.
if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant();
// Prepare an iterator over argument values recorded in the frame state.
Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
Node* const parameters = frame_state.parameters();
StateValuesAccess parameters_access(parameters);
auto parameters_it = ++parameters_access.begin();
......@@ -1453,15 +1449,15 @@ Node* JSCreateLowering::AllocateArguments(Node* effect, Node* control,
// Helper that allocates a FixedArray holding argument values recorded in the
// given {frame_state}. Serves as backing store for JSCreateArguments nodes.
Node* JSCreateLowering::AllocateRestArguments(Node* effect, Node* control,
Node* frame_state,
FrameState frame_state,
int start_index) {
FrameStateInfo state_info = FrameStateInfoOf(frame_state->op());
FrameStateInfo state_info = frame_state.frame_state_info();
int argument_count = state_info.parameter_count() - 1; // Minus receiver.
int num_elements = std::max(0, argument_count - start_index);
if (num_elements == 0) return jsgraph()->EmptyFixedArrayConstant();
// Prepare an iterator over argument values recorded in the frame state.
Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
Node* const parameters = frame_state.parameters();
StateValuesAccess parameters_access(parameters);
auto parameters_it = ++parameters_access.begin();
......@@ -1485,9 +1481,9 @@ Node* JSCreateLowering::AllocateRestArguments(Node* effect, Node* control,
// recorded in the given {frame_state}. Some elements map to slots within the
// given {context}. Serves as backing store for JSCreateArguments nodes.
Node* JSCreateLowering::AllocateAliasedArguments(
Node* effect, Node* control, Node* frame_state, Node* context,
Node* effect, Node* control, FrameState frame_state, Node* context,
const SharedFunctionInfoRef& shared, bool* has_aliased_arguments) {
FrameStateInfo state_info = FrameStateInfoOf(frame_state->op());
FrameStateInfo state_info = frame_state.frame_state_info();
int argument_count = state_info.parameter_count() - 1; // Minus receiver.
if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant();
......@@ -1503,7 +1499,7 @@ Node* JSCreateLowering::AllocateAliasedArguments(
*has_aliased_arguments = true;
// Prepare an iterator over argument values recorded in the frame state.
Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
Node* const parameters = frame_state.parameters();
StateValuesAccess parameters_access(parameters);
auto parameters_it = ++parameters_access.begin();
......
......@@ -22,6 +22,7 @@ namespace compiler {
// Forward declarations.
class CommonOperatorBuilder;
class CompilationDependencies;
class FrameState;
class JSGraph;
class JSOperatorBuilder;
class MachineOperatorBuilder;
......@@ -82,11 +83,11 @@ class V8_EXPORT_PRIVATE JSCreateLowering final
const SlackTrackingPrediction& slack_tracking_prediction);
Reduction ReduceJSCreateObject(Node* node);
Node* AllocateArguments(Node* effect, Node* control, Node* frame_state);
Node* AllocateRestArguments(Node* effect, Node* control, Node* frame_state,
int start_index);
Node* AllocateAliasedArguments(Node* effect, Node* control, Node* frame_state,
Node* context,
Node* AllocateArguments(Node* effect, Node* control, FrameState frame_state);
Node* AllocateRestArguments(Node* effect, Node* control,
FrameState frame_state, int start_index);
Node* AllocateAliasedArguments(Node* effect, Node* control,
FrameState frame_state, Node* context,
const SharedFunctionInfoRef& shared,
bool* has_aliased_arguments);
Node* AllocateAliasedArguments(Node* effect, Node* control, Node* context,
......
......@@ -171,8 +171,8 @@ Reduction JSInliningHeuristic::Reduce(Node* node) {
bool can_inline_candidate = false, candidate_is_small = true;
candidate.total_size = 0;
Node* frame_state = NodeProperties::GetFrameStateInput(node);
FrameStateInfo const& frame_info = FrameStateInfoOf(frame_state->op());
FrameState frame_state{NodeProperties::GetFrameStateInput(node)};
FrameStateInfo const& frame_info = frame_state.frame_state_info();
Handle<SharedFunctionInfo> frame_shared_info;
for (int i = 0; i < candidate.num_functions; ++i) {
if (!candidate.bytecode[i].has_value()) {
......@@ -341,19 +341,18 @@ Node* JSInliningHeuristic::DuplicateStateValuesAndRename(Node* state_values,
namespace {
bool CollectFrameStateUniqueUses(Node* node, Node* frame_state,
bool CollectFrameStateUniqueUses(Node* node, FrameState frame_state,
NodeAndIndex* uses_buffer, size_t* use_count,
size_t max_uses) {
// Only accumulate states that are not shared with other users.
if (frame_state->UseCount() > 1) return true;
if (frame_state->InputAt(kFrameStateStackInput) == node) {
if (frame_state.stack() == node) {
if (*use_count >= max_uses) return false;
uses_buffer[*use_count] = {frame_state, kFrameStateStackInput};
uses_buffer[*use_count] = {frame_state, FrameState::kFrameStateStackInput};
(*use_count)++;
}
if (!CollectStateValuesOwnedUses(node,
frame_state->InputAt(kFrameStateLocalsInput),
uses_buffer, use_count, max_uses)) {
if (!CollectStateValuesOwnedUses(node, frame_state.locals(), uses_buffer,
use_count, max_uses)) {
return false;
}
return true;
......@@ -361,28 +360,28 @@ bool CollectFrameStateUniqueUses(Node* node, Node* frame_state,
} // namespace
Node* JSInliningHeuristic::DuplicateFrameStateAndRename(Node* frame_state,
Node* from, Node* to,
StateCloneMode mode) {
FrameState JSInliningHeuristic::DuplicateFrameStateAndRename(
FrameState frame_state, Node* from, Node* to, StateCloneMode mode) {
// Only rename in states that are not shared with other users. This needs to
// be in sync with the condition in {DuplicateFrameStateAndRename}.
if (frame_state->UseCount() > 1) return frame_state;
Node* copy = mode == kChangeInPlace ? frame_state : nullptr;
if (frame_state->InputAt(kFrameStateStackInput) == from) {
Node* copy =
mode == kChangeInPlace ? static_cast<Node*>(frame_state) : nullptr;
if (frame_state.stack() == from) {
if (!copy) {
copy = graph()->CloneNode(frame_state);
}
copy->ReplaceInput(kFrameStateStackInput, to);
copy->ReplaceInput(FrameState::kFrameStateStackInput, to);
}
Node* locals = frame_state->InputAt(kFrameStateLocalsInput);
Node* locals = frame_state.locals();
Node* new_locals = DuplicateStateValuesAndRename(locals, from, to, mode);
if (new_locals != locals) {
if (!copy) {
copy = graph()->CloneNode(frame_state);
}
copy->ReplaceInput(kFrameStateLocalsInput, new_locals);
copy->ReplaceInput(FrameState::kFrameStateLocalsInput, new_locals);
}
return copy ? copy : frame_state;
return copy != nullptr ? FrameState{copy} : frame_state;
}
bool JSInliningHeuristic::TryReuseDispatch(Node* node, Node* callee,
......@@ -544,14 +543,15 @@ bool JSInliningHeuristic::TryReuseDispatch(Node* node, Node* callee,
Node* checkpoint_state = nullptr;
if (checkpoint) {
checkpoint_state = checkpoint->InputAt(0);
if (!CollectFrameStateUniqueUses(callee, checkpoint_state, replaceable_uses,
&replaceable_uses_count, kMaxUses)) {
if (!CollectFrameStateUniqueUses(callee, FrameState{checkpoint_state},
replaceable_uses, &replaceable_uses_count,
kMaxUses)) {
return false;
}
}
// Collect the uses to check case 3.
Node* frame_state = NodeProperties::GetFrameStateInput(node);
FrameState frame_state{NodeProperties::GetFrameStateInput(node)};
if (!CollectFrameStateUniqueUses(callee, frame_state, replaceable_uses,
&replaceable_uses_count, kMaxUses)) {
return false;
......@@ -588,15 +588,15 @@ bool JSInliningHeuristic::TryReuseDispatch(Node* node, Node* callee,
if (checkpoint) {
// Duplicate the checkpoint.
Node* new_checkpoint_state = DuplicateFrameStateAndRename(
checkpoint_state, callee, target,
FrameState new_checkpoint_state = DuplicateFrameStateAndRename(
FrameState{checkpoint_state}, callee, target,
(i == num_calls - 1) ? kChangeInPlace : kCloneState);
effect = graph()->NewNode(checkpoint->op(), new_checkpoint_state, effect,
control);
}
// Duplicate the call.
Node* new_lazy_frame_state = DuplicateFrameStateAndRename(
FrameState new_lazy_frame_state = DuplicateFrameStateAndRename(
frame_state, callee, target,
(i == num_calls - 1) ? kChangeInPlace : kCloneState);
inputs[0] = target;
......
......@@ -81,8 +81,8 @@ class JSInliningHeuristic final : public AdvancedReducer {
bool TryReuseDispatch(Node* node, Node* callee, Node** if_successes,
Node** calls, Node** inputs, int input_count);
enum StateCloneMode { kCloneState, kChangeInPlace };
Node* DuplicateFrameStateAndRename(Node* frame_state, Node* from, Node* to,
StateCloneMode mode);
FrameState DuplicateFrameStateAndRename(FrameState frame_state, Node* from,
Node* to, StateCloneMode mode);
Node* DuplicateStateValuesAndRename(Node* state_values, Node* from, Node* to,
StateCloneMode mode);
Candidate CollectFunctions(Node* node, int functions_size);
......
......@@ -61,8 +61,8 @@ class JSCallAccessor {
Node* new_target() const { return JSConstructNode{call_}.new_target(); }
Node* frame_state() const {
return NodeProperties::GetFrameStateInput(call_);
FrameState frame_state() const {
return FrameState{NodeProperties::GetFrameStateInput(call_)};
}
int argument_count() const {
......@@ -245,12 +245,10 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context,
}
}
Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state,
int parameter_count,
BytecodeOffset bailout_id,
FrameStateType frame_state_type,
SharedFunctionInfoRef shared,
Node* context) {
FrameState JSInliner::CreateArtificialFrameState(
Node* node, FrameState outer_frame_state, int parameter_count,
BytecodeOffset bailout_id, FrameStateType frame_state_type,
SharedFunctionInfoRef shared, Node* context) {
const int parameter_count_with_receiver =
parameter_count + JSCallOrConstructNode::kReceiverOrNewTargetInputCount;
const FrameStateFunctionInfo* state_info =
......@@ -273,9 +271,9 @@ Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state,
Node* params_node = graph()->NewNode(
op_param, static_cast<int>(params.size()), &params.front());
if (context == nullptr) context = jsgraph()->UndefinedConstant();
return graph()->NewNode(op, params_node, node0, node0, context,
node->InputAt(JSCallOrConstructNode::TargetIndex()),
outer_frame_state);
return FrameState{graph()->NewNode(
op, params_node, node0, node0, context,
node->InputAt(JSCallOrConstructNode::TargetIndex()), outer_frame_state)};
}
namespace {
......@@ -480,9 +478,9 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
// To ensure inlining always terminates, we have an upper limit on inlining
// the nested calls.
int nesting_level = 0;
for (Node* frame_state = call.frame_state();
for (FrameState frame_state = FrameState{call.frame_state()};
frame_state->opcode() == IrOpcode::kFrameState;
frame_state = frame_state->InputAt(kFrameStateOuterStateInput)) {
frame_state = frame_state.outer_frame_state()) {
nesting_level++;
if (nesting_level > kMaxDepthForInlining) {
TRACE("Not inlining "
......@@ -573,7 +571,7 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
}
}
Node* frame_state = call.frame_state();
FrameState frame_state = call.frame_state();
Node* new_target = jsgraph()->UndefinedConstant();
// Inline {JSConstruct} requires some additional magic.
......
......@@ -63,12 +63,10 @@ class JSInliner final : public AdvancedReducer {
base::Optional<SharedFunctionInfoRef> DetermineCallTarget(Node* node);
FeedbackCellRef DetermineCallContext(Node* node, Node** context_out);
Node* CreateArtificialFrameState(Node* node, Node* outer_frame_state,
int parameter_count,
BytecodeOffset bailout_id,
FrameStateType frame_state_type,
SharedFunctionInfoRef shared,
Node* context = nullptr);
FrameState CreateArtificialFrameState(
Node* node, FrameState outer_frame_state, int parameter_count,
BytecodeOffset bailout_id, FrameStateType frame_state_type,
SharedFunctionInfoRef shared, Node* context = nullptr);
Reduction InlineCall(Node* call, Node* new_target, Node* context,
Node* frame_state, Node* start, Node* end,
......
......@@ -7,6 +7,7 @@
#include "src/base/compiler-specific.h"
#include "src/codegen/tnode.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/feedback-source.h"
#include "src/compiler/globals.h"
#include "src/compiler/node-properties.h"
......
......@@ -367,25 +367,6 @@ class Control : public NodeWrapper {
}
};
class FrameState : public NodeWrapper {
public:
explicit constexpr FrameState(Node* node) : NodeWrapper(node) {
// TODO(jgruber): Disallow kStart (needed for PromiseConstructorBasic unit
// test, among others).
SLOW_DCHECK(node->opcode() == IrOpcode::kFrameState ||
node->opcode() == IrOpcode::kStart);
}
// Duplicating here from frame-states.h for ease of access and to keep
// header include-balls small. Equality of the two constants is
// static-asserted elsewhere.
static constexpr int kFrameStateOuterStateInput = 5;
FrameState outer_frame_state() const {
return FrameState{node()->InputAt(kFrameStateOuterStateInput)};
}
};
// Typedefs to shorten commonly used Node containers.
using NodeDeque = ZoneDeque<Node*>;
using NodeSet = ZoneSet<Node*>;
......
......@@ -1224,34 +1224,41 @@ class RepresentationSelector {
}
template <Phase T>
void VisitFrameState(Node* node) {
void VisitFrameState(FrameState node) {
DCHECK_EQ(5, node->op()->ValueInputCount());
DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
DCHECK_EQ(FrameState::kFrameStateInputCount, node->InputCount());
ProcessInput<T>(node, 0, UseInfo::AnyTagged()); // Parameters.
ProcessInput<T>(node, 1, UseInfo::AnyTagged()); // Registers.
ProcessInput<T>(node, FrameState::kFrameStateParametersInput,
UseInfo::AnyTagged());
ProcessInput<T>(node, FrameState::kFrameStateLocalsInput,
UseInfo::AnyTagged());
// Accumulator is a special flower - we need to remember its type in
// a singleton typed-state-values node (as if it was a singleton
// state-values node).
Node* accumulator = node->InputAt(2);
Node* accumulator = node.stack();
if (propagate<T>()) {
// TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
// truncated BigInts.
if (TypeOf(accumulator).Is(Type::BigInt())) {
EnqueueInput<T>(node, 2, UseInfo::AnyTagged());
EnqueueInput<T>(node, FrameState::kFrameStateStackInput,
UseInfo::AnyTagged());
} else {
EnqueueInput<T>(node, 2, UseInfo::Any());
EnqueueInput<T>(node, FrameState::kFrameStateStackInput,
UseInfo::Any());
}
} else if (lower<T>()) {
// TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
// truncated BigInts.
if (TypeOf(accumulator).Is(Type::BigInt())) {
ConvertInput(node, 2, UseInfo::AnyTagged());
ConvertInput(node, FrameState::kFrameStateStackInput,
UseInfo::AnyTagged());
}
Zone* zone = jsgraph_->zone();
if (accumulator == jsgraph_->OptimizedOutConstant()) {
node->ReplaceInput(2, jsgraph_->SingleDeadTypedStateValues());
node->ReplaceInput(FrameState::kFrameStateStackInput,
jsgraph_->SingleDeadTypedStateValues());
} else {
ZoneVector<MachineType>* types =
zone->New<ZoneVector<MachineType>>(1, zone);
......@@ -1259,15 +1266,19 @@ class RepresentationSelector {
TypeOf(accumulator));
node->ReplaceInput(
2, jsgraph_->graph()->NewNode(jsgraph_->common()->TypedStateValues(
types, SparseInputMask::Dense()),
node->InputAt(2)));
FrameState::kFrameStateStackInput,
jsgraph_->graph()->NewNode(jsgraph_->common()->TypedStateValues(
types, SparseInputMask::Dense()),
node.stack()));
}
}
ProcessInput<T>(node, 3, UseInfo::AnyTagged()); // Context.
ProcessInput<T>(node, 4, UseInfo::AnyTagged()); // Closure.
ProcessInput<T>(node, 5, UseInfo::AnyTagged()); // Outer frame state.
ProcessInput<T>(node, FrameState::kFrameStateContextInput,
UseInfo::AnyTagged());
ProcessInput<T>(node, FrameState::kFrameStateFunctionInput,
UseInfo::AnyTagged());
ProcessInput<T>(node, FrameState::kFrameStateOuterStateInput,
UseInfo::AnyTagged());
return SetOutput<T>(node, MachineRepresentation::kTagged);
}
......@@ -3745,7 +3756,7 @@ class RepresentationSelector {
VisitInputs<T>(node);
return SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
case IrOpcode::kFrameState:
return VisitFrameState<T>(node);
return VisitFrameState<T>(FrameState{node});
case IrOpcode::kStateValues:
return VisitStateValues<T>(node);
case IrOpcode::kObjectState:
......
......@@ -11,6 +11,7 @@
#include "src/codegen/machine-type.h"
#include "src/codegen/tnode.h"
#include "src/common/globals.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/feedback-source.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/operator.h"
......
......@@ -536,28 +536,24 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
CHECK_EQ(0, control_count);
CHECK_EQ(0, effect_count);
CHECK_EQ(6, input_count);
// Check that the parameters and registers are kStateValues or
// kTypedStateValues.
for (int i = 0; i < 2; ++i) {
CHECK(NodeProperties::GetValueInput(node, i)->opcode() ==
IrOpcode::kStateValues ||
NodeProperties::GetValueInput(node, i)->opcode() ==
IrOpcode::kTypedStateValues);
}
FrameState state{node};
CHECK(state.parameters()->opcode() == IrOpcode::kStateValues ||
state.parameters()->opcode() == IrOpcode::kTypedStateValues);
CHECK(state.locals()->opcode() == IrOpcode::kStateValues ||
state.locals()->opcode() == IrOpcode::kTypedStateValues);
// Checks that the state input is empty for all but kInterpretedFunction
// frames, where it should have size one.
{
const FrameStateInfo& state_info = FrameStateInfoOf(node->op());
const FrameStateFunctionInfo* func_info = state_info.function_info();
const FrameStateFunctionInfo* func_info =
state.frame_state_info().function_info();
CHECK_EQ(func_info->parameter_count(),
StateValuesAccess(node->InputAt(kFrameStateParametersInput))
.size());
CHECK_EQ(
func_info->local_count(),
StateValuesAccess(node->InputAt(kFrameStateLocalsInput)).size());
StateValuesAccess(state.parameters()).size());
CHECK_EQ(func_info->local_count(),
StateValuesAccess(state.locals()).size());
Node* accumulator = node->InputAt(kFrameStateStackInput);
Node* accumulator = state.stack();
if (func_info->type() == FrameStateType::kInterpretedFunction) {
// The accumulator (InputAt(2)) cannot be kStateValues.
// It can be kTypedStateValues (to signal the type) and it can have
......
......@@ -361,7 +361,7 @@ TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) {
m.common()->FrameState(bailout_id, OutputFrameStateCombine::PokeAt(0),
m.GetFrameStateFunctionInfo(1, 0)),
parameters, locals, stack, context_sentinel, function_node,
m.UndefinedConstant());
m.graph()->start());
// Build the call.
Node* nodes[] = {function_node, receiver, m.UndefinedConstant(),
......@@ -421,7 +421,7 @@ TARGET_TEST_F(InstructionSelectorTest, CallStubWithDeopt) {
OutputFrameStateCombine::PokeAt(0),
m.GetFrameStateFunctionInfo(1, 1)),
parameters, locals, stack, context_sentinel, function_node,
m.UndefinedConstant());
m.graph()->start());
// Build the call.
Node* stub_code = m.HeapConstant(callable.code());
......@@ -512,7 +512,7 @@ TARGET_TEST_F(InstructionSelectorTest, CallStubWithDeoptRecursiveFrameState) {
m.common()->FrameState(bailout_id_parent,
OutputFrameStateCombine::Ignore(),
m.GetFrameStateFunctionInfo(1, 1)),
parameters, locals, stack, context, function_node, m.UndefinedConstant());
parameters, locals, stack, context, function_node, m.graph()->start());
Node* parameters2 = m.AddNode(
m.common()->TypedStateValues(&int32_type, SparseInputMask::Dense()),
......
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