[nci] Add feedback input to more nodes kinds

... and extend JS node wrapper functionality.

Node wrappers now have accessors for value inputs and
context/control/effect/frame-state inputs. Accessors are typed,
although types aren't very meaningful so far (in current examples we
only distinguish between Object/HeapObject).

The following node kinds now take an additional feedback vector input,
and use the new node wrapper functionality above:

- CloneObject
- CreateLiteralArray
- CreateLiteralObject
- CreateLiteralRegExp
- GetIterator
- GetTemplateObject
- HasProperty
- LoadProperty
- StoreProperty

Bug: v8:8888
Change-Id: I1eb33c078b11725a72ec983bbaa848b9a3c7b0d9
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2259936
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68538}
This commit is contained in:
Jakob Gruber 2020-06-25 14:10:24 +02:00 committed by Commit Bot
parent bc8efc9a2c
commit 5d417c0d49
11 changed files with 401 additions and 156 deletions

View File

@ -1954,7 +1954,10 @@ void BytecodeGraphBuilder::VisitLdaKeyedProperty() {
node = lowering.value(); node = lowering.value();
} else { } else {
DCHECK(!lowering.Changed()); DCHECK(!lowering.Changed());
node = NewNode(op, object, key); STATIC_ASSERT(JSLoadPropertyNode::ObjectIndex() == 0);
STATIC_ASSERT(JSLoadPropertyNode::KeyIndex() == 1);
STATIC_ASSERT(JSLoadPropertyNode::FeedbackVectorIndex() == 2);
node = NewNode(op, object, key, feedback_vector_node());
} }
environment()->BindAccumulator(node, Environment::kAttachFrameState); environment()->BindAccumulator(node, Environment::kAttachFrameState);
} }
@ -2041,7 +2044,11 @@ void BytecodeGraphBuilder::VisitStaKeyedProperty() {
node = lowering.value(); node = lowering.value();
} else { } else {
DCHECK(!lowering.Changed()); DCHECK(!lowering.Changed());
node = NewNode(op, object, key, value); STATIC_ASSERT(JSStorePropertyNode::ObjectIndex() == 0);
STATIC_ASSERT(JSStorePropertyNode::KeyIndex() == 1);
STATIC_ASSERT(JSStorePropertyNode::ValueIndex() == 2);
STATIC_ASSERT(JSStorePropertyNode::FeedbackVectorIndex() == 3);
node = NewNode(op, object, key, value, feedback_vector_node());
} }
environment()->RecordAfterState(node, Environment::kAttachFrameState); environment()->RecordAfterState(node, Environment::kAttachFrameState);
@ -2177,8 +2184,10 @@ void BytecodeGraphBuilder::VisitCreateRegExpLiteral() {
int const slot_id = bytecode_iterator().GetIndexOperand(1); int const slot_id = bytecode_iterator().GetIndexOperand(1);
FeedbackSource pair = CreateFeedbackSource(slot_id); FeedbackSource pair = CreateFeedbackSource(slot_id);
int literal_flags = bytecode_iterator().GetFlagOperand(2); int literal_flags = bytecode_iterator().GetFlagOperand(2);
STATIC_ASSERT(JSCreateLiteralRegExpNode::FeedbackVectorIndex() == 0);
Node* literal = NewNode(javascript()->CreateLiteralRegExp( Node* literal = NewNode(javascript()->CreateLiteralRegExp(
constant_pattern.object(), pair, literal_flags)); constant_pattern.object(), pair, literal_flags),
feedback_vector_node());
environment()->BindAccumulator(literal, Environment::kAttachFrameState); environment()->BindAccumulator(literal, Environment::kAttachFrameState);
} }
@ -2197,9 +2206,11 @@ void BytecodeGraphBuilder::VisitCreateArrayLiteral() {
literal_flags |= ArrayLiteral::kDisableMementos; literal_flags |= ArrayLiteral::kDisableMementos;
int number_of_elements = int number_of_elements =
array_boilerplate_description.constants_elements_length(); array_boilerplate_description.constants_elements_length();
Node* literal = NewNode(javascript()->CreateLiteralArray( STATIC_ASSERT(JSCreateLiteralArrayNode::FeedbackVectorIndex() == 0);
array_boilerplate_description.object(), pair, literal_flags, Node* literal = NewNode(
number_of_elements)); javascript()->CreateLiteralArray(array_boilerplate_description.object(),
pair, literal_flags, number_of_elements),
feedback_vector_node());
environment()->BindAccumulator(literal, Environment::kAttachFrameState); environment()->BindAccumulator(literal, Environment::kAttachFrameState);
} }
@ -2225,8 +2236,11 @@ void BytecodeGraphBuilder::VisitCreateObjectLiteral() {
int literal_flags = int literal_flags =
interpreter::CreateObjectLiteralFlags::FlagsBits::decode(bytecode_flags); interpreter::CreateObjectLiteralFlags::FlagsBits::decode(bytecode_flags);
int number_of_properties = constant_properties.size(); int number_of_properties = constant_properties.size();
Node* literal = NewNode(javascript()->CreateLiteralObject( STATIC_ASSERT(JSCreateLiteralObjectNode::FeedbackVectorIndex() == 0);
constant_properties.object(), pair, literal_flags, number_of_properties)); Node* literal = NewNode(
javascript()->CreateLiteralObject(constant_properties.object(), pair,
literal_flags, number_of_properties),
feedback_vector_node());
environment()->BindAccumulator(literal, Environment::kAttachFrameState); environment()->BindAccumulator(literal, Environment::kAttachFrameState);
} }
@ -2243,7 +2257,9 @@ void BytecodeGraphBuilder::VisitCloneObject() {
int slot = bytecode_iterator().GetIndexOperand(2); int slot = bytecode_iterator().GetIndexOperand(2);
const Operator* op = const Operator* op =
javascript()->CloneObject(CreateFeedbackSource(slot), flags); javascript()->CloneObject(CreateFeedbackSource(slot), flags);
Node* value = NewNode(op, source); STATIC_ASSERT(JSCloneObjectNode::SourceIndex() == 0);
STATIC_ASSERT(JSCloneObjectNode::FeedbackVectorIndex() == 1);
Node* value = NewNode(op, source, feedback_vector_node());
environment()->BindAccumulator(value, Environment::kAttachFrameState); environment()->BindAccumulator(value, Environment::kAttachFrameState);
} }
@ -2253,8 +2269,11 @@ void BytecodeGraphBuilder::VisitGetTemplateObject() {
CreateFeedbackSource(bytecode_iterator().GetIndexOperand(1)); CreateFeedbackSource(bytecode_iterator().GetIndexOperand(1));
TemplateObjectDescriptionRef description( TemplateObjectDescriptionRef description(
broker(), bytecode_iterator().GetConstantForIndexOperand(0, isolate())); broker(), bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
Node* template_object = NewNode(javascript()->GetTemplateObject( STATIC_ASSERT(JSGetTemplateObjectNode::FeedbackVectorIndex() == 0);
description.object(), shared_info().object(), source)); Node* template_object =
NewNode(javascript()->GetTemplateObject(description.object(),
shared_info().object(), source),
feedback_vector_node());
environment()->BindAccumulator(template_object); environment()->BindAccumulator(template_object);
} }
@ -3173,7 +3192,11 @@ void BytecodeGraphBuilder::VisitTestIn() {
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
FeedbackSource feedback = FeedbackSource feedback =
CreateFeedbackSource(bytecode_iterator().GetIndexOperand(1)); CreateFeedbackSource(bytecode_iterator().GetIndexOperand(1));
Node* node = NewNode(javascript()->HasProperty(feedback), object, key); STATIC_ASSERT(JSHasPropertyNode::ObjectIndex() == 0);
STATIC_ASSERT(JSHasPropertyNode::KeyIndex() == 1);
STATIC_ASSERT(JSHasPropertyNode::FeedbackVectorIndex() == 2);
Node* node = NewNode(javascript()->HasProperty(feedback), object, key,
feedback_vector_node());
environment()->BindAccumulator(node, Environment::kAttachFrameState); environment()->BindAccumulator(node, Environment::kAttachFrameState);
} }
@ -3548,7 +3571,9 @@ void BytecodeGraphBuilder::VisitGetIterator() {
if (lowering.IsExit()) return; if (lowering.IsExit()) return;
DCHECK(!lowering.Changed()); DCHECK(!lowering.Changed());
Node* iterator = NewNode(op, receiver); STATIC_ASSERT(JSGetIteratorNode::ReceiverIndex() == 0);
STATIC_ASSERT(JSGetIteratorNode::FeedbackVectorIndex() == 1);
Node* iterator = NewNode(op, receiver, feedback_vector_node());
environment()->BindAccumulator(iterator, Environment::kAttachFrameState); environment()->BindAccumulator(iterator, Environment::kAttachFrameState);
} }

View File

@ -16,6 +16,11 @@ namespace v8 {
namespace internal { namespace internal {
namespace compiler { 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) { size_t hash_value(OutputFrameStateCombine const& sc) {
return base::hash_value(sc.parameter_); return base::hash_value(sc.parameter_);
} }

View File

@ -140,13 +140,13 @@ size_t hash_value(FrameStateInfo const&);
std::ostream& operator<<(std::ostream&, FrameStateInfo const&); std::ostream& operator<<(std::ostream&, FrameStateInfo const&);
static const int kFrameStateParametersInput = 0; static constexpr int kFrameStateParametersInput = 0;
static const int kFrameStateLocalsInput = 1; static constexpr int kFrameStateLocalsInput = 1;
static const int kFrameStateStackInput = 2; static constexpr int kFrameStateStackInput = 2;
static const int kFrameStateContextInput = 3; static constexpr int kFrameStateContextInput = 3;
static const int kFrameStateFunctionInput = 4; static constexpr int kFrameStateFunctionInput = 4;
static const int kFrameStateOuterStateInput = 5; static constexpr int kFrameStateOuterStateInput = 5;
static const int kFrameStateInputCount = kFrameStateOuterStateInput + 1; static constexpr int kFrameStateInputCount = kFrameStateOuterStateInput + 1;
enum class ContinuationFrameStateMode { EAGER, LAZY, LAZY_WITH_CATCH }; enum class ContinuationFrameStateMode { EAGER, LAZY, LAZY_WITH_CATCH };

View File

@ -130,37 +130,6 @@ class BasicBlock;
class GraphAssembler; class GraphAssembler;
// Wrapper classes for special node/edge types (effect, control, frame states)
// that otherwise don't fit into the type system.
class Effect : public NodeWrapper {
public:
explicit constexpr Effect(Node* node) : NodeWrapper(node) {
// TODO(jgruber): Remove the End special case.
SLOW_DCHECK(node == nullptr || node->op()->opcode() == IrOpcode::kEnd ||
node->op()->EffectOutputCount() > 0);
}
};
class Control : public NodeWrapper {
public:
explicit constexpr Control(Node* node) : NodeWrapper(node) {
// TODO(jgruber): Remove the End special case.
SLOW_DCHECK(node == nullptr || node->opcode() == IrOpcode::kEnd ||
node->op()->ControlOutputCount() > 0);
}
};
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);
}
};
enum class GraphAssemblerLabelType { kDeferred, kNonDeferred, kLoop }; enum class GraphAssemblerLabelType { kDeferred, kNonDeferred, kLoop };
// Label with statically known count of incoming branches and phis. // Label with statically known count of incoming branches and phis.

View File

@ -3089,9 +3089,9 @@ Reduction JSCallReducer::ReduceReflectHas(Node* node) {
Node* vtrue; Node* vtrue;
{ {
// TODO(magardn): collect feedback so this can be optimized // TODO(magardn): collect feedback so this can be optimized
vtrue = etrue = if_true = vtrue = etrue = if_true = graph()->NewNode(
graph()->NewNode(javascript()->HasProperty(FeedbackSource()), target, javascript()->HasProperty(FeedbackSource()), target, key,
key, context, frame_state, etrue, if_true); jsgraph()->UndefinedConstant(), context, frame_state, etrue, if_true);
} }
// Rewire potential exception edges. // Rewire potential exception edges.

View File

@ -1088,9 +1088,10 @@ Reduction JSCreateLowering::ReduceJSCreatePromise(Node* node) {
Reduction JSCreateLowering::ReduceJSCreateLiteralArrayOrObject(Node* node) { Reduction JSCreateLowering::ReduceJSCreateLiteralArrayOrObject(Node* node) {
DCHECK(node->opcode() == IrOpcode::kJSCreateLiteralArray || DCHECK(node->opcode() == IrOpcode::kJSCreateLiteralArray ||
node->opcode() == IrOpcode::kJSCreateLiteralObject); node->opcode() == IrOpcode::kJSCreateLiteralObject);
CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); JSCreateLiteralOpNode n(node);
Node* effect = NodeProperties::GetEffectInput(node); CreateLiteralParameters const& p = n.Parameters();
Node* control = NodeProperties::GetControlInput(node); Effect effect = n.effect();
Control control = n.control();
ProcessedFeedback const& feedback = ProcessedFeedback const& feedback =
broker()->GetFeedbackForArrayOrObjectLiteral(p.feedback()); broker()->GetFeedbackForArrayOrObjectLiteral(p.feedback());
if (!feedback.IsInsufficient()) { if (!feedback.IsInsufficient()) {
@ -1168,10 +1169,10 @@ Reduction JSCreateLowering::ReduceJSCreateEmptyLiteralObject(Node* node) {
} }
Reduction JSCreateLowering::ReduceJSCreateLiteralRegExp(Node* node) { Reduction JSCreateLowering::ReduceJSCreateLiteralRegExp(Node* node) {
DCHECK_EQ(IrOpcode::kJSCreateLiteralRegExp, node->opcode()); JSCreateLiteralRegExpNode n(node);
CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); CreateLiteralParameters const& p = n.Parameters();
Node* effect = NodeProperties::GetEffectInput(node); Effect effect = n.effect();
Node* control = NodeProperties::GetControlInput(node); Control control = n.control();
ProcessedFeedback const& feedback = ProcessedFeedback const& feedback =
broker()->GetFeedbackForRegExpLiteral(p.feedback()); broker()->GetFeedbackForRegExpLiteral(p.feedback());
if (!feedback.IsInsufficient()) { if (!feedback.IsInsufficient()) {
@ -1184,9 +1185,8 @@ Reduction JSCreateLowering::ReduceJSCreateLiteralRegExp(Node* node) {
} }
Reduction JSCreateLowering::ReduceJSGetTemplateObject(Node* node) { Reduction JSCreateLowering::ReduceJSGetTemplateObject(Node* node) {
DCHECK_EQ(IrOpcode::kJSGetTemplateObject, node->opcode()); JSGetTemplateObjectNode n(node);
GetTemplateObjectParameters const& parameters = GetTemplateObjectParameters const& parameters = n.Parameters();
GetTemplateObjectParametersOf(node->op());
SharedFunctionInfoRef shared(broker(), parameters.shared()); SharedFunctionInfoRef shared(broker(), parameters.shared());
JSArrayRef template_object = shared.GetTemplateObject( JSArrayRef template_object = shared.GetTemplateObject(
TemplateObjectDescriptionRef(broker(), parameters.description()), TemplateObjectDescriptionRef(broker(), parameters.description()),

View File

@ -60,7 +60,6 @@ Reduction JSGenericLowering::Reduce(Node* node) {
void JSGenericLowering::LowerJS##Name(Node* node) { \ void JSGenericLowering::LowerJS##Name(Node* node) { \
ReplaceWithBuiltinCall(node, Builtins::k##Name); \ ReplaceWithBuiltinCall(node, Builtins::k##Name); \
} }
REPLACE_STUB_CALL(HasProperty)
REPLACE_STUB_CALL(ToLength) REPLACE_STUB_CALL(ToLength)
REPLACE_STUB_CALL(ToNumber) REPLACE_STUB_CALL(ToNumber)
REPLACE_STUB_CALL(ToNumberConvertBigInt) REPLACE_STUB_CALL(ToNumberConvertBigInt)
@ -208,6 +207,7 @@ DEF_BINARY_LOWERING(LessThanOrEqual)
void JSGenericLowering::LowerJSStrictEqual(Node* node) { void JSGenericLowering::LowerJSStrictEqual(Node* node) {
// The === operator doesn't need the current context. // The === operator doesn't need the current context.
NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant()); NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
DCHECK_EQ(node->op()->ControlInputCount(), 1);
node->RemoveInput(NodeProperties::FirstControlIndex(node)); node->RemoveInput(NodeProperties::FirstControlIndex(node));
Builtins::Name builtin_id; Builtins::Name builtin_id;
@ -246,20 +246,29 @@ bool ShouldUseMegamorphicLoadBuiltin(FeedbackSource const& source,
} }
} // namespace } // namespace
void JSGenericLowering::LowerJSHasProperty(Node* node) {
// TODO(jgruber,v8:8888): Collect feedback.
node->RemoveInput(JSHasPropertyNode::FeedbackVectorIndex());
ReplaceWithBuiltinCall(node, Builtins::kHasProperty);
}
void JSGenericLowering::LowerJSLoadProperty(Node* node) { void JSGenericLowering::LowerJSLoadProperty(Node* node) {
const PropertyAccess& p = PropertyAccessOf(node->op()); JSLoadPropertyNode n(node);
Node* frame_state = NodeProperties::GetFrameStateInput(node); const PropertyAccess& p = n.Parameters();
Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput); FrameState frame_state = n.frame_state();
node->InsertInput(zone(), 2, FrameState outer_state = frame_state.outer_frame_state();
jsgraph()->TaggedIndexConstant(p.feedback().index())); STATIC_ASSERT(n.FeedbackVectorIndex() == 2);
if (outer_state->opcode() != IrOpcode::kFrameState) { if (outer_state->opcode() != IrOpcode::kFrameState) {
n->RemoveInput(n.FeedbackVectorIndex());
n->InsertInput(zone(), 2,
jsgraph()->TaggedIndexConstant(p.feedback().index()));
ReplaceWithBuiltinCall( ReplaceWithBuiltinCall(
node, ShouldUseMegamorphicLoadBuiltin(p.feedback(), broker()) node, ShouldUseMegamorphicLoadBuiltin(p.feedback(), broker())
? Builtins::kKeyedLoadICTrampoline_Megamorphic ? Builtins::kKeyedLoadICTrampoline_Megamorphic
: Builtins::kKeyedLoadICTrampoline); : Builtins::kKeyedLoadICTrampoline);
} else { } else {
Node* vector = jsgraph()->HeapConstant(p.feedback().vector); n->InsertInput(zone(), 2,
node->InsertInput(zone(), 3, vector); jsgraph()->TaggedIndexConstant(p.feedback().index()));
ReplaceWithBuiltinCall( ReplaceWithBuiltinCall(
node, ShouldUseMegamorphicLoadBuiltin(p.feedback(), broker()) node, ShouldUseMegamorphicLoadBuiltin(p.feedback(), broker())
? Builtins::kKeyedLoadIC_Megamorphic ? Builtins::kKeyedLoadIC_Megamorphic
@ -324,30 +333,33 @@ void JSGenericLowering::LowerJSGetIterator(Node* node) {
// instead of 2 calls resulting from the generic lowering of the LoadNamed // instead of 2 calls resulting from the generic lowering of the LoadNamed
// and Call operators. // and Call operators.
GetIteratorParameters const& p = GetIteratorParametersOf(node->op()); JSGetIteratorNode n(node);
GetIteratorParameters const& p = n.Parameters();
Node* load_slot = Node* load_slot =
jsgraph()->TaggedIndexConstant(p.loadFeedback().slot.ToInt()); jsgraph()->TaggedIndexConstant(p.loadFeedback().slot.ToInt());
Node* call_slot = Node* call_slot =
jsgraph()->TaggedIndexConstant(p.callFeedback().slot.ToInt()); jsgraph()->TaggedIndexConstant(p.callFeedback().slot.ToInt());
Node* feedback = jsgraph()->HeapConstant(p.callFeedback().vector); STATIC_ASSERT(n.FeedbackVectorIndex() == 1);
node->InsertInput(zone(), 1, load_slot); node->InsertInput(zone(), 1, load_slot);
node->InsertInput(zone(), 2, call_slot); node->InsertInput(zone(), 2, call_slot);
node->InsertInput(zone(), 3, feedback);
ReplaceWithBuiltinCall(node, Builtins::kGetIteratorWithFeedback); ReplaceWithBuiltinCall(node, Builtins::kGetIteratorWithFeedback);
} }
void JSGenericLowering::LowerJSStoreProperty(Node* node) { void JSGenericLowering::LowerJSStoreProperty(Node* node) {
PropertyAccess const& p = PropertyAccessOf(node->op()); JSStorePropertyNode n(node);
Node* frame_state = NodeProperties::GetFrameStateInput(node); const PropertyAccess& p = n.Parameters();
Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput); FrameState frame_state = n.frame_state();
node->InsertInput(zone(), 3, FrameState outer_state = frame_state.outer_frame_state();
jsgraph()->TaggedIndexConstant(p.feedback().index())); STATIC_ASSERT(n.FeedbackVectorIndex() == 3);
if (outer_state->opcode() != IrOpcode::kFrameState) { if (outer_state->opcode() != IrOpcode::kFrameState) {
n->RemoveInput(n.FeedbackVectorIndex());
node->InsertInput(zone(), 3,
jsgraph()->TaggedIndexConstant(p.feedback().index()));
ReplaceWithBuiltinCall(node, Builtins::kKeyedStoreICTrampoline); ReplaceWithBuiltinCall(node, Builtins::kKeyedStoreICTrampoline);
} else { } else {
Node* vector = jsgraph()->HeapConstant(p.feedback().vector); node->InsertInput(zone(), 3,
node->InsertInput(zone(), 4, vector); jsgraph()->TaggedIndexConstant(p.feedback().index()));
ReplaceWithBuiltinCall(node, Builtins::kKeyedStoreIC); ReplaceWithBuiltinCall(node, Builtins::kKeyedStoreIC);
} }
} }
@ -595,13 +607,14 @@ void JSGenericLowering::LowerJSCreateTypedArray(Node* node) {
} }
void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) { void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) {
CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); JSCreateLiteralArrayNode n(node);
node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector)); CreateLiteralParameters const& p = n.Parameters();
STATIC_ASSERT(n.FeedbackVectorIndex() == 0);
node->InsertInput(zone(), 1, node->InsertInput(zone(), 1,
jsgraph()->TaggedIndexConstant(p.feedback().index())); jsgraph()->TaggedIndexConstant(p.feedback().index()));
node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant())); node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
// Use the CreateShallowArrayLiteratlr builtin only for shallow boilerplates // Use the CreateShallowArrayLiteral builtin only for shallow boilerplates
// without properties up to the number of elements that the stubs can handle. // without properties up to the number of elements that the stubs can handle.
if ((p.flags() & AggregateLiteral::kIsShallow) != 0 && if ((p.flags() & AggregateLiteral::kIsShallow) != 0 &&
p.length() < ConstructorBuiltins::kMaximumClonedShallowArrayElements) { p.length() < ConstructorBuiltins::kMaximumClonedShallowArrayElements) {
@ -613,17 +626,19 @@ void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) {
} }
void JSGenericLowering::LowerJSGetTemplateObject(Node* node) { void JSGenericLowering::LowerJSGetTemplateObject(Node* node) {
GetTemplateObjectParameters const& p = JSGetTemplateObjectNode n(node);
GetTemplateObjectParametersOf(node->op()); GetTemplateObjectParameters const& p = n.Parameters();
SharedFunctionInfoRef shared(broker(), p.shared()); SharedFunctionInfoRef shared(broker(), p.shared());
TemplateObjectDescriptionRef description(broker(), p.description()); TemplateObjectDescriptionRef description(broker(), p.description());
DCHECK_EQ(node->op()->ControlInputCount(), 1);
node->RemoveInput(NodeProperties::FirstControlIndex(node));
STATIC_ASSERT(JSGetTemplateObjectNode::FeedbackVectorIndex() == 0);
node->InsertInput(zone(), 0, jsgraph()->Constant(shared)); node->InsertInput(zone(), 0, jsgraph()->Constant(shared));
node->InsertInput(zone(), 1, jsgraph()->Constant(description)); node->InsertInput(zone(), 1, jsgraph()->Constant(description));
node->InsertInput(zone(), 2, node->InsertInput(zone(), 2,
jsgraph()->UintPtrConstant(p.feedback().index())); jsgraph()->UintPtrConstant(p.feedback().index()));
node->InsertInput(zone(), 3, jsgraph()->HeapConstant(p.feedback().vector));
node->RemoveInput(6); // control
ReplaceWithBuiltinCall(node, Builtins::kGetTemplateObject); ReplaceWithBuiltinCall(node, Builtins::kGetTemplateObject);
} }
@ -642,8 +657,9 @@ void JSGenericLowering::LowerJSCreateArrayFromIterable(Node* node) {
} }
void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) { void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) {
CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); JSCreateLiteralObjectNode n(node);
node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector)); CreateLiteralParameters const& p = n.Parameters();
STATIC_ASSERT(n.FeedbackVectorIndex() == 0);
node->InsertInput(zone(), 1, node->InsertInput(zone(), 1,
jsgraph()->TaggedIndexConstant(p.feedback().index())); jsgraph()->TaggedIndexConstant(p.feedback().index()));
node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant())); node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
@ -661,11 +677,12 @@ void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) {
} }
void JSGenericLowering::LowerJSCloneObject(Node* node) { void JSGenericLowering::LowerJSCloneObject(Node* node) {
CloneObjectParameters const& p = CloneObjectParametersOf(node->op()); JSCloneObjectNode n(node);
CloneObjectParameters const& p = n.Parameters();
STATIC_ASSERT(n.FeedbackVectorIndex() == 1);
node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.flags())); node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.flags()));
node->InsertInput(zone(), 2, node->InsertInput(zone(), 2,
jsgraph()->TaggedIndexConstant(p.feedback().index())); jsgraph()->TaggedIndexConstant(p.feedback().index()));
node->InsertInput(zone(), 3, jsgraph()->HeapConstant(p.feedback().vector));
ReplaceWithBuiltinCall(node, Builtins::kCloneObjectIC); ReplaceWithBuiltinCall(node, Builtins::kCloneObjectIC);
} }
@ -674,8 +691,9 @@ void JSGenericLowering::LowerJSCreateEmptyLiteralObject(Node* node) {
} }
void JSGenericLowering::LowerJSCreateLiteralRegExp(Node* node) { void JSGenericLowering::LowerJSCreateLiteralRegExp(Node* node) {
CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); JSCreateLiteralRegExpNode n(node);
node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector)); CreateLiteralParameters const& p = n.Parameters();
STATIC_ASSERT(n.FeedbackVectorIndex() == 0);
node->InsertInput(zone(), 1, node->InsertInput(zone(), 1,
jsgraph()->TaggedIndexConstant(p.feedback().index())); jsgraph()->TaggedIndexConstant(p.feedback().index()));
node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant())); node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));

View File

@ -1358,14 +1358,14 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
} }
Reduction JSNativeContextSpecialization::ReduceJSGetIterator(Node* node) { Reduction JSNativeContextSpecialization::ReduceJSGetIterator(Node* node) {
DCHECK_EQ(IrOpcode::kJSGetIterator, node->opcode()); JSGetIteratorNode n(node);
GetIteratorParameters const& p = GetIteratorParametersOf(node->op()); GetIteratorParameters const& p = n.Parameters();
Node* receiver = NodeProperties::GetValueInput(node, 0); TNode<Object> receiver = n.receiver();
Node* context = NodeProperties::GetContextInput(node); TNode<Object> context = n.context();
Node* frame_state = NodeProperties::GetFrameStateInput(node); FrameState frame_state = n.frame_state();
Node* effect = NodeProperties::GetEffectInput(node); Effect effect = n.effect();
Node* control = NodeProperties::GetControlInput(node); Control control = n.control();
// Load iterator property operator // Load iterator property operator
Handle<Name> iterator_symbol = factory()->iterator_symbol(); Handle<Name> iterator_symbol = factory()->iterator_symbol();
@ -1895,13 +1895,11 @@ Reduction JSNativeContextSpecialization::ReduceSoftDeoptimize(
} }
Reduction JSNativeContextSpecialization::ReduceJSHasProperty(Node* node) { Reduction JSNativeContextSpecialization::ReduceJSHasProperty(Node* node) {
DCHECK_EQ(IrOpcode::kJSHasProperty, node->opcode()); JSHasPropertyNode n(node);
PropertyAccess const& p = PropertyAccessOf(node->op()); PropertyAccess const& p = n.Parameters();
Node* key = NodeProperties::GetValueInput(node, 1);
Node* value = jsgraph()->Dead(); Node* value = jsgraph()->Dead();
if (!p.feedback().IsValid()) return NoChange(); if (!p.feedback().IsValid()) return NoChange();
return ReducePropertyAccess(node, key, base::nullopt, value, return ReducePropertyAccess(node, n.key(), base::nullopt, value,
FeedbackSource(p.feedback()), AccessMode::kHas); FeedbackSource(p.feedback()), AccessMode::kHas);
} }
@ -2012,9 +2010,9 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadPropertyWithEnumeratedKey(
} }
Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) { Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadProperty, node->opcode()); JSLoadPropertyNode n(node);
PropertyAccess const& p = PropertyAccessOf(node->op()); PropertyAccess const& p = n.Parameters();
Node* name = NodeProperties::GetValueInput(node, 1); Node* name = n.key();
if (name->opcode() == IrOpcode::kJSForInNext) { if (name->opcode() == IrOpcode::kJSForInNext) {
Reduction reduction = ReduceJSLoadPropertyWithEnumeratedKey(node); Reduction reduction = ReduceJSLoadPropertyWithEnumeratedKey(node);
@ -2028,13 +2026,10 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) {
} }
Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) { Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) {
DCHECK_EQ(IrOpcode::kJSStoreProperty, node->opcode()); JSStorePropertyNode n(node);
PropertyAccess const& p = PropertyAccessOf(node->op()); PropertyAccess const& p = n.Parameters();
Node* const key = NodeProperties::GetValueInput(node, 1);
Node* const value = NodeProperties::GetValueInput(node, 2);
if (!p.feedback().IsValid()) return NoChange(); if (!p.feedback().IsValid()) return NoChange();
return ReducePropertyAccess(node, key, base::nullopt, value, return ReducePropertyAccess(node, n.key(), base::nullopt, n.value(),
FeedbackSource(p.feedback()), AccessMode::kStore); FeedbackSource(p.feedback()), AccessMode::kStore);
} }

View File

@ -890,7 +890,7 @@ const Operator* JSOperatorBuilder::LoadProperty(
return new (zone()) Operator1<PropertyAccess>( // -- return new (zone()) Operator1<PropertyAccess>( // --
IrOpcode::kJSLoadProperty, Operator::kNoProperties, // opcode IrOpcode::kJSLoadProperty, Operator::kNoProperties, // opcode
"JSLoadProperty", // name "JSLoadProperty", // name
2, 1, 1, 1, 1, 2, // counts 3, 1, 1, 1, 1, 2, // counts
access); // parameter access); // parameter
} }
@ -900,7 +900,7 @@ const Operator* JSOperatorBuilder::GetIterator(
return new (zone()) Operator1<GetIteratorParameters>( // -- return new (zone()) Operator1<GetIteratorParameters>( // --
IrOpcode::kJSGetIterator, Operator::kNoProperties, // opcode IrOpcode::kJSGetIterator, Operator::kNoProperties, // opcode
"JSGetIterator", // name "JSGetIterator", // name
1, 1, 1, 1, 1, 2, // counts 2, 1, 1, 1, 1, 2, // counts
access); // parameter access); // parameter
} }
@ -909,7 +909,7 @@ const Operator* JSOperatorBuilder::HasProperty(FeedbackSource const& feedback) {
return new (zone()) Operator1<PropertyAccess>( // -- return new (zone()) Operator1<PropertyAccess>( // --
IrOpcode::kJSHasProperty, Operator::kNoProperties, // opcode IrOpcode::kJSHasProperty, Operator::kNoProperties, // opcode
"JSHasProperty", // name "JSHasProperty", // name
2, 1, 1, 1, 1, 2, // counts 3, 1, 1, 1, 1, 2, // counts
access); // parameter access); // parameter
} }
@ -987,7 +987,7 @@ const Operator* JSOperatorBuilder::StoreProperty(
return new (zone()) Operator1<PropertyAccess>( // -- return new (zone()) Operator1<PropertyAccess>( // --
IrOpcode::kJSStoreProperty, Operator::kNoProperties, // opcode IrOpcode::kJSStoreProperty, Operator::kNoProperties, // opcode
"JSStoreProperty", // name "JSStoreProperty", // name
3, 1, 1, 0, 1, 2, // counts 4, 1, 1, 0, 1, 2, // counts
access); // parameter access); // parameter
} }
@ -1167,7 +1167,7 @@ const Operator* JSOperatorBuilder::CreateLiteralArray(
IrOpcode::kJSCreateLiteralArray, // opcode IrOpcode::kJSCreateLiteralArray, // opcode
Operator::kNoProperties, // properties Operator::kNoProperties, // properties
"JSCreateLiteralArray", // name "JSCreateLiteralArray", // name
0, 1, 1, 1, 1, 2, // counts 1, 1, 1, 1, 1, 2, // counts
parameters); // parameter parameters); // parameter
} }
@ -1200,7 +1200,7 @@ const Operator* JSOperatorBuilder::CreateLiteralObject(
IrOpcode::kJSCreateLiteralObject, // opcode IrOpcode::kJSCreateLiteralObject, // opcode
Operator::kNoProperties, // properties Operator::kNoProperties, // properties
"JSCreateLiteralObject", // name "JSCreateLiteralObject", // name
0, 1, 1, 1, 1, 2, // counts 1, 1, 1, 1, 1, 2, // counts
parameters); // parameter parameters); // parameter
} }
@ -1212,7 +1212,7 @@ const Operator* JSOperatorBuilder::GetTemplateObject(
IrOpcode::kJSGetTemplateObject, // opcode IrOpcode::kJSGetTemplateObject, // opcode
Operator::kEliminatable, // properties Operator::kEliminatable, // properties
"JSGetTemplateObject", // name "JSGetTemplateObject", // name
0, 1, 1, 1, 1, 0, // counts 1, 1, 1, 1, 1, 0, // counts
parameters); // parameter parameters); // parameter
} }
@ -1223,7 +1223,7 @@ const Operator* JSOperatorBuilder::CloneObject(FeedbackSource const& feedback,
IrOpcode::kJSCloneObject, // opcode IrOpcode::kJSCloneObject, // opcode
Operator::kNoProperties, // properties Operator::kNoProperties, // properties
"JSCloneObject", // name "JSCloneObject", // name
1, 1, 1, 1, 1, 2, // counts 2, 1, 1, 1, 1, 2, // counts
parameters); // parameter parameters); // parameter
} }
@ -1253,7 +1253,7 @@ const Operator* JSOperatorBuilder::CreateLiteralRegExp(
IrOpcode::kJSCreateLiteralRegExp, // opcode IrOpcode::kJSCreateLiteralRegExp, // opcode
Operator::kNoProperties, // properties Operator::kNoProperties, // properties
"JSCreateLiteralRegExp", // name "JSCreateLiteralRegExp", // name
0, 1, 1, 1, 1, 2, // counts 1, 1, 1, 1, 1, 2, // counts
parameters); // parameter parameters); // parameter
} }

View File

@ -6,8 +6,10 @@
#define V8_COMPILER_JS_OPERATOR_H_ #define V8_COMPILER_JS_OPERATOR_H_
#include "src/base/compiler-specific.h" #include "src/base/compiler-specific.h"
#include "src/codegen/tnode.h"
#include "src/compiler/feedback-source.h" #include "src/compiler/feedback-source.h"
#include "src/compiler/globals.h" #include "src/compiler/globals.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/node.h" #include "src/compiler/node.h"
#include "src/compiler/opcodes.h" #include "src/compiler/opcodes.h"
#include "src/handles/maybe-handles.h" #include "src/handles/maybe-handles.h"
@ -69,37 +71,6 @@ class JSOperator final : public AllStatic {
} }
}; };
// Node wrappers.
class JSUnaryOpNode final : public NodeWrapper {
public:
explicit constexpr JSUnaryOpNode(Node* node) : NodeWrapper(node) {
CONSTEXPR_DCHECK(JSOperator::IsUnaryWithFeedback(node->opcode()));
}
static constexpr int ValueIndex() { return 0; }
static constexpr int FeedbackVectorIndex() { return 1; }
};
#define V(JSName, ...) using JSName##Node = JSUnaryOpNode;
JS_UNOP_WITH_FEEDBACK(V)
#undef V
class JSBinaryOpNode final : public NodeWrapper {
public:
explicit constexpr JSBinaryOpNode(Node* node) : NodeWrapper(node) {
CONSTEXPR_DCHECK(JSOperator::IsBinaryWithFeedback(node->opcode()));
}
static constexpr int LeftIndex() { return 0; }
static constexpr int RightIndex() { return 1; }
static constexpr int FeedbackVectorIndex() { return 2; }
};
#define V(JSName, ...) using JSName##Node = JSBinaryOpNode;
JS_BINOP_WITH_FEEDBACK(V)
#undef V
// Defines the frequency a given Call/Construct site was executed. For some // Defines the frequency a given Call/Construct site was executed. For some
// call sites the frequency is not known. // call sites the frequency is not known.
class CallFrequency final { class CallFrequency final {
@ -1043,6 +1014,208 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
DISALLOW_COPY_AND_ASSIGN(JSOperatorBuilder); DISALLOW_COPY_AND_ASSIGN(JSOperatorBuilder);
}; };
// Node wrappers.
class JSNodeWrapperBase : public NodeWrapper {
public:
explicit constexpr JSNodeWrapperBase(Node* node) : NodeWrapper(node) {}
// Valid iff this node has a context input.
TNode<Object> context() const {
// Could be a Context or NoContextConstant.
return TNode<Object>::UncheckedCast(
NodeProperties::GetContextInput(node()));
}
// Valid iff this node has exactly one effect input.
Effect effect() const {
DCHECK_EQ(node()->op()->EffectInputCount(), 1);
return Effect{NodeProperties::GetEffectInput(node())};
}
// Valid iff this node has exactly one control input.
Control control() const {
DCHECK_EQ(node()->op()->ControlInputCount(), 1);
return Control{NodeProperties::GetControlInput(node())};
}
// Valid iff this node has a frame state input.
FrameState frame_state() const {
return FrameState{NodeProperties::GetFrameStateInput(node())};
}
};
#define DEFINE_INPUT_ACCESSORS(Name, name, TheIndex, Type) \
static constexpr int Name##Index() { return TheIndex; } \
TNode<Type> name() const { \
return TNode<Type>::UncheckedCast( \
NodeProperties::GetValueInput(node(), TheIndex)); \
}
class JSUnaryOpNode final : public JSNodeWrapperBase {
public:
explicit constexpr JSUnaryOpNode(Node* node) : JSNodeWrapperBase(node) {
CONSTEXPR_DCHECK(JSOperator::IsUnaryWithFeedback(node->opcode()));
}
#define INPUTS(V) \
V(Value, value, 0, Object) \
V(FeedbackVector, feedback_vector, 1, HeapObject)
INPUTS(DEFINE_INPUT_ACCESSORS)
#undef INPUTS
};
#define V(JSName, ...) using JSName##Node = JSUnaryOpNode;
JS_UNOP_WITH_FEEDBACK(V)
#undef V
class JSBinaryOpNode final : public JSNodeWrapperBase {
public:
explicit constexpr JSBinaryOpNode(Node* node) : JSNodeWrapperBase(node) {
CONSTEXPR_DCHECK(JSOperator::IsBinaryWithFeedback(node->opcode()));
}
#define INPUTS(V) \
V(Left, left, 0, Object) \
V(Right, right, 1, Object) \
V(FeedbackVector, feedback_vector, 2, HeapObject)
INPUTS(DEFINE_INPUT_ACCESSORS)
#undef INPUTS
};
#define V(JSName, ...) using JSName##Node = JSBinaryOpNode;
JS_BINOP_WITH_FEEDBACK(V)
#undef V
class JSGetIteratorNode final : public JSNodeWrapperBase {
public:
explicit constexpr JSGetIteratorNode(Node* node) : JSNodeWrapperBase(node) {
CONSTEXPR_DCHECK(node->opcode() == IrOpcode::kJSGetIterator);
}
const GetIteratorParameters& Parameters() const {
return GetIteratorParametersOf(node()->op());
}
#define INPUTS(V) \
V(Receiver, receiver, 0, Object) \
V(FeedbackVector, feedback_vector, 1, HeapObject)
INPUTS(DEFINE_INPUT_ACCESSORS)
#undef INPUTS
};
class JSCloneObjectNode final : public JSNodeWrapperBase {
public:
explicit constexpr JSCloneObjectNode(Node* node) : JSNodeWrapperBase(node) {
CONSTEXPR_DCHECK(node->opcode() == IrOpcode::kJSCloneObject);
}
const CloneObjectParameters& Parameters() const {
return CloneObjectParametersOf(node()->op());
}
#define INPUTS(V) \
V(Source, source, 0, Object) \
V(FeedbackVector, feedback_vector, 1, HeapObject)
INPUTS(DEFINE_INPUT_ACCESSORS)
#undef INPUTS
};
class JSGetTemplateObjectNode final : public JSNodeWrapperBase {
public:
explicit constexpr JSGetTemplateObjectNode(Node* node)
: JSNodeWrapperBase(node) {
CONSTEXPR_DCHECK(node->opcode() == IrOpcode::kJSGetTemplateObject);
}
const GetTemplateObjectParameters& Parameters() const {
return GetTemplateObjectParametersOf(node()->op());
}
#define INPUTS(V) V(FeedbackVector, feedback_vector, 0, HeapObject)
INPUTS(DEFINE_INPUT_ACCESSORS)
#undef INPUTS
};
class JSCreateLiteralOpNode final : public JSNodeWrapperBase {
public:
explicit constexpr JSCreateLiteralOpNode(Node* node)
: JSNodeWrapperBase(node) {
CONSTEXPR_DCHECK(node->opcode() == IrOpcode::kJSCreateLiteralArray ||
node->opcode() == IrOpcode::kJSCreateLiteralObject ||
node->opcode() == IrOpcode::kJSCreateLiteralRegExp);
}
const CreateLiteralParameters& Parameters() const {
return CreateLiteralParametersOf(node()->op());
}
#define INPUTS(V) V(FeedbackVector, feedback_vector, 0, HeapObject)
INPUTS(DEFINE_INPUT_ACCESSORS)
#undef INPUTS
};
using JSCreateLiteralArrayNode = JSCreateLiteralOpNode;
using JSCreateLiteralObjectNode = JSCreateLiteralOpNode;
using JSCreateLiteralRegExpNode = JSCreateLiteralOpNode;
class JSHasPropertyNode final : public JSNodeWrapperBase {
public:
explicit constexpr JSHasPropertyNode(Node* node) : JSNodeWrapperBase(node) {
CONSTEXPR_DCHECK(node->opcode() == IrOpcode::kJSHasProperty);
}
const PropertyAccess& Parameters() const {
return PropertyAccessOf(node()->op());
}
#define INPUTS(V) \
V(Object, object, 0, Object) \
V(Key, key, 1, Object) \
V(FeedbackVector, feedback_vector, 2, HeapObject)
INPUTS(DEFINE_INPUT_ACCESSORS)
#undef INPUTS
};
class JSLoadPropertyNode final : public JSNodeWrapperBase {
public:
explicit constexpr JSLoadPropertyNode(Node* node) : JSNodeWrapperBase(node) {
CONSTEXPR_DCHECK(node->opcode() == IrOpcode::kJSLoadProperty);
}
const PropertyAccess& Parameters() const {
return PropertyAccessOf(node()->op());
}
#define INPUTS(V) \
V(Object, object, 0, Object) \
V(Key, key, 1, Object) \
V(FeedbackVector, feedback_vector, 2, HeapObject)
INPUTS(DEFINE_INPUT_ACCESSORS)
#undef INPUTS
};
class JSStorePropertyNode final : public JSNodeWrapperBase {
public:
explicit constexpr JSStorePropertyNode(Node* node) : JSNodeWrapperBase(node) {
CONSTEXPR_DCHECK(node->opcode() == IrOpcode::kJSStoreProperty);
}
const PropertyAccess& Parameters() const {
return PropertyAccessOf(node()->op());
}
#define INPUTS(V) \
V(Object, object, 0, Object) \
V(Key, key, 1, Object) \
V(Value, value, 2, Object) \
V(FeedbackVector, feedback_vector, 3, HeapObject)
INPUTS(DEFINE_INPUT_ACCESSORS)
#undef INPUTS
};
#undef DEFINE_INPUT_ACCESSORS
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8

View File

@ -310,10 +310,70 @@ class NodeWrapper {
operator Node*() const { return node_; } operator Node*() const { return node_; }
Node* operator->() const { return node_; } Node* operator->() const { return node_; }
protected:
Node* node() const { return node_; }
void set_node(Node* node) {
DCHECK_NOT_NULL(node);
node_ = node;
}
private: private:
Node* node_; Node* node_;
}; };
// Wrapper classes for special node/edge types (effect, control, frame states).
class Effect : public NodeWrapper {
public:
explicit constexpr Effect(Node* node) : NodeWrapper(node) {
// TODO(jgruber): Remove the End special case.
SLOW_DCHECK(node == nullptr || node->op()->opcode() == IrOpcode::kEnd ||
node->op()->EffectOutputCount() > 0);
}
// Support the common `Node* x = effect = ...` pattern.
Node* operator=(Node* value) {
DCHECK_GT(value->op()->EffectOutputCount(), 0);
set_node(value);
return value;
}
};
class Control : public NodeWrapper {
public:
explicit constexpr Control(Node* node) : NodeWrapper(node) {
// TODO(jgruber): Remove the End special case.
SLOW_DCHECK(node == nullptr || node->opcode() == IrOpcode::kEnd ||
node->op()->ControlOutputCount() > 0);
}
// Support the common `Node* x = control = ...` pattern.
Node* operator=(Node* value) {
DCHECK_GT(value->op()->ControlOutputCount(), 0);
set_node(value);
return value;
}
};
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. // Typedefs to shorten commonly used Node containers.
using NodeDeque = ZoneDeque<Node*>; using NodeDeque = ZoneDeque<Node*>;
using NodeSet = ZoneSet<Node*>; using NodeSet = ZoneSet<Node*>;