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