From 5d417c0d49b4d0ec75915e229f2ab4d7d2690688 Mon Sep 17 00:00:00 2001 From: Jakob Gruber Date: Thu, 25 Jun 2020 14:10:24 +0200 Subject: [PATCH] [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 Reviewed-by: Georg Neis Cr-Commit-Position: refs/heads/master@{#68538} --- src/compiler/bytecode-graph-builder.cc | 51 +++- src/compiler/frame-states.cc | 5 + src/compiler/frame-states.h | 14 +- src/compiler/graph-assembler.h | 31 --- src/compiler/js-call-reducer.cc | 6 +- src/compiler/js-create-lowering.cc | 20 +- src/compiler/js-generic-lowering.cc | 80 +++--- .../js-native-context-specialization.cc | 37 ++- src/compiler/js-operator.cc | 18 +- src/compiler/js-operator.h | 235 +++++++++++++++--- src/compiler/node.h | 60 +++++ 11 files changed, 401 insertions(+), 156 deletions(-) diff --git a/src/compiler/bytecode-graph-builder.cc b/src/compiler/bytecode-graph-builder.cc index 93aaca2512..97a3148c12 100644 --- a/src/compiler/bytecode-graph-builder.cc +++ b/src/compiler/bytecode-graph-builder.cc @@ -1954,7 +1954,10 @@ void BytecodeGraphBuilder::VisitLdaKeyedProperty() { node = lowering.value(); } else { 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); } @@ -2041,7 +2044,11 @@ void BytecodeGraphBuilder::VisitStaKeyedProperty() { node = lowering.value(); } else { 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); @@ -2177,8 +2184,10 @@ void BytecodeGraphBuilder::VisitCreateRegExpLiteral() { int const slot_id = bytecode_iterator().GetIndexOperand(1); FeedbackSource pair = CreateFeedbackSource(slot_id); int literal_flags = bytecode_iterator().GetFlagOperand(2); + STATIC_ASSERT(JSCreateLiteralRegExpNode::FeedbackVectorIndex() == 0); 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); } @@ -2197,9 +2206,11 @@ void BytecodeGraphBuilder::VisitCreateArrayLiteral() { literal_flags |= ArrayLiteral::kDisableMementos; int number_of_elements = array_boilerplate_description.constants_elements_length(); - Node* literal = NewNode(javascript()->CreateLiteralArray( - array_boilerplate_description.object(), pair, literal_flags, - number_of_elements)); + STATIC_ASSERT(JSCreateLiteralArrayNode::FeedbackVectorIndex() == 0); + Node* literal = NewNode( + javascript()->CreateLiteralArray(array_boilerplate_description.object(), + pair, literal_flags, number_of_elements), + feedback_vector_node()); environment()->BindAccumulator(literal, Environment::kAttachFrameState); } @@ -2225,8 +2236,11 @@ void BytecodeGraphBuilder::VisitCreateObjectLiteral() { int literal_flags = interpreter::CreateObjectLiteralFlags::FlagsBits::decode(bytecode_flags); int number_of_properties = constant_properties.size(); - Node* literal = NewNode(javascript()->CreateLiteralObject( - constant_properties.object(), pair, literal_flags, number_of_properties)); + STATIC_ASSERT(JSCreateLiteralObjectNode::FeedbackVectorIndex() == 0); + Node* literal = NewNode( + javascript()->CreateLiteralObject(constant_properties.object(), pair, + literal_flags, number_of_properties), + feedback_vector_node()); environment()->BindAccumulator(literal, Environment::kAttachFrameState); } @@ -2243,7 +2257,9 @@ void BytecodeGraphBuilder::VisitCloneObject() { int slot = bytecode_iterator().GetIndexOperand(2); const Operator* op = 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); } @@ -2253,8 +2269,11 @@ void BytecodeGraphBuilder::VisitGetTemplateObject() { CreateFeedbackSource(bytecode_iterator().GetIndexOperand(1)); TemplateObjectDescriptionRef description( broker(), bytecode_iterator().GetConstantForIndexOperand(0, isolate())); - Node* template_object = NewNode(javascript()->GetTemplateObject( - description.object(), shared_info().object(), source)); + STATIC_ASSERT(JSGetTemplateObjectNode::FeedbackVectorIndex() == 0); + Node* template_object = + NewNode(javascript()->GetTemplateObject(description.object(), + shared_info().object(), source), + feedback_vector_node()); environment()->BindAccumulator(template_object); } @@ -3173,7 +3192,11 @@ void BytecodeGraphBuilder::VisitTestIn() { environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); FeedbackSource feedback = 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); } @@ -3548,7 +3571,9 @@ void BytecodeGraphBuilder::VisitGetIterator() { if (lowering.IsExit()) return; 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); } diff --git a/src/compiler/frame-states.cc b/src/compiler/frame-states.cc index 576f6ce542..7710e92ea3 100644 --- a/src/compiler/frame-states.cc +++ b/src/compiler/frame-states.cc @@ -16,6 +16,11 @@ 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_); } diff --git a/src/compiler/frame-states.h b/src/compiler/frame-states.h index 3922a21a9c..b9de40a185 100644 --- a/src/compiler/frame-states.h +++ b/src/compiler/frame-states.h @@ -140,13 +140,13 @@ size_t hash_value(FrameStateInfo const&); std::ostream& operator<<(std::ostream&, FrameStateInfo const&); -static const int kFrameStateParametersInput = 0; -static const int kFrameStateLocalsInput = 1; -static const int kFrameStateStackInput = 2; -static const int kFrameStateContextInput = 3; -static const int kFrameStateFunctionInput = 4; -static const int kFrameStateOuterStateInput = 5; -static const int kFrameStateInputCount = kFrameStateOuterStateInput + 1; +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 }; diff --git a/src/compiler/graph-assembler.h b/src/compiler/graph-assembler.h index 9b0b5b42c1..8448e4a53d 100644 --- a/src/compiler/graph-assembler.h +++ b/src/compiler/graph-assembler.h @@ -130,37 +130,6 @@ class BasicBlock; 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 }; // Label with statically known count of incoming branches and phis. diff --git a/src/compiler/js-call-reducer.cc b/src/compiler/js-call-reducer.cc index a2f9aaeb6f..7664904141 100644 --- a/src/compiler/js-call-reducer.cc +++ b/src/compiler/js-call-reducer.cc @@ -3089,9 +3089,9 @@ Reduction JSCallReducer::ReduceReflectHas(Node* node) { Node* vtrue; { // TODO(magardn): collect feedback so this can be optimized - vtrue = etrue = if_true = - graph()->NewNode(javascript()->HasProperty(FeedbackSource()), target, - key, context, frame_state, etrue, if_true); + vtrue = etrue = if_true = graph()->NewNode( + javascript()->HasProperty(FeedbackSource()), target, key, + jsgraph()->UndefinedConstant(), context, frame_state, etrue, if_true); } // Rewire potential exception edges. diff --git a/src/compiler/js-create-lowering.cc b/src/compiler/js-create-lowering.cc index 9674a436ad..fbc3abb2ac 100644 --- a/src/compiler/js-create-lowering.cc +++ b/src/compiler/js-create-lowering.cc @@ -1088,9 +1088,10 @@ Reduction JSCreateLowering::ReduceJSCreatePromise(Node* node) { Reduction JSCreateLowering::ReduceJSCreateLiteralArrayOrObject(Node* node) { DCHECK(node->opcode() == IrOpcode::kJSCreateLiteralArray || node->opcode() == IrOpcode::kJSCreateLiteralObject); - CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); - Node* effect = NodeProperties::GetEffectInput(node); - Node* control = NodeProperties::GetControlInput(node); + JSCreateLiteralOpNode n(node); + CreateLiteralParameters const& p = n.Parameters(); + Effect effect = n.effect(); + Control control = n.control(); ProcessedFeedback const& feedback = broker()->GetFeedbackForArrayOrObjectLiteral(p.feedback()); if (!feedback.IsInsufficient()) { @@ -1168,10 +1169,10 @@ Reduction JSCreateLowering::ReduceJSCreateEmptyLiteralObject(Node* node) { } Reduction JSCreateLowering::ReduceJSCreateLiteralRegExp(Node* node) { - DCHECK_EQ(IrOpcode::kJSCreateLiteralRegExp, node->opcode()); - CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); - Node* effect = NodeProperties::GetEffectInput(node); - Node* control = NodeProperties::GetControlInput(node); + JSCreateLiteralRegExpNode n(node); + CreateLiteralParameters const& p = n.Parameters(); + Effect effect = n.effect(); + Control control = n.control(); ProcessedFeedback const& feedback = broker()->GetFeedbackForRegExpLiteral(p.feedback()); if (!feedback.IsInsufficient()) { @@ -1184,9 +1185,8 @@ Reduction JSCreateLowering::ReduceJSCreateLiteralRegExp(Node* node) { } Reduction JSCreateLowering::ReduceJSGetTemplateObject(Node* node) { - DCHECK_EQ(IrOpcode::kJSGetTemplateObject, node->opcode()); - GetTemplateObjectParameters const& parameters = - GetTemplateObjectParametersOf(node->op()); + JSGetTemplateObjectNode n(node); + GetTemplateObjectParameters const& parameters = n.Parameters(); SharedFunctionInfoRef shared(broker(), parameters.shared()); JSArrayRef template_object = shared.GetTemplateObject( TemplateObjectDescriptionRef(broker(), parameters.description()), diff --git a/src/compiler/js-generic-lowering.cc b/src/compiler/js-generic-lowering.cc index 8dbb64fe66..7aac92634a 100644 --- a/src/compiler/js-generic-lowering.cc +++ b/src/compiler/js-generic-lowering.cc @@ -60,7 +60,6 @@ Reduction JSGenericLowering::Reduce(Node* node) { void JSGenericLowering::LowerJS##Name(Node* node) { \ ReplaceWithBuiltinCall(node, Builtins::k##Name); \ } -REPLACE_STUB_CALL(HasProperty) REPLACE_STUB_CALL(ToLength) REPLACE_STUB_CALL(ToNumber) REPLACE_STUB_CALL(ToNumberConvertBigInt) @@ -208,6 +207,7 @@ DEF_BINARY_LOWERING(LessThanOrEqual) void JSGenericLowering::LowerJSStrictEqual(Node* node) { // The === operator doesn't need the current context. NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant()); + DCHECK_EQ(node->op()->ControlInputCount(), 1); node->RemoveInput(NodeProperties::FirstControlIndex(node)); Builtins::Name builtin_id; @@ -246,20 +246,29 @@ bool ShouldUseMegamorphicLoadBuiltin(FeedbackSource const& source, } } // 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) { - const PropertyAccess& p = PropertyAccessOf(node->op()); - Node* frame_state = NodeProperties::GetFrameStateInput(node); - Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput); - node->InsertInput(zone(), 2, - jsgraph()->TaggedIndexConstant(p.feedback().index())); + JSLoadPropertyNode n(node); + const PropertyAccess& p = n.Parameters(); + FrameState frame_state = n.frame_state(); + FrameState outer_state = frame_state.outer_frame_state(); + STATIC_ASSERT(n.FeedbackVectorIndex() == 2); if (outer_state->opcode() != IrOpcode::kFrameState) { + n->RemoveInput(n.FeedbackVectorIndex()); + n->InsertInput(zone(), 2, + jsgraph()->TaggedIndexConstant(p.feedback().index())); ReplaceWithBuiltinCall( node, ShouldUseMegamorphicLoadBuiltin(p.feedback(), broker()) ? Builtins::kKeyedLoadICTrampoline_Megamorphic : Builtins::kKeyedLoadICTrampoline); } else { - Node* vector = jsgraph()->HeapConstant(p.feedback().vector); - node->InsertInput(zone(), 3, vector); + n->InsertInput(zone(), 2, + jsgraph()->TaggedIndexConstant(p.feedback().index())); ReplaceWithBuiltinCall( node, ShouldUseMegamorphicLoadBuiltin(p.feedback(), broker()) ? Builtins::kKeyedLoadIC_Megamorphic @@ -324,30 +333,33 @@ void JSGenericLowering::LowerJSGetIterator(Node* node) { // instead of 2 calls resulting from the generic lowering of the LoadNamed // and Call operators. - GetIteratorParameters const& p = GetIteratorParametersOf(node->op()); + JSGetIteratorNode n(node); + GetIteratorParameters const& p = n.Parameters(); Node* load_slot = jsgraph()->TaggedIndexConstant(p.loadFeedback().slot.ToInt()); Node* call_slot = 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(), 2, call_slot); - node->InsertInput(zone(), 3, feedback); ReplaceWithBuiltinCall(node, Builtins::kGetIteratorWithFeedback); } void JSGenericLowering::LowerJSStoreProperty(Node* node) { - PropertyAccess const& p = PropertyAccessOf(node->op()); - Node* frame_state = NodeProperties::GetFrameStateInput(node); - Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput); - node->InsertInput(zone(), 3, - jsgraph()->TaggedIndexConstant(p.feedback().index())); + JSStorePropertyNode n(node); + const PropertyAccess& p = n.Parameters(); + FrameState frame_state = n.frame_state(); + FrameState outer_state = frame_state.outer_frame_state(); + STATIC_ASSERT(n.FeedbackVectorIndex() == 3); if (outer_state->opcode() != IrOpcode::kFrameState) { + n->RemoveInput(n.FeedbackVectorIndex()); + node->InsertInput(zone(), 3, + jsgraph()->TaggedIndexConstant(p.feedback().index())); ReplaceWithBuiltinCall(node, Builtins::kKeyedStoreICTrampoline); } else { - Node* vector = jsgraph()->HeapConstant(p.feedback().vector); - node->InsertInput(zone(), 4, vector); + node->InsertInput(zone(), 3, + jsgraph()->TaggedIndexConstant(p.feedback().index())); ReplaceWithBuiltinCall(node, Builtins::kKeyedStoreIC); } } @@ -595,13 +607,14 @@ void JSGenericLowering::LowerJSCreateTypedArray(Node* node) { } void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) { - CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); - node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector)); + JSCreateLiteralArrayNode n(node); + CreateLiteralParameters const& p = n.Parameters(); + STATIC_ASSERT(n.FeedbackVectorIndex() == 0); node->InsertInput(zone(), 1, jsgraph()->TaggedIndexConstant(p.feedback().index())); 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. if ((p.flags() & AggregateLiteral::kIsShallow) != 0 && p.length() < ConstructorBuiltins::kMaximumClonedShallowArrayElements) { @@ -613,17 +626,19 @@ void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) { } void JSGenericLowering::LowerJSGetTemplateObject(Node* node) { - GetTemplateObjectParameters const& p = - GetTemplateObjectParametersOf(node->op()); + JSGetTemplateObjectNode n(node); + GetTemplateObjectParameters const& p = n.Parameters(); SharedFunctionInfoRef shared(broker(), p.shared()); 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(), 1, jsgraph()->Constant(description)); node->InsertInput(zone(), 2, jsgraph()->UintPtrConstant(p.feedback().index())); - node->InsertInput(zone(), 3, jsgraph()->HeapConstant(p.feedback().vector)); - node->RemoveInput(6); // control ReplaceWithBuiltinCall(node, Builtins::kGetTemplateObject); } @@ -642,8 +657,9 @@ void JSGenericLowering::LowerJSCreateArrayFromIterable(Node* node) { } void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) { - CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); - node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector)); + JSCreateLiteralObjectNode n(node); + CreateLiteralParameters const& p = n.Parameters(); + STATIC_ASSERT(n.FeedbackVectorIndex() == 0); node->InsertInput(zone(), 1, jsgraph()->TaggedIndexConstant(p.feedback().index())); node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant())); @@ -661,11 +677,12 @@ void JSGenericLowering::LowerJSCreateLiteralObject(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(), 2, jsgraph()->TaggedIndexConstant(p.feedback().index())); - node->InsertInput(zone(), 3, jsgraph()->HeapConstant(p.feedback().vector)); ReplaceWithBuiltinCall(node, Builtins::kCloneObjectIC); } @@ -674,8 +691,9 @@ void JSGenericLowering::LowerJSCreateEmptyLiteralObject(Node* node) { } void JSGenericLowering::LowerJSCreateLiteralRegExp(Node* node) { - CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); - node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector)); + JSCreateLiteralRegExpNode n(node); + CreateLiteralParameters const& p = n.Parameters(); + STATIC_ASSERT(n.FeedbackVectorIndex() == 0); node->InsertInput(zone(), 1, jsgraph()->TaggedIndexConstant(p.feedback().index())); node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant())); diff --git a/src/compiler/js-native-context-specialization.cc b/src/compiler/js-native-context-specialization.cc index 73b10435e2..ee59db0a70 100644 --- a/src/compiler/js-native-context-specialization.cc +++ b/src/compiler/js-native-context-specialization.cc @@ -1358,14 +1358,14 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) { } Reduction JSNativeContextSpecialization::ReduceJSGetIterator(Node* node) { - DCHECK_EQ(IrOpcode::kJSGetIterator, node->opcode()); - GetIteratorParameters const& p = GetIteratorParametersOf(node->op()); + JSGetIteratorNode n(node); + GetIteratorParameters const& p = n.Parameters(); - Node* receiver = NodeProperties::GetValueInput(node, 0); - Node* context = NodeProperties::GetContextInput(node); - Node* frame_state = NodeProperties::GetFrameStateInput(node); - Node* effect = NodeProperties::GetEffectInput(node); - Node* control = NodeProperties::GetControlInput(node); + TNode receiver = n.receiver(); + TNode context = n.context(); + FrameState frame_state = n.frame_state(); + Effect effect = n.effect(); + Control control = n.control(); // Load iterator property operator Handle iterator_symbol = factory()->iterator_symbol(); @@ -1895,13 +1895,11 @@ Reduction JSNativeContextSpecialization::ReduceSoftDeoptimize( } Reduction JSNativeContextSpecialization::ReduceJSHasProperty(Node* node) { - DCHECK_EQ(IrOpcode::kJSHasProperty, node->opcode()); - PropertyAccess const& p = PropertyAccessOf(node->op()); - Node* key = NodeProperties::GetValueInput(node, 1); + JSHasPropertyNode n(node); + PropertyAccess const& p = n.Parameters(); Node* value = jsgraph()->Dead(); - 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); } @@ -2012,9 +2010,9 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadPropertyWithEnumeratedKey( } Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) { - DCHECK_EQ(IrOpcode::kJSLoadProperty, node->opcode()); - PropertyAccess const& p = PropertyAccessOf(node->op()); - Node* name = NodeProperties::GetValueInput(node, 1); + JSLoadPropertyNode n(node); + PropertyAccess const& p = n.Parameters(); + Node* name = n.key(); if (name->opcode() == IrOpcode::kJSForInNext) { Reduction reduction = ReduceJSLoadPropertyWithEnumeratedKey(node); @@ -2028,13 +2026,10 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) { } Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) { - DCHECK_EQ(IrOpcode::kJSStoreProperty, node->opcode()); - PropertyAccess const& p = PropertyAccessOf(node->op()); - Node* const key = NodeProperties::GetValueInput(node, 1); - Node* const value = NodeProperties::GetValueInput(node, 2); - + JSStorePropertyNode n(node); + PropertyAccess const& p = n.Parameters(); 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); } diff --git a/src/compiler/js-operator.cc b/src/compiler/js-operator.cc index b152569ae1..691796d9cb 100644 --- a/src/compiler/js-operator.cc +++ b/src/compiler/js-operator.cc @@ -890,7 +890,7 @@ const Operator* JSOperatorBuilder::LoadProperty( return new (zone()) Operator1( // -- IrOpcode::kJSLoadProperty, Operator::kNoProperties, // opcode "JSLoadProperty", // name - 2, 1, 1, 1, 1, 2, // counts + 3, 1, 1, 1, 1, 2, // counts access); // parameter } @@ -900,7 +900,7 @@ const Operator* JSOperatorBuilder::GetIterator( return new (zone()) Operator1( // -- IrOpcode::kJSGetIterator, Operator::kNoProperties, // opcode "JSGetIterator", // name - 1, 1, 1, 1, 1, 2, // counts + 2, 1, 1, 1, 1, 2, // counts access); // parameter } @@ -909,7 +909,7 @@ const Operator* JSOperatorBuilder::HasProperty(FeedbackSource const& feedback) { return new (zone()) Operator1( // -- IrOpcode::kJSHasProperty, Operator::kNoProperties, // opcode "JSHasProperty", // name - 2, 1, 1, 1, 1, 2, // counts + 3, 1, 1, 1, 1, 2, // counts access); // parameter } @@ -987,7 +987,7 @@ const Operator* JSOperatorBuilder::StoreProperty( return new (zone()) Operator1( // -- IrOpcode::kJSStoreProperty, Operator::kNoProperties, // opcode "JSStoreProperty", // name - 3, 1, 1, 0, 1, 2, // counts + 4, 1, 1, 0, 1, 2, // counts access); // parameter } @@ -1167,7 +1167,7 @@ const Operator* JSOperatorBuilder::CreateLiteralArray( IrOpcode::kJSCreateLiteralArray, // opcode Operator::kNoProperties, // properties "JSCreateLiteralArray", // name - 0, 1, 1, 1, 1, 2, // counts + 1, 1, 1, 1, 1, 2, // counts parameters); // parameter } @@ -1200,7 +1200,7 @@ const Operator* JSOperatorBuilder::CreateLiteralObject( IrOpcode::kJSCreateLiteralObject, // opcode Operator::kNoProperties, // properties "JSCreateLiteralObject", // name - 0, 1, 1, 1, 1, 2, // counts + 1, 1, 1, 1, 1, 2, // counts parameters); // parameter } @@ -1212,7 +1212,7 @@ const Operator* JSOperatorBuilder::GetTemplateObject( IrOpcode::kJSGetTemplateObject, // opcode Operator::kEliminatable, // properties "JSGetTemplateObject", // name - 0, 1, 1, 1, 1, 0, // counts + 1, 1, 1, 1, 1, 0, // counts parameters); // parameter } @@ -1223,7 +1223,7 @@ const Operator* JSOperatorBuilder::CloneObject(FeedbackSource const& feedback, IrOpcode::kJSCloneObject, // opcode Operator::kNoProperties, // properties "JSCloneObject", // name - 1, 1, 1, 1, 1, 2, // counts + 2, 1, 1, 1, 1, 2, // counts parameters); // parameter } @@ -1253,7 +1253,7 @@ const Operator* JSOperatorBuilder::CreateLiteralRegExp( IrOpcode::kJSCreateLiteralRegExp, // opcode Operator::kNoProperties, // properties "JSCreateLiteralRegExp", // name - 0, 1, 1, 1, 1, 2, // counts + 1, 1, 1, 1, 1, 2, // counts parameters); // parameter } diff --git a/src/compiler/js-operator.h b/src/compiler/js-operator.h index ad9365b4b5..28cbada072 100644 --- a/src/compiler/js-operator.h +++ b/src/compiler/js-operator.h @@ -6,8 +6,10 @@ #define V8_COMPILER_JS_OPERATOR_H_ #include "src/base/compiler-specific.h" +#include "src/codegen/tnode.h" #include "src/compiler/feedback-source.h" #include "src/compiler/globals.h" +#include "src/compiler/node-properties.h" #include "src/compiler/node.h" #include "src/compiler/opcodes.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 // call sites the frequency is not known. class CallFrequency final { @@ -1043,6 +1014,208 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final 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 context() const { + // Could be a Context or NoContextConstant. + return TNode::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 name() const { \ + return TNode::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 internal } // namespace v8 diff --git a/src/compiler/node.h b/src/compiler/node.h index add4116dac..1cd235af92 100644 --- a/src/compiler/node.h +++ b/src/compiler/node.h @@ -310,10 +310,70 @@ class NodeWrapper { operator Node*() 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: 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. using NodeDeque = ZoneDeque; using NodeSet = ZoneSet;