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