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