• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // 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.
40 enum class BranchSemantics { kJS, kMachine };
41 
42 // Prediction hint for branches.
43 enum class BranchHint : uint8_t { kNone, kTrue, kFalse };
44 
NegateBranchHint(BranchHint hint)45 inline 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 
hash_value(BranchHint hint)57 inline size_t hash_value(BranchHint hint) { return static_cast<size_t>(hint); }
58 
59 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, BranchHint);
60 
61 enum 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 
hash_value(TrapId id)68 inline size_t hash_value(TrapId id) { return static_cast<uint32_t>(id); }
69 
70 std::ostream& operator<<(std::ostream&, TrapId trap_id);
71 
72 TrapId TrapIdOf(const Operator* const op);
73 
74 V8_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.
78 int ValueInputCountOfReturn(Operator const* const op);
79 
80 // Parameters for the {Deoptimize} operator.
81 class DeoptimizeParameters final {
82  public:
DeoptimizeParameters(DeoptimizeReason reason,FeedbackSource const & feedback)83   DeoptimizeParameters(DeoptimizeReason reason, FeedbackSource const& feedback)
84       : reason_(reason), feedback_(feedback) {}
85 
reason()86   DeoptimizeReason reason() const { return reason_; }
feedback()87   const FeedbackSource& feedback() const { return feedback_; }
88 
89  private:
90   DeoptimizeReason const reason_;
91   FeedbackSource const feedback_;
92 };
93 
94 bool operator==(DeoptimizeParameters, DeoptimizeParameters);
95 bool operator!=(DeoptimizeParameters, DeoptimizeParameters);
96 
97 size_t hast_value(DeoptimizeParameters p);
98 
99 std::ostream& operator<<(std::ostream&, DeoptimizeParameters p);
100 
101 DeoptimizeParameters const& DeoptimizeParametersOf(Operator const* const)
102     V8_WARN_UNUSED_RESULT;
103 
104 class SelectParameters final {
105  public:
106   explicit SelectParameters(MachineRepresentation representation,
107                             BranchHint hint = BranchHint::kNone)
representation_(representation)108       : representation_(representation), hint_(hint) {}
109 
representation()110   MachineRepresentation representation() const { return representation_; }
hint()111   BranchHint hint() const { return hint_; }
112 
113  private:
114   const MachineRepresentation representation_;
115   const BranchHint hint_;
116 };
117 
118 bool operator==(SelectParameters const&, SelectParameters const&);
119 bool operator!=(SelectParameters const&, SelectParameters const&);
120 
121 size_t hash_value(SelectParameters const& p);
122 
123 std::ostream& operator<<(std::ostream&, SelectParameters const& p);
124 
125 V8_EXPORT_PRIVATE SelectParameters const& SelectParametersOf(
126     const Operator* const) V8_WARN_UNUSED_RESULT;
127 
128 V8_EXPORT_PRIVATE CallDescriptor const* CallDescriptorOf(const Operator* const)
129     V8_WARN_UNUSED_RESULT;
130 
131 V8_EXPORT_PRIVATE size_t ProjectionIndexOf(const Operator* const)
132     V8_WARN_UNUSED_RESULT;
133 
134 V8_EXPORT_PRIVATE MachineRepresentation
135 LoopExitValueRepresentationOf(const Operator* const) V8_WARN_UNUSED_RESULT;
136 
137 V8_EXPORT_PRIVATE MachineRepresentation
138 PhiRepresentationOf(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.
142 class ParameterInfo final {
143  public:
144   static constexpr int kMinIndex = Linkage::kJSCallClosureParamIndex;
145 
ParameterInfo(int index,const char * debug_name)146   ParameterInfo(int index, const char* debug_name)
147       : index_(index), debug_name_(debug_name) {
148     DCHECK_LE(kMinIndex, index);
149   }
150 
index()151   int index() const { return index_; }
debug_name()152   const char* debug_name() const { return debug_name_; }
153 
154  private:
155   int index_;
156   const char* debug_name_;
157 };
158 
159 std::ostream& operator<<(std::ostream&, ParameterInfo const&);
160 
161 V8_EXPORT_PRIVATE int ParameterIndexOf(const Operator* const)
162     V8_WARN_UNUSED_RESULT;
163 const ParameterInfo& ParameterInfoOf(const Operator* const)
164     V8_WARN_UNUSED_RESULT;
165 
166 struct ObjectStateInfo final : std::pair<uint32_t, int> {
ObjectStateInfofinal167   ObjectStateInfo(uint32_t object_id, int size)
168       : std::pair<uint32_t, int>(object_id, size) {}
object_idfinal169   uint32_t object_id() const { return first; }
sizefinal170   int size() const { return second; }
171 };
172 std::ostream& operator<<(std::ostream&, ObjectStateInfo const&);
173 size_t hash_value(ObjectStateInfo const& p);
174 
175 struct TypedObjectStateInfo final
176     : std::pair<uint32_t, const ZoneVector<MachineType>*> {
TypedObjectStateInfofinal177   TypedObjectStateInfo(uint32_t object_id,
178                        const ZoneVector<MachineType>* machine_types)
179       : std::pair<uint32_t, const ZoneVector<MachineType>*>(object_id,
180                                                             machine_types) {}
object_idfinal181   uint32_t object_id() const { return first; }
machine_typesfinal182   const ZoneVector<MachineType>* machine_types() const { return second; }
183 };
184 std::ostream& operator<<(std::ostream&, TypedObjectStateInfo const&);
185 size_t hash_value(TypedObjectStateInfo const& p);
186 
187 class RelocatablePtrConstantInfo final {
188  public:
189   enum Type { kInt32, kInt64 };
190 
RelocatablePtrConstantInfo(int32_t value,RelocInfo::Mode rmode)191   RelocatablePtrConstantInfo(int32_t value, RelocInfo::Mode rmode)
192       : value_(value), rmode_(rmode), type_(kInt32) {}
RelocatablePtrConstantInfo(int64_t value,RelocInfo::Mode rmode)193   RelocatablePtrConstantInfo(int64_t value, RelocInfo::Mode rmode)
194       : value_(value), rmode_(rmode), type_(kInt64) {}
195 
value()196   intptr_t value() const { return value_; }
rmode()197   RelocInfo::Mode rmode() const { return rmode_; }
type()198   Type type() const { return type_; }
199 
200  private:
201   intptr_t value_;
202   RelocInfo::Mode rmode_;
203   Type type_;
204 };
205 
206 bool operator==(RelocatablePtrConstantInfo const& lhs,
207                 RelocatablePtrConstantInfo const& rhs);
208 bool operator!=(RelocatablePtrConstantInfo const& lhs,
209                 RelocatablePtrConstantInfo const& rhs);
210 
211 std::ostream& operator<<(std::ostream&, RelocatablePtrConstantInfo const&);
212 
213 size_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.
218 class 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 
parent()238     Node* parent() const { return parent_; }
real_index()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.
Get(Node * empty_value)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.
IsEmpty()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 
SparseInputMask(BitMaskType bit_mask)276   explicit SparseInputMask(BitMaskType bit_mask) : bit_mask_(bit_mask) {}
277 
278   // Provides a SparseInputMask representing a dense input set.
Dense()279   static SparseInputMask Dense() { return SparseInputMask(kDenseBitMask); }
280 
mask()281   BitMaskType mask() const { return bit_mask_; }
282 
IsDense()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 
311 bool operator==(SparseInputMask const& lhs, SparseInputMask const& rhs);
312 bool operator!=(SparseInputMask const& lhs, SparseInputMask const& rhs);
313 
314 class TypedStateValueInfo final {
315  public:
TypedStateValueInfo(ZoneVector<MachineType> const * machine_types,SparseInputMask sparse_input_mask)316   TypedStateValueInfo(ZoneVector<MachineType> const* machine_types,
317                       SparseInputMask sparse_input_mask)
318       : machine_types_(machine_types), sparse_input_mask_(sparse_input_mask) {}
319 
machine_types()320   ZoneVector<MachineType> const* machine_types() const {
321     return machine_types_;
322   }
sparse_input_mask()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 
330 bool operator==(TypedStateValueInfo const& lhs, TypedStateValueInfo const& rhs);
331 bool operator!=(TypedStateValueInfo const& lhs, TypedStateValueInfo const& rhs);
332 
333 std::ostream& operator<<(std::ostream&, TypedStateValueInfo const&);
334 
335 size_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).
340 enum class RegionObservability : uint8_t { kObservable, kNotObservable };
341 
342 size_t hash_value(RegionObservability);
343 
344 std::ostream& operator<<(std::ostream&, RegionObservability);
345 
346 RegionObservability RegionObservabilityOf(Operator const*)
347     V8_WARN_UNUSED_RESULT;
348 
349 std::ostream& operator<<(std::ostream& os,
350                          const ZoneVector<MachineType>* types);
351 
352 Type TypeGuardTypeOf(Operator const*) V8_WARN_UNUSED_RESULT;
353 
354 int OsrValueIndexOf(Operator const*) V8_WARN_UNUSED_RESULT;
355 
356 SparseInputMask SparseInputMaskOf(Operator const*) V8_WARN_UNUSED_RESULT;
357 
358 ZoneVector<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}.
380 using ArgumentsStateType = CreateArgumentsType;
381 
382 ArgumentsStateType ArgumentsStateTypeOf(Operator const*) V8_WARN_UNUSED_RESULT;
383 
384 uint32_t ObjectIdOf(Operator const*);
385 
386 MachineRepresentation DeadValueRepresentationOf(Operator const*)
387     V8_WARN_UNUSED_RESULT;
388 
389 class IfValueParameters final {
390  public:
391   IfValueParameters(int32_t value, int32_t comparison_order,
392                     BranchHint hint = BranchHint::kNone)
value_(value)393       : value_(value), comparison_order_(comparison_order), hint_(hint) {}
394 
value()395   int32_t value() const { return value_; }
comparison_order()396   int32_t comparison_order() const { return comparison_order_; }
hint()397   BranchHint hint() const { return hint_; }
398 
399  private:
400   int32_t value_;
401   int32_t comparison_order_;
402   BranchHint hint_;
403 };
404 
405 V8_EXPORT_PRIVATE bool operator==(IfValueParameters const&,
406                                   IfValueParameters const&);
407 
408 size_t hash_value(IfValueParameters const&);
409 
410 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&,
411                                            IfValueParameters const&);
412 
413 V8_EXPORT_PRIVATE IfValueParameters const& IfValueParametersOf(
414     const Operator* op) V8_WARN_UNUSED_RESULT;
415 
416 const FrameStateInfo& FrameStateInfoOf(const Operator* op)
417     V8_WARN_UNUSED_RESULT;
418 
419 V8_EXPORT_PRIVATE Handle<HeapObject> HeapConstantOf(const Operator* op)
420     V8_WARN_UNUSED_RESULT;
421 
422 const StringConstantBase* StringConstantBaseOf(const Operator* op)
423     V8_WARN_UNUSED_RESULT;
424 
425 const char* StaticAssertSourceOf(const Operator* op);
426 
427 class SLVerifierHintParameters final {
428  public:
SLVerifierHintParameters(const Operator * semantics,base::Optional<Type> override_output_type)429   explicit SLVerifierHintParameters(const Operator* semantics,
430                                     base::Optional<Type> override_output_type)
431       : semantics_(semantics), override_output_type_(override_output_type) {}
432 
semantics()433   const Operator* semantics() const { return semantics_; }
override_output_type()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 
443 V8_EXPORT_PRIVATE bool operator==(const SLVerifierHintParameters& p1,
444                                   const SLVerifierHintParameters& p2);
445 
446 size_t hash_value(const SLVerifierHintParameters& p);
447 
448 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out,
449                                            const SLVerifierHintParameters& p);
450 
451 V8_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.
456 class V8_EXPORT_PRIVATE CommonOperatorBuilder final
NON_EXPORTED_BASE(ZoneObject)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 
579 class CommonNodeWrapperBase : public NodeWrapper {
580  public:
CommonNodeWrapperBase(Node * node)581   explicit constexpr CommonNodeWrapperBase(Node* node) : NodeWrapper(node) {}
582 
583   // Valid iff this node has exactly one effect input.
effect()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.
control()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.
607 class FrameState : public CommonNodeWrapperBase {
608  public:
FrameState(Node * node)609   explicit constexpr FrameState(Node* node) : CommonNodeWrapperBase(node) {
610     DCHECK_EQ(node->opcode(), IrOpcode::kFrameState);
611   }
612 
frame_state_info()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.
parameters()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   }
locals()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'.
stack()640   Node* stack() const { return node()->InputAt(kFrameStateStackInput); }
context()641   Node* context() const { return node()->InputAt(kFrameStateContextInput); }
function()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.
outer_frame_state()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 
655 class StartNode final : public CommonNodeWrapperBase {
656  public:
StartNode(Node * node)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.
OutputArityForFormalParameterCount(int argc)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 
FormalParameterCount()684   int FormalParameterCount() const {
685     DCHECK_GE(node()->op()->ValueOutputCount(),
686               kExtraOutputCount + kReceiverOutputCount);
687     return node()->op()->ValueOutputCount() - kExtraOutputCount;
688   }
689 
FormalParameterCountWithoutReceiver()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.
NewTargetParameterIndex()700   int NewTargetParameterIndex() const {
701     return Linkage::GetJSCallNewTargetParamIndex(FormalParameterCount());
702   }
ArgCountParameterIndex()703   int ArgCountParameterIndex() const {
704     return Linkage::GetJSCallArgCountParamIndex(FormalParameterCount());
705   }
ContextParameterIndex()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.
ContextParameterIndex_MaybeNonStandardLayout()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   }
LastParameterIndex_MaybeNonStandardLayout()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).
NewTargetOutputIndex()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   }
ArgCountOutputIndex()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   }
ContextOutputIndex()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   }
LastOutputIndex()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