1// Copyright 2014 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#ifndef V8_COMPILER_COMMON_OPERATOR_H_ 6#define V8_COMPILER_COMMON_OPERATOR_H_ 7 8#include "src/base/compiler-specific.h" 9#include "src/codegen/machine-type.h" 10#include "src/codegen/reloc-info.h" 11#include "src/codegen/string-constants.h" 12#include "src/common/globals.h" 13#include "src/compiler/feedback-source.h" 14#include "src/compiler/frame-states.h" 15#include "src/compiler/linkage.h" 16#include "src/compiler/node-properties.h" 17#include "src/deoptimizer/deoptimize-reason.h" 18#include "src/zone/zone-containers.h" 19#include "src/zone/zone-handle-set.h" 20 21namespace v8 { 22namespace internal { 23 24class StringConstantBase; 25 26namespace compiler { 27 28// Forward declarations. 29class CallDescriptor; 30struct CommonOperatorGlobalCache; 31class Operator; 32class Type; 33class Node; 34 35// The semantics of IrOpcode::kBranch changes throughout the pipeline, and in 36// particular is not the same before SimplifiedLowering (JS semantics) and after 37// (machine branch semantics). Some passes are applied both before and after 38// SimplifiedLowering, and use the BranchSemantics enum to know how branches 39// should be treated. 40enum class BranchSemantics { kJS, kMachine }; 41 42// Prediction hint for branches. 43enum class BranchHint : uint8_t { kNone, kTrue, kFalse }; 44 45inline BranchHint NegateBranchHint(BranchHint hint) { 46 switch (hint) { 47 case BranchHint::kNone: 48 return hint; 49 case BranchHint::kTrue: 50 return BranchHint::kFalse; 51 case BranchHint::kFalse: 52 return BranchHint::kTrue; 53 } 54 UNREACHABLE(); 55} 56 57inline size_t hash_value(BranchHint hint) { return static_cast<size_t>(hint); } 58 59V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, BranchHint); 60 61enum class TrapId : uint32_t { 62#define DEF_ENUM(Name, ...) k##Name, 63 FOREACH_WASM_TRAPREASON(DEF_ENUM) 64#undef DEF_ENUM 65 kInvalid 66}; 67 68inline size_t hash_value(TrapId id) { return static_cast<uint32_t>(id); } 69 70std::ostream& operator<<(std::ostream&, TrapId trap_id); 71 72TrapId TrapIdOf(const Operator* const op); 73 74V8_EXPORT_PRIVATE BranchHint BranchHintOf(const Operator* const) 75 V8_WARN_UNUSED_RESULT; 76 77// Helper function for return nodes, because returns have a hidden value input. 78int ValueInputCountOfReturn(Operator const* const op); 79 80// Parameters for the {Deoptimize} operator. 81class DeoptimizeParameters final { 82 public: 83 DeoptimizeParameters(DeoptimizeReason reason, FeedbackSource const& feedback) 84 : reason_(reason), feedback_(feedback) {} 85 86 DeoptimizeReason reason() const { return reason_; } 87 const FeedbackSource& feedback() const { return feedback_; } 88 89 private: 90 DeoptimizeReason const reason_; 91 FeedbackSource const feedback_; 92}; 93 94bool operator==(DeoptimizeParameters, DeoptimizeParameters); 95bool operator!=(DeoptimizeParameters, DeoptimizeParameters); 96 97size_t hast_value(DeoptimizeParameters p); 98 99std::ostream& operator<<(std::ostream&, DeoptimizeParameters p); 100 101DeoptimizeParameters const& DeoptimizeParametersOf(Operator const* const) 102 V8_WARN_UNUSED_RESULT; 103 104class SelectParameters final { 105 public: 106 explicit SelectParameters(MachineRepresentation representation, 107 BranchHint hint = BranchHint::kNone) 108 : representation_(representation), hint_(hint) {} 109 110 MachineRepresentation representation() const { return representation_; } 111 BranchHint hint() const { return hint_; } 112 113 private: 114 const MachineRepresentation representation_; 115 const BranchHint hint_; 116}; 117 118bool operator==(SelectParameters const&, SelectParameters const&); 119bool operator!=(SelectParameters const&, SelectParameters const&); 120 121size_t hash_value(SelectParameters const& p); 122 123std::ostream& operator<<(std::ostream&, SelectParameters const& p); 124 125V8_EXPORT_PRIVATE SelectParameters const& SelectParametersOf( 126 const Operator* const) V8_WARN_UNUSED_RESULT; 127 128V8_EXPORT_PRIVATE CallDescriptor const* CallDescriptorOf(const Operator* const) 129 V8_WARN_UNUSED_RESULT; 130 131V8_EXPORT_PRIVATE size_t ProjectionIndexOf(const Operator* const) 132 V8_WARN_UNUSED_RESULT; 133 134V8_EXPORT_PRIVATE MachineRepresentation 135LoopExitValueRepresentationOf(const Operator* const) V8_WARN_UNUSED_RESULT; 136 137V8_EXPORT_PRIVATE MachineRepresentation 138PhiRepresentationOf(const Operator* const) V8_WARN_UNUSED_RESULT; 139 140// The {IrOpcode::kParameter} opcode represents an incoming parameter to the 141// function. This class bundles the index and a debug name for such operators. 142class ParameterInfo final { 143 public: 144 static constexpr int kMinIndex = Linkage::kJSCallClosureParamIndex; 145 146 ParameterInfo(int index, const char* debug_name) 147 : index_(index), debug_name_(debug_name) { 148 DCHECK_LE(kMinIndex, index); 149 } 150 151 int index() const { return index_; } 152 const char* debug_name() const { return debug_name_; } 153 154 private: 155 int index_; 156 const char* debug_name_; 157}; 158 159std::ostream& operator<<(std::ostream&, ParameterInfo const&); 160 161V8_EXPORT_PRIVATE int ParameterIndexOf(const Operator* const) 162 V8_WARN_UNUSED_RESULT; 163const ParameterInfo& ParameterInfoOf(const Operator* const) 164 V8_WARN_UNUSED_RESULT; 165 166struct ObjectStateInfo final : std::pair<uint32_t, int> { 167 ObjectStateInfo(uint32_t object_id, int size) 168 : std::pair<uint32_t, int>(object_id, size) {} 169 uint32_t object_id() const { return first; } 170 int size() const { return second; } 171}; 172std::ostream& operator<<(std::ostream&, ObjectStateInfo const&); 173size_t hash_value(ObjectStateInfo const& p); 174 175struct TypedObjectStateInfo final 176 : std::pair<uint32_t, const ZoneVector<MachineType>*> { 177 TypedObjectStateInfo(uint32_t object_id, 178 const ZoneVector<MachineType>* machine_types) 179 : std::pair<uint32_t, const ZoneVector<MachineType>*>(object_id, 180 machine_types) {} 181 uint32_t object_id() const { return first; } 182 const ZoneVector<MachineType>* machine_types() const { return second; } 183}; 184std::ostream& operator<<(std::ostream&, TypedObjectStateInfo const&); 185size_t hash_value(TypedObjectStateInfo const& p); 186 187class RelocatablePtrConstantInfo final { 188 public: 189 enum Type { kInt32, kInt64 }; 190 191 RelocatablePtrConstantInfo(int32_t value, RelocInfo::Mode rmode) 192 : value_(value), rmode_(rmode), type_(kInt32) {} 193 RelocatablePtrConstantInfo(int64_t value, RelocInfo::Mode rmode) 194 : value_(value), rmode_(rmode), type_(kInt64) {} 195 196 intptr_t value() const { return value_; } 197 RelocInfo::Mode rmode() const { return rmode_; } 198 Type type() const { return type_; } 199 200 private: 201 intptr_t value_; 202 RelocInfo::Mode rmode_; 203 Type type_; 204}; 205 206bool operator==(RelocatablePtrConstantInfo const& lhs, 207 RelocatablePtrConstantInfo const& rhs); 208bool operator!=(RelocatablePtrConstantInfo const& lhs, 209 RelocatablePtrConstantInfo const& rhs); 210 211std::ostream& operator<<(std::ostream&, RelocatablePtrConstantInfo const&); 212 213size_t hash_value(RelocatablePtrConstantInfo const& p); 214 215// Used to define a sparse set of inputs. This can be used to efficiently encode 216// nodes that can have a lot of inputs, but where many inputs can have the same 217// value. 218class SparseInputMask final { 219 public: 220 using BitMaskType = uint32_t; 221 222 // The mask representing a dense input set. 223 static const BitMaskType kDenseBitMask = 0x0; 224 // The bits representing the end of a sparse input set. 225 static const BitMaskType kEndMarker = 0x1; 226 // The mask for accessing a sparse input entry in the bitmask. 227 static const BitMaskType kEntryMask = 0x1; 228 229 // The number of bits in the mask, minus one for the end marker. 230 static const int kMaxSparseInputs = (sizeof(BitMaskType) * kBitsPerByte - 1); 231 232 // An iterator over a node's sparse inputs. 233 class InputIterator final { 234 public: 235 InputIterator() = default; 236 InputIterator(BitMaskType bit_mask, Node* parent); 237 238 Node* parent() const { return parent_; } 239 int real_index() const { return real_index_; } 240 241 // Advance the iterator to the next sparse input. Only valid if the iterator 242 // has not reached the end. 243 void Advance(); 244 245 // Get the current sparse input's real node value. Only valid if the 246 // current sparse input is real. 247 Node* GetReal() const; 248 249 // Advance to the next real value or the end. Only valid if the iterator is 250 // not dense. Returns the number of empty values that were skipped. This can 251 // return 0 and in that case, it does not advance. 252 size_t AdvanceToNextRealOrEnd(); 253 254 // Get the current sparse input, returning either a real input node if 255 // the current sparse input is real, or the given {empty_value} if the 256 // current sparse input is empty. 257 Node* Get(Node* empty_value) const { 258 return IsReal() ? GetReal() : empty_value; 259 } 260 261 // True if the current sparse input is a real input node. 262 bool IsReal() const; 263 264 // True if the current sparse input is an empty value. 265 bool IsEmpty() const { return !IsReal(); } 266 267 // True if the iterator has reached the end of the sparse inputs. 268 bool IsEnd() const; 269 270 private: 271 BitMaskType bit_mask_; 272 Node* parent_; 273 int real_index_; 274 }; 275 276 explicit SparseInputMask(BitMaskType bit_mask) : bit_mask_(bit_mask) {} 277 278 // Provides a SparseInputMask representing a dense input set. 279 static SparseInputMask Dense() { return SparseInputMask(kDenseBitMask); } 280 281 BitMaskType mask() const { return bit_mask_; } 282 283 bool IsDense() const { return bit_mask_ == SparseInputMask::kDenseBitMask; } 284 285 // Counts how many real values are in the sparse array. Only valid for 286 // non-dense masks. 287 int CountReal() const; 288 289 // Returns an iterator over the sparse inputs of {node}. 290 InputIterator IterateOverInputs(Node* node); 291 292 private: 293 // 294 // The sparse input mask has a bitmask specifying if the node's inputs are 295 // represented sparsely. If the bitmask value is 0, then the inputs are dense; 296 // otherwise, they should be interpreted as follows: 297 // 298 // * The bitmask represents which values are real, with 1 for real values 299 // and 0 for empty values. 300 // * The inputs to the node are the real values, in the order of the 1s from 301 // least- to most-significant. 302 // * The top bit of the bitmask is a guard indicating the end of the values, 303 // whether real or empty (and is not representative of a real input 304 // itself). This is used so that we don't have to additionally store a 305 // value count. 306 // 307 // So, for N 1s in the bitmask, there are N - 1 inputs into the node. 308 BitMaskType bit_mask_; 309}; 310 311bool operator==(SparseInputMask const& lhs, SparseInputMask const& rhs); 312bool operator!=(SparseInputMask const& lhs, SparseInputMask const& rhs); 313 314class TypedStateValueInfo final { 315 public: 316 TypedStateValueInfo(ZoneVector<MachineType> const* machine_types, 317 SparseInputMask sparse_input_mask) 318 : machine_types_(machine_types), sparse_input_mask_(sparse_input_mask) {} 319 320 ZoneVector<MachineType> const* machine_types() const { 321 return machine_types_; 322 } 323 SparseInputMask sparse_input_mask() const { return sparse_input_mask_; } 324 325 private: 326 ZoneVector<MachineType> const* machine_types_; 327 SparseInputMask sparse_input_mask_; 328}; 329 330bool operator==(TypedStateValueInfo const& lhs, TypedStateValueInfo const& rhs); 331bool operator!=(TypedStateValueInfo const& lhs, TypedStateValueInfo const& rhs); 332 333std::ostream& operator<<(std::ostream&, TypedStateValueInfo const&); 334 335size_t hash_value(TypedStateValueInfo const& p); 336 337// Used to mark a region (as identified by BeginRegion/FinishRegion) as either 338// JavaScript-observable or not (i.e. allocations are not JavaScript observable 339// themselves, but transitioning stores are). 340enum class RegionObservability : uint8_t { kObservable, kNotObservable }; 341 342size_t hash_value(RegionObservability); 343 344std::ostream& operator<<(std::ostream&, RegionObservability); 345 346RegionObservability RegionObservabilityOf(Operator const*) 347 V8_WARN_UNUSED_RESULT; 348 349std::ostream& operator<<(std::ostream& os, 350 const ZoneVector<MachineType>* types); 351 352Type TypeGuardTypeOf(Operator const*) V8_WARN_UNUSED_RESULT; 353 354int OsrValueIndexOf(Operator const*) V8_WARN_UNUSED_RESULT; 355 356SparseInputMask SparseInputMaskOf(Operator const*) V8_WARN_UNUSED_RESULT; 357 358ZoneVector<MachineType> const* MachineTypesOf(Operator const*) 359 V8_WARN_UNUSED_RESULT; 360 361// The ArgumentsElementsState and ArgumentsLengthState can describe the layout 362// for backing stores of arguments objects of various types: 363// 364// +------------------------------------+ 365// - kUnmappedArguments: | arg0, ... argK-1, argK, ... argN-1 | {length:N} 366// +------------------------------------+ 367// +------------------------------------+ 368// - kMappedArguments: | hole, ... hole, argK, ... argN-1 | {length:N} 369// +------------------------------------+ 370// +------------------+ 371// - kRestParameter: | argK, ... argN-1 | {length:N-K} 372// +------------------+ 373// 374// Here {K} represents the number for formal parameters of the active function, 375// whereas {N} represents the actual number of arguments passed at runtime. 376// Note that {N < K} can happen and causes {K} to be capped accordingly. 377// 378// Also note that it is possible for an arguments object of {kMappedArguments} 379// type to carry a backing store of {kUnappedArguments} type when {K == 0}. 380using ArgumentsStateType = CreateArgumentsType; 381 382ArgumentsStateType ArgumentsStateTypeOf(Operator const*) V8_WARN_UNUSED_RESULT; 383 384uint32_t ObjectIdOf(Operator const*); 385 386MachineRepresentation DeadValueRepresentationOf(Operator const*) 387 V8_WARN_UNUSED_RESULT; 388 389class IfValueParameters final { 390 public: 391 IfValueParameters(int32_t value, int32_t comparison_order, 392 BranchHint hint = BranchHint::kNone) 393 : value_(value), comparison_order_(comparison_order), hint_(hint) {} 394 395 int32_t value() const { return value_; } 396 int32_t comparison_order() const { return comparison_order_; } 397 BranchHint hint() const { return hint_; } 398 399 private: 400 int32_t value_; 401 int32_t comparison_order_; 402 BranchHint hint_; 403}; 404 405V8_EXPORT_PRIVATE bool operator==(IfValueParameters const&, 406 IfValueParameters const&); 407 408size_t hash_value(IfValueParameters const&); 409 410V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, 411 IfValueParameters const&); 412 413V8_EXPORT_PRIVATE IfValueParameters const& IfValueParametersOf( 414 const Operator* op) V8_WARN_UNUSED_RESULT; 415 416const FrameStateInfo& FrameStateInfoOf(const Operator* op) 417 V8_WARN_UNUSED_RESULT; 418 419V8_EXPORT_PRIVATE Handle<HeapObject> HeapConstantOf(const Operator* op) 420 V8_WARN_UNUSED_RESULT; 421 422const StringConstantBase* StringConstantBaseOf(const Operator* op) 423 V8_WARN_UNUSED_RESULT; 424 425const char* StaticAssertSourceOf(const Operator* op); 426 427class SLVerifierHintParameters final { 428 public: 429 explicit SLVerifierHintParameters(const Operator* semantics, 430 base::Optional<Type> override_output_type) 431 : semantics_(semantics), override_output_type_(override_output_type) {} 432 433 const Operator* semantics() const { return semantics_; } 434 const base::Optional<Type>& override_output_type() const { 435 return override_output_type_; 436 } 437 438 private: 439 const Operator* semantics_; 440 base::Optional<Type> override_output_type_; 441}; 442 443V8_EXPORT_PRIVATE bool operator==(const SLVerifierHintParameters& p1, 444 const SLVerifierHintParameters& p2); 445 446size_t hash_value(const SLVerifierHintParameters& p); 447 448V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out, 449 const SLVerifierHintParameters& p); 450 451V8_EXPORT_PRIVATE const SLVerifierHintParameters& SLVerifierHintParametersOf( 452 const Operator* op) V8_WARN_UNUSED_RESULT; 453 454// Interface for building common operators that can be used at any level of IR, 455// including JavaScript, mid-level, and low-level. 456class V8_EXPORT_PRIVATE CommonOperatorBuilder final 457 : public NON_EXPORTED_BASE(ZoneObject) { 458 public: 459 explicit CommonOperatorBuilder(Zone* zone); 460 CommonOperatorBuilder(const CommonOperatorBuilder&) = delete; 461 CommonOperatorBuilder& operator=(const CommonOperatorBuilder&) = delete; 462 463 // A dummy value node temporarily used as input when the actual value doesn't 464 // matter. This operator is inserted only in SimplifiedLowering and is 465 // expected to not survive dead code elimination. 466 const Operator* Plug(); 467 468 const Operator* Dead(); 469 const Operator* DeadValue(MachineRepresentation rep); 470 const Operator* Unreachable(); 471 const Operator* StaticAssert(const char* source); 472 // SLVerifierHint is used only during SimplifiedLowering. It may be introduced 473 // during lowering to provide additional hints for the verifier. These nodes 474 // are removed at the end of SimplifiedLowering after verification. 475 const Operator* SLVerifierHint( 476 const Operator* semantics, 477 const base::Optional<Type>& override_output_type); 478 const Operator* End(size_t control_input_count); 479 const Operator* Branch(BranchHint = BranchHint::kNone); 480 const Operator* IfTrue(); 481 const Operator* IfFalse(); 482 const Operator* IfSuccess(); 483 const Operator* IfException(); 484 const Operator* Switch(size_t control_output_count); 485 const Operator* IfValue(int32_t value, int32_t order = 0, 486 BranchHint hint = BranchHint::kNone); 487 const Operator* IfDefault(BranchHint hint = BranchHint::kNone); 488 const Operator* Throw(); 489 const Operator* Deoptimize(DeoptimizeReason reason, 490 FeedbackSource const& feedback); 491 const Operator* DeoptimizeIf(DeoptimizeReason reason, 492 FeedbackSource const& feedback); 493 const Operator* DeoptimizeUnless(DeoptimizeReason reason, 494 FeedbackSource const& feedback); 495 const Operator* TrapIf(TrapId trap_id); 496 const Operator* TrapUnless(TrapId trap_id); 497 const Operator* Return(int value_input_count = 1); 498 const Operator* Terminate(); 499 500 const Operator* Start(int value_output_count); 501 const Operator* Loop(int control_input_count); 502 const Operator* Merge(int control_input_count); 503 const Operator* Parameter(int index, const char* debug_name = nullptr); 504 505 const Operator* OsrValue(int index); 506 507 const Operator* Int32Constant(int32_t); 508 const Operator* Int64Constant(int64_t); 509 const Operator* TaggedIndexConstant(int32_t value); 510 const Operator* Float32Constant(volatile float); 511 const Operator* Float64Constant(volatile double); 512 const Operator* ExternalConstant(const ExternalReference&); 513 const Operator* NumberConstant(volatile double); 514 const Operator* PointerConstant(intptr_t); 515 const Operator* HeapConstant(const Handle<HeapObject>&); 516 const Operator* CompressedHeapConstant(const Handle<HeapObject>&); 517 const Operator* ObjectId(uint32_t); 518 519 const Operator* RelocatableInt32Constant(int32_t value, 520 RelocInfo::Mode rmode); 521 const Operator* RelocatableInt64Constant(int64_t value, 522 RelocInfo::Mode rmode); 523 524 const Operator* Select(MachineRepresentation, BranchHint = BranchHint::kNone); 525 const Operator* Phi(MachineRepresentation representation, 526 int value_input_count); 527 const Operator* EffectPhi(int effect_input_count); 528 const Operator* InductionVariablePhi(int value_input_count); 529 const Operator* LoopExit(); 530 const Operator* LoopExitValue(MachineRepresentation rep); 531 const Operator* LoopExitEffect(); 532 const Operator* Checkpoint(); 533 const Operator* BeginRegion(RegionObservability); 534 const Operator* FinishRegion(); 535 const Operator* StateValues(int arguments, SparseInputMask bitmask); 536 const Operator* TypedStateValues(const ZoneVector<MachineType>* types, 537 SparseInputMask bitmask); 538 const Operator* ArgumentsElementsState(ArgumentsStateType type); 539 const Operator* ArgumentsLengthState(); 540 const Operator* ObjectState(uint32_t object_id, int pointer_slots); 541 const Operator* TypedObjectState(uint32_t object_id, 542 const ZoneVector<MachineType>* types); 543 const Operator* FrameState(BytecodeOffset bailout_id, 544 OutputFrameStateCombine state_combine, 545 const FrameStateFunctionInfo* function_info); 546 const Operator* Call(const CallDescriptor* call_descriptor); 547 const Operator* TailCall(const CallDescriptor* call_descriptor); 548 const Operator* Projection(size_t index); 549 const Operator* Retain(); 550 const Operator* TypeGuard(Type type); 551 const Operator* FoldConstant(); 552 553 // Constructs a new merge or phi operator with the same opcode as {op}, but 554 // with {size} inputs. 555 const Operator* ResizeMergeOrPhi(const Operator* op, int size); 556 557 // Constructs function info for frame state construction. 558 const FrameStateFunctionInfo* CreateFrameStateFunctionInfo( 559 FrameStateType type, int parameter_count, int local_count, 560 Handle<SharedFunctionInfo> shared_info); 561#if V8_ENABLE_WEBASSEMBLY 562 const FrameStateFunctionInfo* CreateJSToWasmFrameStateFunctionInfo( 563 FrameStateType type, int parameter_count, int local_count, 564 Handle<SharedFunctionInfo> shared_info, 565 const wasm::FunctionSig* signature); 566#endif // V8_ENABLE_WEBASSEMBLY 567 568 const Operator* DelayedStringConstant(const StringConstantBase* str); 569 570 private: 571 Zone* zone() const { return zone_; } 572 573 const CommonOperatorGlobalCache& cache_; 574 Zone* const zone_; 575}; 576 577// Node wrappers. 578 579class CommonNodeWrapperBase : public NodeWrapper { 580 public: 581 explicit constexpr CommonNodeWrapperBase(Node* node) : NodeWrapper(node) {} 582 583 // Valid iff this node has exactly one effect input. 584 Effect effect() const { 585 DCHECK_EQ(node()->op()->EffectInputCount(), 1); 586 return Effect{NodeProperties::GetEffectInput(node())}; 587 } 588 589 // Valid iff this node has exactly one control input. 590 Control control() const { 591 DCHECK_EQ(node()->op()->ControlInputCount(), 1); 592 return Control{NodeProperties::GetControlInput(node())}; 593 } 594}; 595 596#define DEFINE_INPUT_ACCESSORS(Name, name, TheIndex, Type) \ 597 static constexpr int Name##Index() { return TheIndex; } \ 598 TNode<Type> name() const { \ 599 return TNode<Type>::UncheckedCast( \ 600 NodeProperties::GetValueInput(node(), TheIndex)); \ 601 } 602 603// TODO(jgruber): This class doesn't match the usual OpcodeNode naming 604// convention for historical reasons (it was originally a very basic typed node 605// wrapper similar to Effect and Control). Consider updating the name, with low 606// priority. 607class FrameState : public CommonNodeWrapperBase { 608 public: 609 explicit constexpr FrameState(Node* node) : CommonNodeWrapperBase(node) { 610 DCHECK_EQ(node->opcode(), IrOpcode::kFrameState); 611 } 612 613 FrameStateInfo frame_state_info() const { 614 return FrameStateInfoOf(node()->op()); 615 } 616 617 static constexpr int kFrameStateParametersInput = 0; 618 static constexpr int kFrameStateLocalsInput = 1; 619 static constexpr int kFrameStateStackInput = 2; 620 static constexpr int kFrameStateContextInput = 3; 621 static constexpr int kFrameStateFunctionInput = 4; 622 static constexpr int kFrameStateOuterStateInput = 5; 623 static constexpr int kFrameStateInputCount = 6; 624 625 // Note: The parameters should be accessed through StateValuesAccess. 626 Node* parameters() const { 627 Node* n = node()->InputAt(kFrameStateParametersInput); 628 DCHECK(n->opcode() == IrOpcode::kStateValues || 629 n->opcode() == IrOpcode::kTypedStateValues); 630 return n; 631 } 632 Node* locals() const { 633 Node* n = node()->InputAt(kFrameStateLocalsInput); 634 DCHECK(n->opcode() == IrOpcode::kStateValues || 635 n->opcode() == IrOpcode::kTypedStateValues); 636 return n; 637 } 638 // TODO(jgruber): Consider renaming this to the more meaningful 639 // 'accumulator'. 640 Node* stack() const { return node()->InputAt(kFrameStateStackInput); } 641 Node* context() const { return node()->InputAt(kFrameStateContextInput); } 642 Node* function() const { return node()->InputAt(kFrameStateFunctionInput); } 643 644 // An outer frame state exists for inlined functions; otherwise it points at 645 // the start node. Could also be dead. 646 Node* outer_frame_state() const { 647 Node* result = node()->InputAt(kFrameStateOuterStateInput); 648 DCHECK(result->opcode() == IrOpcode::kFrameState || 649 result->opcode() == IrOpcode::kStart || 650 result->opcode() == IrOpcode::kDeadValue); 651 return result; 652 } 653}; 654 655class StartNode final : public CommonNodeWrapperBase { 656 public: 657 explicit constexpr StartNode(Node* node) : CommonNodeWrapperBase(node) { 658 DCHECK_EQ(IrOpcode::kStart, node->opcode()); 659 } 660 661 // The receiver is counted as part of formal parameters. 662 static constexpr int kReceiverOutputCount = 1; 663 // These outputs are in addition to formal parameters. 664 static constexpr int kExtraOutputCount = 4; 665 666 // Takes the formal parameter count of the current function (including 667 // receiver) and returns the number of value outputs of the start node. 668 static constexpr int OutputArityForFormalParameterCount(int argc) { 669 constexpr int kClosure = 1; 670 constexpr int kNewTarget = 1; 671 constexpr int kArgCount = 1; 672 constexpr int kContext = 1; 673 STATIC_ASSERT(kClosure + kNewTarget + kArgCount + kContext == 674 kExtraOutputCount); 675 // Checking related linkage methods here since they rely on Start node 676 // layout. 677 DCHECK_EQ(-1, Linkage::kJSCallClosureParamIndex); 678 DCHECK_EQ(argc + 0, Linkage::GetJSCallNewTargetParamIndex(argc)); 679 DCHECK_EQ(argc + 1, Linkage::GetJSCallArgCountParamIndex(argc)); 680 DCHECK_EQ(argc + 2, Linkage::GetJSCallContextParamIndex(argc)); 681 return argc + kClosure + kNewTarget + kArgCount + kContext; 682 } 683 684 int FormalParameterCount() const { 685 DCHECK_GE(node()->op()->ValueOutputCount(), 686 kExtraOutputCount + kReceiverOutputCount); 687 return node()->op()->ValueOutputCount() - kExtraOutputCount; 688 } 689 690 int FormalParameterCountWithoutReceiver() const { 691 DCHECK_GE(node()->op()->ValueOutputCount(), 692 kExtraOutputCount + kReceiverOutputCount); 693 return node()->op()->ValueOutputCount() - kExtraOutputCount - 694 kReceiverOutputCount; 695 } 696 697 // Note these functions don't return the index of the Start output; instead 698 // they return the index assigned to the Parameter node. 699 // TODO(jgruber): Consider unifying the two. 700 int NewTargetParameterIndex() const { 701 return Linkage::GetJSCallNewTargetParamIndex(FormalParameterCount()); 702 } 703 int ArgCountParameterIndex() const { 704 return Linkage::GetJSCallArgCountParamIndex(FormalParameterCount()); 705 } 706 int ContextParameterIndex() const { 707 return Linkage::GetJSCallContextParamIndex(FormalParameterCount()); 708 } 709 710 // TODO(jgruber): Remove this function and use 711 // Linkage::GetJSCallContextParamIndex instead. This currently doesn't work 712 // because tests don't create valid Start nodes - for example, they may add 713 // only two context outputs (and not the closure, new target, argc). Once 714 // tests are fixed, remove this function. 715 int ContextParameterIndex_MaybeNonStandardLayout() const { 716 // The context is always the last parameter to a JavaScript function, and 717 // {Parameter} indices start at -1, so value outputs of {Start} look like 718 // this: closure, receiver, param0, ..., paramN, context. 719 // 720 // TODO(jgruber): This function is called from spots that operate on 721 // CSA/Torque graphs; Start node layout appears to be different there. 722 // These should be unified to avoid confusion. Once done, enable this 723 // DCHECK: DCHECK_EQ(LastOutputIndex(), ContextOutputIndex()); 724 return node()->op()->ValueOutputCount() - 2; 725 } 726 int LastParameterIndex_MaybeNonStandardLayout() const { 727 return ContextParameterIndex_MaybeNonStandardLayout(); 728 } 729 730 // Unlike ContextParameterIndex_MaybeNonStandardLayout above, these return 731 // output indices (and not the index assigned to a Parameter). 732 int NewTargetOutputIndex() const { 733 // Indices assigned to parameters are off-by-one (Parameters indices start 734 // at -1). 735 // TODO(jgruber): Consider starting at 0. 736 DCHECK_EQ(Linkage::GetJSCallNewTargetParamIndex(FormalParameterCount()) + 1, 737 node()->op()->ValueOutputCount() - 3); 738 return node()->op()->ValueOutputCount() - 3; 739 } 740 int ArgCountOutputIndex() const { 741 // Indices assigned to parameters are off-by-one (Parameters indices start 742 // at -1). 743 // TODO(jgruber): Consider starting at 0. 744 DCHECK_EQ(Linkage::GetJSCallArgCountParamIndex(FormalParameterCount()) + 1, 745 node()->op()->ValueOutputCount() - 2); 746 return node()->op()->ValueOutputCount() - 2; 747 } 748 int ContextOutputIndex() const { 749 // Indices assigned to parameters are off-by-one (Parameters indices start 750 // at -1). 751 // TODO(jgruber): Consider starting at 0. 752 DCHECK_EQ(Linkage::GetJSCallContextParamIndex(FormalParameterCount()) + 1, 753 node()->op()->ValueOutputCount() - 1); 754 return node()->op()->ValueOutputCount() - 1; 755 } 756 int LastOutputIndex() const { return ContextOutputIndex(); } 757}; 758 759#undef DEFINE_INPUT_ACCESSORS 760 761} // namespace compiler 762} // namespace internal 763} // namespace v8 764 765#endif // V8_COMPILER_COMMON_OPERATOR_H_ 766