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 IsSafetyCheck : uint8_t {
55 kCriticalSafetyCheck,
56 kSafetyCheck,
57 kNoSafetyCheck
58 };
59
60 // Get the more critical safety check of the two arguments.
61 IsSafetyCheck CombineSafetyChecks(IsSafetyCheck, IsSafetyCheck);
62
63 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, IsSafetyCheck);
hash_value(IsSafetyCheck is_safety_check)64 inline size_t hash_value(IsSafetyCheck is_safety_check) {
65 return static_cast<size_t>(is_safety_check);
66 }
67
68 enum class TrapId : uint32_t {
69 #define DEF_ENUM(Name, ...) k##Name,
70 FOREACH_WASM_TRAPREASON(DEF_ENUM)
71 #undef DEF_ENUM
72 kInvalid
73 };
74
hash_value(TrapId id)75 inline size_t hash_value(TrapId id) { return static_cast<uint32_t>(id); }
76
77 std::ostream& operator<<(std::ostream&, TrapId trap_id);
78
79 TrapId TrapIdOf(const Operator* const op);
80
81 struct BranchOperatorInfo {
82 BranchHint hint;
83 IsSafetyCheck is_safety_check;
84 };
85
hash_value(const BranchOperatorInfo & info)86 inline size_t hash_value(const BranchOperatorInfo& info) {
87 return base::hash_combine(info.hint, info.is_safety_check);
88 }
89
90 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, BranchOperatorInfo);
91
92 inline bool operator==(const BranchOperatorInfo& a,
93 const BranchOperatorInfo& b) {
94 return a.hint == b.hint && a.is_safety_check == b.is_safety_check;
95 }
96
97 V8_EXPORT_PRIVATE const BranchOperatorInfo& BranchOperatorInfoOf(
98 const Operator* const) V8_WARN_UNUSED_RESULT;
99 V8_EXPORT_PRIVATE BranchHint BranchHintOf(const Operator* const)
100 V8_WARN_UNUSED_RESULT;
101
102 // Helper function for return nodes, because returns have a hidden value input.
103 int ValueInputCountOfReturn(Operator const* const op);
104
105 // Parameters for the {Deoptimize} operator.
106 class DeoptimizeParameters final {
107 public:
DeoptimizeParameters(DeoptimizeKind kind,DeoptimizeReason reason,FeedbackSource const & feedback,IsSafetyCheck is_safety_check)108 DeoptimizeParameters(DeoptimizeKind kind, DeoptimizeReason reason,
109 FeedbackSource const& feedback,
110 IsSafetyCheck is_safety_check)
111 : kind_(kind),
112 reason_(reason),
113 feedback_(feedback),
114 is_safety_check_(is_safety_check) {}
115
kind()116 DeoptimizeKind kind() const { return kind_; }
reason()117 DeoptimizeReason reason() const { return reason_; }
feedback()118 const FeedbackSource& feedback() const { return feedback_; }
is_safety_check()119 IsSafetyCheck is_safety_check() const { return is_safety_check_; }
120
121 private:
122 DeoptimizeKind const kind_;
123 DeoptimizeReason const reason_;
124 FeedbackSource const feedback_;
125 IsSafetyCheck is_safety_check_;
126 };
127
128 bool operator==(DeoptimizeParameters, DeoptimizeParameters);
129 bool operator!=(DeoptimizeParameters, DeoptimizeParameters);
130
131 size_t hast_value(DeoptimizeParameters p);
132
133 std::ostream& operator<<(std::ostream&, DeoptimizeParameters p);
134
135 DeoptimizeParameters const& DeoptimizeParametersOf(Operator const* const)
136 V8_WARN_UNUSED_RESULT;
137
138 IsSafetyCheck IsSafetyCheckOf(const Operator* op) V8_WARN_UNUSED_RESULT;
139
140 class SelectParameters final {
141 public:
142 explicit SelectParameters(MachineRepresentation representation,
143 BranchHint hint = BranchHint::kNone)
representation_(representation)144 : representation_(representation), hint_(hint) {}
145
representation()146 MachineRepresentation representation() const { return representation_; }
hint()147 BranchHint hint() const { return hint_; }
148
149 private:
150 const MachineRepresentation representation_;
151 const BranchHint hint_;
152 };
153
154 bool operator==(SelectParameters const&, SelectParameters const&);
155 bool operator!=(SelectParameters const&, SelectParameters const&);
156
157 size_t hash_value(SelectParameters const& p);
158
159 std::ostream& operator<<(std::ostream&, SelectParameters const& p);
160
161 V8_EXPORT_PRIVATE SelectParameters const& SelectParametersOf(
162 const Operator* const) V8_WARN_UNUSED_RESULT;
163
164 V8_EXPORT_PRIVATE CallDescriptor const* CallDescriptorOf(const Operator* const)
165 V8_WARN_UNUSED_RESULT;
166
167 V8_EXPORT_PRIVATE size_t ProjectionIndexOf(const Operator* const)
168 V8_WARN_UNUSED_RESULT;
169
170 V8_EXPORT_PRIVATE MachineRepresentation
171 PhiRepresentationOf(const Operator* const) V8_WARN_UNUSED_RESULT;
172
173 // The {IrOpcode::kParameter} opcode represents an incoming parameter to the
174 // function. This class bundles the index and a debug name for such operators.
175 class ParameterInfo final {
176 public:
ParameterInfo(int index,const char * debug_name)177 ParameterInfo(int index, const char* debug_name)
178 : index_(index), debug_name_(debug_name) {}
179
index()180 int index() const { return index_; }
debug_name()181 const char* debug_name() const { return debug_name_; }
182
183 private:
184 int index_;
185 const char* debug_name_;
186 };
187
188 std::ostream& operator<<(std::ostream&, ParameterInfo const&);
189
190 V8_EXPORT_PRIVATE int ParameterIndexOf(const Operator* const)
191 V8_WARN_UNUSED_RESULT;
192 const ParameterInfo& ParameterInfoOf(const Operator* const)
193 V8_WARN_UNUSED_RESULT;
194
195 struct ObjectStateInfo final : std::pair<uint32_t, int> {
ObjectStateInfofinal196 ObjectStateInfo(uint32_t object_id, int size)
197 : std::pair<uint32_t, int>(object_id, size) {}
object_idfinal198 uint32_t object_id() const { return first; }
sizefinal199 int size() const { return second; }
200 };
201 std::ostream& operator<<(std::ostream&, ObjectStateInfo const&);
202 size_t hash_value(ObjectStateInfo const& p);
203
204 struct TypedObjectStateInfo final
205 : std::pair<uint32_t, const ZoneVector<MachineType>*> {
TypedObjectStateInfofinal206 TypedObjectStateInfo(uint32_t object_id,
207 const ZoneVector<MachineType>* machine_types)
208 : std::pair<uint32_t, const ZoneVector<MachineType>*>(object_id,
209 machine_types) {}
object_idfinal210 uint32_t object_id() const { return first; }
machine_typesfinal211 const ZoneVector<MachineType>* machine_types() const { return second; }
212 };
213 std::ostream& operator<<(std::ostream&, TypedObjectStateInfo const&);
214 size_t hash_value(TypedObjectStateInfo const& p);
215
216 class RelocatablePtrConstantInfo final {
217 public:
218 enum Type { kInt32, kInt64 };
219
RelocatablePtrConstantInfo(int32_t value,RelocInfo::Mode rmode)220 RelocatablePtrConstantInfo(int32_t value, RelocInfo::Mode rmode)
221 : value_(value), rmode_(rmode), type_(kInt32) {}
RelocatablePtrConstantInfo(int64_t value,RelocInfo::Mode rmode)222 RelocatablePtrConstantInfo(int64_t value, RelocInfo::Mode rmode)
223 : value_(value), rmode_(rmode), type_(kInt64) {}
224
value()225 intptr_t value() const { return value_; }
rmode()226 RelocInfo::Mode rmode() const { return rmode_; }
type()227 Type type() const { return type_; }
228
229 private:
230 intptr_t value_;
231 RelocInfo::Mode rmode_;
232 Type type_;
233 };
234
235 bool operator==(RelocatablePtrConstantInfo const& lhs,
236 RelocatablePtrConstantInfo const& rhs);
237 bool operator!=(RelocatablePtrConstantInfo const& lhs,
238 RelocatablePtrConstantInfo const& rhs);
239
240 std::ostream& operator<<(std::ostream&, RelocatablePtrConstantInfo const&);
241
242 size_t hash_value(RelocatablePtrConstantInfo const& p);
243
244 // Used to define a sparse set of inputs. This can be used to efficiently encode
245 // nodes that can have a lot of inputs, but where many inputs can have the same
246 // value.
247 class SparseInputMask final {
248 public:
249 using BitMaskType = uint32_t;
250
251 // The mask representing a dense input set.
252 static const BitMaskType kDenseBitMask = 0x0;
253 // The bits representing the end of a sparse input set.
254 static const BitMaskType kEndMarker = 0x1;
255 // The mask for accessing a sparse input entry in the bitmask.
256 static const BitMaskType kEntryMask = 0x1;
257
258 // The number of bits in the mask, minus one for the end marker.
259 static const int kMaxSparseInputs = (sizeof(BitMaskType) * kBitsPerByte - 1);
260
261 // An iterator over a node's sparse inputs.
262 class InputIterator final {
263 public:
264 InputIterator() = default;
265 InputIterator(BitMaskType bit_mask, Node* parent);
266
parent()267 Node* parent() const { return parent_; }
real_index()268 int real_index() const { return real_index_; }
269
270 // Advance the iterator to the next sparse input. Only valid if the iterator
271 // has not reached the end.
272 void Advance();
273
274 // Get the current sparse input's real node value. Only valid if the
275 // current sparse input is real.
276 Node* GetReal() const;
277
278 // Advance to the next real value or the end. Only valid if the iterator is
279 // not dense. Returns the number of empty values that were skipped. This can
280 // return 0 and in that case, it does not advance.
281 size_t AdvanceToNextRealOrEnd();
282
283 // Get the current sparse input, returning either a real input node if
284 // the current sparse input is real, or the given {empty_value} if the
285 // current sparse input is empty.
Get(Node * empty_value)286 Node* Get(Node* empty_value) const {
287 return IsReal() ? GetReal() : empty_value;
288 }
289
290 // True if the current sparse input is a real input node.
291 bool IsReal() const;
292
293 // True if the current sparse input is an empty value.
IsEmpty()294 bool IsEmpty() const { return !IsReal(); }
295
296 // True if the iterator has reached the end of the sparse inputs.
297 bool IsEnd() const;
298
299 private:
300 BitMaskType bit_mask_;
301 Node* parent_;
302 int real_index_;
303 };
304
SparseInputMask(BitMaskType bit_mask)305 explicit SparseInputMask(BitMaskType bit_mask) : bit_mask_(bit_mask) {}
306
307 // Provides a SparseInputMask representing a dense input set.
Dense()308 static SparseInputMask Dense() { return SparseInputMask(kDenseBitMask); }
309
mask()310 BitMaskType mask() const { return bit_mask_; }
311
IsDense()312 bool IsDense() const { return bit_mask_ == SparseInputMask::kDenseBitMask; }
313
314 // Counts how many real values are in the sparse array. Only valid for
315 // non-dense masks.
316 int CountReal() const;
317
318 // Returns an iterator over the sparse inputs of {node}.
319 InputIterator IterateOverInputs(Node* node);
320
321 private:
322 //
323 // The sparse input mask has a bitmask specifying if the node's inputs are
324 // represented sparsely. If the bitmask value is 0, then the inputs are dense;
325 // otherwise, they should be interpreted as follows:
326 //
327 // * The bitmask represents which values are real, with 1 for real values
328 // and 0 for empty values.
329 // * The inputs to the node are the real values, in the order of the 1s from
330 // least- to most-significant.
331 // * The top bit of the bitmask is a guard indicating the end of the values,
332 // whether real or empty (and is not representative of a real input
333 // itself). This is used so that we don't have to additionally store a
334 // value count.
335 //
336 // So, for N 1s in the bitmask, there are N - 1 inputs into the node.
337 BitMaskType bit_mask_;
338 };
339
340 bool operator==(SparseInputMask const& lhs, SparseInputMask const& rhs);
341 bool operator!=(SparseInputMask const& lhs, SparseInputMask const& rhs);
342
343 class TypedStateValueInfo final {
344 public:
TypedStateValueInfo(ZoneVector<MachineType> const * machine_types,SparseInputMask sparse_input_mask)345 TypedStateValueInfo(ZoneVector<MachineType> const* machine_types,
346 SparseInputMask sparse_input_mask)
347 : machine_types_(machine_types), sparse_input_mask_(sparse_input_mask) {}
348
machine_types()349 ZoneVector<MachineType> const* machine_types() const {
350 return machine_types_;
351 }
sparse_input_mask()352 SparseInputMask sparse_input_mask() const { return sparse_input_mask_; }
353
354 private:
355 ZoneVector<MachineType> const* machine_types_;
356 SparseInputMask sparse_input_mask_;
357 };
358
359 bool operator==(TypedStateValueInfo const& lhs, TypedStateValueInfo const& rhs);
360 bool operator!=(TypedStateValueInfo const& lhs, TypedStateValueInfo const& rhs);
361
362 std::ostream& operator<<(std::ostream&, TypedStateValueInfo const&);
363
364 size_t hash_value(TypedStateValueInfo const& p);
365
366 // Used to mark a region (as identified by BeginRegion/FinishRegion) as either
367 // JavaScript-observable or not (i.e. allocations are not JavaScript observable
368 // themselves, but transitioning stores are).
369 enum class RegionObservability : uint8_t { kObservable, kNotObservable };
370
371 size_t hash_value(RegionObservability);
372
373 std::ostream& operator<<(std::ostream&, RegionObservability);
374
375 RegionObservability RegionObservabilityOf(Operator const*)
376 V8_WARN_UNUSED_RESULT;
377
378 std::ostream& operator<<(std::ostream& os,
379 const ZoneVector<MachineType>* types);
380
381 Type TypeGuardTypeOf(Operator const*) V8_WARN_UNUSED_RESULT;
382
383 int OsrValueIndexOf(Operator const*) V8_WARN_UNUSED_RESULT;
384
385 SparseInputMask SparseInputMaskOf(Operator const*) V8_WARN_UNUSED_RESULT;
386
387 ZoneVector<MachineType> const* MachineTypesOf(Operator const*)
388 V8_WARN_UNUSED_RESULT;
389
390 // The ArgumentsElementsState and ArgumentsLengthState can describe the layout
391 // for backing stores of arguments objects of various types:
392 //
393 // +------------------------------------+
394 // - kUnmappedArguments: | arg0, ... argK-1, argK, ... argN-1 | {length:N}
395 // +------------------------------------+
396 // +------------------------------------+
397 // - kMappedArguments: | hole, ... hole, argK, ... argN-1 | {length:N}
398 // +------------------------------------+
399 // +------------------+
400 // - kRestParameter: | argK, ... argN-1 | {length:N-K}
401 // +------------------+
402 //
403 // Here {K} represents the number for formal parameters of the active function,
404 // whereas {N} represents the actual number of arguments passed at runtime.
405 // Note that {N < K} can happen and causes {K} to be capped accordingly.
406 //
407 // Also note that it is possible for an arguments object of {kMappedArguments}
408 // type to carry a backing store of {kUnappedArguments} type when {K == 0}.
409 using ArgumentsStateType = CreateArgumentsType;
410
411 ArgumentsStateType ArgumentsStateTypeOf(Operator const*) V8_WARN_UNUSED_RESULT;
412
413 uint32_t ObjectIdOf(Operator const*);
414
415 MachineRepresentation DeadValueRepresentationOf(Operator const*)
416 V8_WARN_UNUSED_RESULT;
417
418 class IfValueParameters final {
419 public:
420 IfValueParameters(int32_t value, int32_t comparison_order,
421 BranchHint hint = BranchHint::kNone)
value_(value)422 : value_(value), comparison_order_(comparison_order), hint_(hint) {}
423
value()424 int32_t value() const { return value_; }
comparison_order()425 int32_t comparison_order() const { return comparison_order_; }
hint()426 BranchHint hint() const { return hint_; }
427
428 private:
429 int32_t value_;
430 int32_t comparison_order_;
431 BranchHint hint_;
432 };
433
434 V8_EXPORT_PRIVATE bool operator==(IfValueParameters const&,
435 IfValueParameters const&);
436
437 size_t hash_value(IfValueParameters const&);
438
439 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&,
440 IfValueParameters const&);
441
442 V8_EXPORT_PRIVATE IfValueParameters const& IfValueParametersOf(
443 const Operator* op) V8_WARN_UNUSED_RESULT;
444
445 const FrameStateInfo& FrameStateInfoOf(const Operator* op)
446 V8_WARN_UNUSED_RESULT;
447
448 V8_EXPORT_PRIVATE Handle<HeapObject> HeapConstantOf(const Operator* op)
449 V8_WARN_UNUSED_RESULT;
450
451 const StringConstantBase* StringConstantBaseOf(const Operator* op)
452 V8_WARN_UNUSED_RESULT;
453
454 const char* StaticAssertSourceOf(const Operator* op);
455
456 // Interface for building common operators that can be used at any level of IR,
457 // including JavaScript, mid-level, and low-level.
458 class V8_EXPORT_PRIVATE CommonOperatorBuilder final
NON_EXPORTED_BASE(ZoneObject)459 : public NON_EXPORTED_BASE(ZoneObject) {
460 public:
461 explicit CommonOperatorBuilder(Zone* zone);
462 CommonOperatorBuilder(const CommonOperatorBuilder&) = delete;
463 CommonOperatorBuilder& operator=(const CommonOperatorBuilder&) = delete;
464
465 const Operator* Dead();
466 const Operator* DeadValue(MachineRepresentation rep);
467 const Operator* Unreachable();
468 const Operator* StaticAssert(const char* source);
469 const Operator* End(size_t control_input_count);
470 const Operator* Branch(BranchHint = BranchHint::kNone,
471 IsSafetyCheck = IsSafetyCheck::kSafetyCheck);
472 const Operator* IfTrue();
473 const Operator* IfFalse();
474 const Operator* IfSuccess();
475 const Operator* IfException();
476 const Operator* Switch(size_t control_output_count);
477 const Operator* IfValue(int32_t value, int32_t order = 0,
478 BranchHint hint = BranchHint::kNone);
479 const Operator* IfDefault(BranchHint hint = BranchHint::kNone);
480 const Operator* Throw();
481 const Operator* Deoptimize(DeoptimizeKind kind, DeoptimizeReason reason,
482 FeedbackSource const& feedback);
483 const Operator* DeoptimizeIf(
484 DeoptimizeKind kind, DeoptimizeReason reason,
485 FeedbackSource const& feedback,
486 IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck);
487 const Operator* DeoptimizeUnless(
488 DeoptimizeKind kind, DeoptimizeReason reason,
489 FeedbackSource const& feedback,
490 IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck);
491 const Operator* TrapIf(TrapId trap_id);
492 const Operator* TrapUnless(TrapId trap_id);
493 const Operator* Return(int value_input_count = 1);
494 const Operator* Terminate();
495
496 const Operator* Start(int value_output_count);
497 const Operator* Loop(int control_input_count);
498 const Operator* Merge(int control_input_count);
499 const Operator* Parameter(int index, const char* debug_name = nullptr);
500
501 const Operator* OsrValue(int index);
502
503 const Operator* Int32Constant(int32_t);
504 const Operator* Int64Constant(int64_t);
505 const Operator* TaggedIndexConstant(int32_t value);
506 const Operator* Float32Constant(volatile float);
507 const Operator* Float64Constant(volatile double);
508 const Operator* ExternalConstant(const ExternalReference&);
509 const Operator* NumberConstant(volatile double);
510 const Operator* PointerConstant(intptr_t);
511 const Operator* HeapConstant(const Handle<HeapObject>&);
512 const Operator* CompressedHeapConstant(const Handle<HeapObject>&);
513 const Operator* ObjectId(uint32_t);
514
515 const Operator* RelocatableInt32Constant(int32_t value,
516 RelocInfo::Mode rmode);
517 const Operator* RelocatableInt64Constant(int64_t value,
518 RelocInfo::Mode rmode);
519
520 const Operator* Select(MachineRepresentation, BranchHint = BranchHint::kNone);
521 const Operator* Phi(MachineRepresentation representation,
522 int value_input_count);
523 const Operator* EffectPhi(int effect_input_count);
524 const Operator* InductionVariablePhi(int value_input_count);
525 const Operator* LoopExit();
526 const Operator* LoopExitValue();
527 const Operator* LoopExitEffect();
528 const Operator* Checkpoint();
529 const Operator* BeginRegion(RegionObservability);
530 const Operator* FinishRegion();
531 const Operator* StateValues(int arguments, SparseInputMask bitmask);
532 const Operator* TypedStateValues(const ZoneVector<MachineType>* types,
533 SparseInputMask bitmask);
534 const Operator* ArgumentsElementsState(ArgumentsStateType type);
535 const Operator* ArgumentsLengthState();
536 const Operator* ObjectState(uint32_t object_id, int pointer_slots);
537 const Operator* TypedObjectState(uint32_t object_id,
538 const ZoneVector<MachineType>* types);
539 const Operator* FrameState(BailoutId bailout_id,
540 OutputFrameStateCombine state_combine,
541 const FrameStateFunctionInfo* function_info);
542 const Operator* Call(const CallDescriptor* call_descriptor);
543 const Operator* TailCall(const CallDescriptor* call_descriptor);
544 const Operator* Projection(size_t index);
545 const Operator* Retain();
546 const Operator* TypeGuard(Type type);
547 const Operator* FoldConstant();
548
549 // Constructs a new merge or phi operator with the same opcode as {op}, but
550 // with {size} inputs.
551 const Operator* ResizeMergeOrPhi(const Operator* op, int size);
552
553 // Constructs function info for frame state construction.
554 const FrameStateFunctionInfo* CreateFrameStateFunctionInfo(
555 FrameStateType type, int parameter_count, int local_count,
556 Handle<SharedFunctionInfo> shared_info);
557
558 const Operator* MarkAsSafetyCheck(const Operator* op,
559 IsSafetyCheck safety_check);
560
561 const Operator* DelayedStringConstant(const StringConstantBase* str);
562
563 private:
564 Zone* zone() const { return zone_; }
565
566 const CommonOperatorGlobalCache& cache_;
567 Zone* const zone_;
568 };
569
570 // Node wrappers.
571
572 class CommonNodeWrapperBase : public NodeWrapper {
573 public:
CommonNodeWrapperBase(Node * node)574 explicit constexpr CommonNodeWrapperBase(Node* node) : NodeWrapper(node) {}
575
576 // Valid iff this node has exactly one effect input.
effect()577 Effect effect() const {
578 DCHECK_EQ(node()->op()->EffectInputCount(), 1);
579 return Effect{NodeProperties::GetEffectInput(node())};
580 }
581
582 // Valid iff this node has exactly one control input.
control()583 Control control() const {
584 DCHECK_EQ(node()->op()->ControlInputCount(), 1);
585 return Control{NodeProperties::GetControlInput(node())};
586 }
587 };
588
589 #define DEFINE_INPUT_ACCESSORS(Name, name, TheIndex, Type) \
590 static constexpr int Name##Index() { return TheIndex; } \
591 TNode<Type> name() const { \
592 return TNode<Type>::UncheckedCast( \
593 NodeProperties::GetValueInput(node(), TheIndex)); \
594 }
595
596 class StartNode final : public CommonNodeWrapperBase {
597 public:
StartNode(Node * node)598 explicit constexpr StartNode(Node* node) : CommonNodeWrapperBase(node) {
599 CONSTEXPR_DCHECK(node->opcode() == IrOpcode::kStart);
600 }
601
602 // The receiver is counted as part of formal parameters.
603 static constexpr int kReceiverOutputCount = 1;
604 // These outputs are in addition to formal parameters.
605 static constexpr int kExtraOutputCount = 4;
606
607 // Takes the formal parameter count of the current function (including
608 // receiver) and returns the number of value outputs of the start node.
OutputArityForFormalParameterCount(int argc)609 static constexpr int OutputArityForFormalParameterCount(int argc) {
610 constexpr int kClosure = 1;
611 constexpr int kNewTarget = 1;
612 constexpr int kArgCount = 1;
613 constexpr int kContext = 1;
614 STATIC_ASSERT(kClosure + kNewTarget + kArgCount + kContext ==
615 kExtraOutputCount);
616 // Checking related linkage methods here since they rely on Start node
617 // layout.
618 CONSTEXPR_DCHECK(Linkage::kJSCallClosureParamIndex == -1);
619 CONSTEXPR_DCHECK(Linkage::GetJSCallNewTargetParamIndex(argc) == argc + 0);
620 CONSTEXPR_DCHECK(Linkage::GetJSCallArgCountParamIndex(argc) == argc + 1);
621 CONSTEXPR_DCHECK(Linkage::GetJSCallContextParamIndex(argc) == argc + 2);
622 return argc + kClosure + kNewTarget + kArgCount + kContext;
623 }
624
FormalParameterCount()625 int FormalParameterCount() const {
626 DCHECK_GE(node()->op()->ValueOutputCount(),
627 kExtraOutputCount + kReceiverOutputCount);
628 return node()->op()->ValueOutputCount() - kExtraOutputCount;
629 }
630
FormalParameterCountWithoutReceiver()631 int FormalParameterCountWithoutReceiver() const {
632 DCHECK_GE(node()->op()->ValueOutputCount(),
633 kExtraOutputCount + kReceiverOutputCount);
634 return node()->op()->ValueOutputCount() - kExtraOutputCount -
635 kReceiverOutputCount;
636 }
637 };
638
639 #undef DEFINE_INPUT_ACCESSORS
640
641 } // namespace compiler
642 } // namespace internal
643 } // namespace v8
644
645 #endif // V8_COMPILER_COMMON_OPERATOR_H_
646