v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
instructions.h
Go to the documentation of this file.
1// Copyright 2018 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_TORQUE_INSTRUCTIONS_H_
6#define V8_TORQUE_INSTRUCTIONS_H_
7
8#include <memory>
9#include <optional>
10
11#include "src/torque/ast.h"
13#include "src/torque/types.h"
14#include "src/torque/utils.h"
15
16namespace v8::internal::torque {
17
18class Block;
19class Builtin;
20class ControlFlowGraph;
21class Intrinsic;
22class Macro;
23class NamespaceConstant;
24class RuntimeFunction;
25
26// Instructions where all backends generate code the same way.
27#define TORQUE_BACKEND_AGNOSTIC_INSTRUCTION_LIST(V) \
28 V(PeekInstruction) \
29 V(PokeInstruction) \
30 V(DeleteRangeInstruction)
31
32// Instructions where different backends may generate different code.
33#define TORQUE_BACKEND_DEPENDENT_INSTRUCTION_LIST(V) \
34 V(PushUninitializedInstruction) \
35 V(PushBuiltinPointerInstruction) \
36 V(LoadReferenceInstruction) \
37 V(StoreReferenceInstruction) \
38 V(LoadBitFieldInstruction) \
39 V(StoreBitFieldInstruction) \
40 V(CallCsaMacroInstruction) \
41 V(CallIntrinsicInstruction) \
42 V(NamespaceConstantInstruction) \
43 V(CallCsaMacroAndBranchInstruction) \
44 V(CallBuiltinInstruction) \
45 V(CallRuntimeInstruction) \
46 V(CallBuiltinPointerInstruction) \
47 V(BranchInstruction) \
48 V(ConstexprBranchInstruction) \
49 V(GotoInstruction) \
50 V(GotoExternalInstruction) \
51 V(MakeLazyNodeInstruction) \
52 V(ReturnInstruction) \
53 V(PrintErrorInstruction) \
54 V(AbortInstruction) \
55 V(UnsafeCastInstruction)
56
57#define TORQUE_INSTRUCTION_LIST(V) \
58 TORQUE_BACKEND_AGNOSTIC_INSTRUCTION_LIST(V) \
59 TORQUE_BACKEND_DEPENDENT_INSTRUCTION_LIST(V)
60
61#define TORQUE_INSTRUCTION_BOILERPLATE() \
62 static const InstructionKind kKind; \
63 std::unique_ptr<InstructionBase> Clone() const override; \
64 void Assign(const InstructionBase& other) override; \
65 void TypeInstruction(Stack<const Type*>* stack, ControlFlowGraph* cfg) \
66 const override; \
67 void RecomputeDefinitionLocations(Stack<DefinitionLocation>* locations, \
68 Worklist<Block*>* worklist) \
69 const override;
70
71enum class InstructionKind {
72#define ENUM_ITEM(name) k##name,
74#undef ENUM_ITEM
75};
76
77struct InstructionBase;
78
80 public:
81 enum class Kind {
84 kPhi,
86 };
87
89
90 static DefinitionLocation Parameter(std::size_t index) {
91 return DefinitionLocation(Kind::kParameter, nullptr, index);
92 }
93
94 static DefinitionLocation Phi(const Block* block, std::size_t index) {
95 return DefinitionLocation(Kind::kPhi, block, index);
96 }
97
99 std::size_t index = 0) {
100 return DefinitionLocation(Kind::kInstruction, instruction, index);
101 }
102
103 Kind GetKind() const { return kind_; }
104 bool IsValid() const { return kind_ != Kind::kInvalid; }
105 bool IsParameter() const { return kind_ == Kind::kParameter; }
106 bool IsPhi() const { return kind_ == Kind::kPhi; }
107 bool IsInstruction() const { return kind_ == Kind::kInstruction; }
108
109 std::size_t GetParameterIndex() const {
111 return index_;
112 }
113
114 const Block* GetPhiBlock() const {
115 DCHECK(IsPhi());
116 return reinterpret_cast<const Block*>(location_);
117 }
118
119 bool IsPhiFromBlock(const Block* block) const {
120 return IsPhi() && GetPhiBlock() == block;
121 }
122
123 std::size_t GetPhiIndex() const {
124 DCHECK(IsPhi());
125 return index_;
126 }
127
130 return reinterpret_cast<const InstructionBase*>(location_);
131 }
132
133 std::size_t GetInstructionIndex() const {
135 return index_;
136 }
137
138 bool operator==(const DefinitionLocation& other) const {
139 if (kind_ != other.kind_) return false;
140 if (location_ != other.location_) return false;
141 return index_ == other.index_;
142 }
143
144 bool operator!=(const DefinitionLocation& other) const {
145 return !operator==(other);
146 }
147
148 bool operator<(const DefinitionLocation& other) const {
149 if (kind_ != other.kind_) {
150 return static_cast<int>(kind_) < static_cast<int>(other.kind_);
151 }
152 if (location_ != other.location_) {
153 return location_ < other.location_;
154 }
155 return index_ < other.index_;
156 }
157
158 private:
159 DefinitionLocation(Kind kind, const void* location, std::size_t index)
160 : kind_(kind), location_(location), index_(index) {}
161
163 const void* location_;
164 std::size_t index_;
165};
166
167inline std::ostream& operator<<(std::ostream& stream,
168 const DefinitionLocation& loc) {
169 switch (loc.GetKind()) {
171 return stream << "DefinitionLocation::Invalid()";
173 return stream << "DefinitionLocation::Parameter("
174 << loc.GetParameterIndex() << ")";
176 return stream << "DefinitionLocation::Phi(" << std::hex
177 << loc.GetPhiBlock() << std::dec << ", "
178 << loc.GetPhiIndex() << ")";
180 return stream << "DefinitionLocation::Instruction(" << std::hex
181 << loc.GetInstruction() << std::dec << ", "
182 << loc.GetInstructionIndex() << ")";
183 }
184}
185
187 InstructionBase() : pos(CurrentSourcePosition::Get()) {}
188 virtual std::unique_ptr<InstructionBase> Clone() const = 0;
189 virtual void Assign(const InstructionBase& other) = 0;
190 virtual ~InstructionBase() = default;
191
193 ControlFlowGraph* cfg) const = 0;
195 Stack<DefinitionLocation>* locations,
196 Worklist<Block*>* worklist) const = 0;
198 virtual bool IsBlockTerminator() const { return false; }
199 virtual void AppendSuccessorBlocks(std::vector<Block*>* block_list) const {}
200
202};
203
205 public:
206 template <class T>
207 Instruction(T instr) // NOLINT(runtime/explicit)
208 : kind_(T::kKind), instruction_(new T(std::move(instr))) {}
209
210 template <class T>
211 T& Cast() {
212 DCHECK(Is<T>());
213 return static_cast<T&>(*instruction_);
214 }
215
216 template <class T>
217 const T& Cast() const {
218 DCHECK(Is<T>());
219 return static_cast<const T&>(*instruction_);
220 }
221
222 template <class T>
223 bool Is() const {
224 return kind_ == T::kKind;
225 }
226
227 template <class T>
229 if (Is<T>()) return &Cast<T>();
230 return nullptr;
231 }
232
233 template <class T>
234 const T* DynamicCast() const {
235 if (Is<T>()) return &Cast<T>();
236 return nullptr;
237 }
238
240 : kind_(other.kind_),
241 instruction_(other.instruction_->Clone()) {}
243 if (kind_ == other.kind_) {
244 instruction_->Assign(*other.instruction_);
245 } else {
246 kind_ = other.kind_;
247 instruction_ = other.instruction_->Clone();
248 }
249 return *this;
250 }
251
252 InstructionKind kind() const { return kind_; }
253 const char* Mnemonic() const {
254 switch (kind()) {
255#define ENUM_ITEM(name) \
256 case InstructionKind::k##name: \
257 return #name;
259#undef ENUM_ITEM
260 default:
261 UNREACHABLE();
262 }
263 }
265 return instruction_->TypeInstruction(stack, cfg);
266 }
268 Worklist<Block*>* worklist) const {
269 instruction_->RecomputeDefinitionLocations(locations, worklist);
270 }
271
273 const InstructionBase* operator->() const { return instruction_.get(); }
274
275 private:
277 std::unique_ptr<InstructionBase> instruction_;
278};
279
289
290inline std::ostream& operator<<(std::ostream& os,
291 const PeekInstruction& instruction) {
292 os << "Peek " << instruction.slot;
293 if (instruction.widened_type) {
294 os << ", " << **instruction.widened_type;
295 }
296 return os;
297}
298
308
309inline std::ostream& operator<<(std::ostream& os,
310 const PokeInstruction& instruction) {
311 os << "Poke " << instruction.slot;
312 if (instruction.widened_type) {
313 os << ", " << **instruction.widened_type;
314 }
315 return os;
316}
317
318// Preserve the top {preserved_slots} number of slots, and delete
319// {deleted_slots} number or slots below.
326
327inline std::ostream& operator<<(std::ostream& os,
328 const DeleteRangeInstruction& instruction) {
329 return os << "DeleteRange " << instruction.range;
330}
331
340
341inline std::ostream& operator<<(
342 std::ostream& os, const PushUninitializedInstruction& instruction) {
343 return os << "PushUninitialized " << *instruction.type;
344}
345
349 : external_name(std::move(external_name)), type(type) {
350 DCHECK(type->IsBuiltinPointerType());
351 }
352
354
355 std::string external_name;
356 const Type* type;
357};
358
359inline std::ostream& operator<<(
360 std::ostream& os, const PushBuiltinPointerInstruction& instruction) {
361 return os << "PushBuiltinPointer "
362 << StringLiteralQuote(instruction.external_name) << ", "
363 << *instruction.type;
364}
365
369 : constant(constant) {}
370
371 std::size_t GetValueDefinitionCount() const;
372 DefinitionLocation GetValueDefinition(std::size_t index) const;
373
375};
376
377std::ostream& operator<<(std::ostream& os,
378 const NamespaceConstantInstruction& instruction);
379
391
392inline std::ostream& operator<<(std::ostream& os,
393 const LoadReferenceInstruction& instruction) {
394 return os << "LoadReference " << *instruction.type;
395}
396
402
403inline std::ostream& operator<<(std::ostream& os,
404 const StoreReferenceInstruction& instruction) {
405 return os << "StoreReference " << *instruction.type;
406}
407
408// Pops a bitfield struct; pushes a bitfield value extracted from it.
420
421inline std::ostream& operator<<(std::ostream& os,
422 const LoadBitFieldInstruction& instruction) {
423 return os << "LoadBitField " << *instruction.bit_field_struct_type << ", "
424 << instruction.bit_field.name_and_type.name;
425}
426
427// Pops a bitfield value and a bitfield struct; pushes a new bitfield struct
428// containing the updated value.
444
445inline std::ostream& operator<<(std::ostream& os,
446 const StoreBitFieldInstruction& instruction) {
447 os << "StoreBitField " << *instruction.bit_field_struct_type << ", "
448 << instruction.bit_field.name_and_type.name;
449 if (instruction.starts_as_zero) {
450 os << ", starts_as_zero";
451 }
452 return os;
453}
454
471
472std::ostream& operator<<(std::ostream& os,
473 const CallIntrinsicInstruction& instruction);
474
478 std::vector<std::string> constexpr_arguments,
479 std::optional<Block*> catch_block)
480 : macro(macro),
483 void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
484 if (catch_block) block_list->push_back(*catch_block);
485 }
486
487 std::optional<DefinitionLocation> GetExceptionObjectDefinition() const;
488 std::size_t GetValueDefinitionCount() const;
489 DefinitionLocation GetValueDefinition(std::size_t index) const;
490
492 std::vector<std::string> constexpr_arguments;
493 std::optional<Block*> catch_block;
494};
495
496std::ostream& operator<<(std::ostream& os,
497 const CallCsaMacroInstruction& instruction);
498
511 bool IsBlockTerminator() const override { return true; }
512 void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
513 if (catch_block) block_list->push_back(*catch_block);
514 if (return_continuation) block_list->push_back(*return_continuation);
515 for (Block* block : label_blocks) block_list->push_back(block);
516 }
517
518 std::size_t GetLabelCount() const;
519 std::size_t GetLabelValueDefinitionCount(std::size_t label) const;
521 std::size_t index) const;
522 std::size_t GetValueDefinitionCount() const;
523 DefinitionLocation GetValueDefinition(std::size_t index) const;
524 std::optional<DefinitionLocation> GetExceptionObjectDefinition() const;
525
527 std::vector<std::string> constexpr_arguments;
528 std::optional<Block*> return_continuation;
529 std::vector<Block*> label_blocks;
530 std::optional<Block*> catch_block;
531};
532
533std::ostream& operator<<(std::ostream& os,
534 const CallCsaMacroAndBranchInstruction& instruction);
535
550
551std::ostream& operator<<(std::ostream& os,
552 const MakeLazyNodeInstruction& instruction);
553
556 bool IsBlockTerminator() const override { return is_tailcall; }
558 std::optional<Block*> catch_block)
560 builtin(builtin),
561 argc(argc),
563 void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
564 if (catch_block) block_list->push_back(*catch_block);
565 }
566
567 std::size_t GetValueDefinitionCount() const;
568 DefinitionLocation GetValueDefinition(std::size_t index) const;
569 std::optional<DefinitionLocation> GetExceptionObjectDefinition() const;
570
573 size_t argc;
574 std::optional<Block*> catch_block;
575};
576
577std::ostream& operator<<(std::ostream& os,
578 const CallBuiltinInstruction& instruction);
579
582 bool IsBlockTerminator() const override { return is_tailcall; }
584 const BuiltinPointerType* type, size_t argc)
585 : is_tailcall(is_tailcall), type(type), argc(argc) {}
586
587 std::size_t GetValueDefinitionCount() const;
588 DefinitionLocation GetValueDefinition(std::size_t index) const;
589
592 size_t argc;
593};
594
595inline std::ostream& operator<<(
596 std::ostream& os, const CallBuiltinPointerInstruction& instruction) {
597 os << "CallBuiltinPointer " << *instruction.type
598 << ", argc: " << instruction.argc;
599 if (instruction.is_tailcall) {
600 os << ", is_tailcall";
601 }
602 return os;
603}
604
607 bool IsBlockTerminator() const override;
608
615 void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
616 if (catch_block) block_list->push_back(*catch_block);
617 }
618
619 std::size_t GetValueDefinitionCount() const;
620 DefinitionLocation GetValueDefinition(std::size_t index) const;
621 std::optional<DefinitionLocation> GetExceptionObjectDefinition() const;
622
625 size_t argc;
626 std::optional<Block*> catch_block;
627};
628
629std::ostream& operator<<(std::ostream& os,
630 const CallRuntimeInstruction& instruction);
631
634 bool IsBlockTerminator() const override { return true; }
635 void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
636 block_list->push_back(if_true);
637 block_list->push_back(if_false);
638 }
639
642
645};
646
647std::ostream& operator<<(std::ostream& os,
648 const BranchInstruction& instruction);
649
652 bool IsBlockTerminator() const override { return true; }
653 void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
654 block_list->push_back(if_true);
655 block_list->push_back(if_false);
656 }
657
661
662 std::string condition;
665};
666
667std::ostream& operator<<(std::ostream& os,
668 const ConstexprBranchInstruction& instruction);
669
672 bool IsBlockTerminator() const override { return true; }
673 void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
674 block_list->push_back(destination);
675 }
676
678
680};
681
682std::ostream& operator<<(std::ostream& os, const GotoInstruction& instruction);
683
686 bool IsBlockTerminator() const override { return true; }
687
689 std::vector<std::string> variable_names)
690 : destination(std::move(destination)),
692
693 std::string destination;
694 std::vector<std::string> variable_names;
695};
696
697inline std::ostream& operator<<(std::ostream& os,
698 const GotoExternalInstruction& instruction) {
699 os << "GotoExternal " << instruction.destination;
700 for (const std::string& name : instruction.variable_names) {
701 os << ", " << name;
702 }
703 return os;
704}
705
708 explicit ReturnInstruction(size_t count) : count(count) {}
709 bool IsBlockTerminator() const override { return true; }
710
711 size_t count; // How many values to return.
712};
713
714inline std::ostream& operator<<(std::ostream& os,
715 const ReturnInstruction& instruction) {
716 return os << "Return count: " << instruction.count;
717}
718
721 explicit PrintErrorInstruction(std::string message)
722 : message(std::move(message)) {}
723
724 std::string message;
725};
726
727inline std::ostream& operator<<(std::ostream& os,
728 const PrintErrorInstruction& instruction) {
729 return os << "PrintConstantString "
730 << StringLiteralQuote(instruction.message);
731}
732
736 bool IsBlockTerminator() const override { return kind != Kind::kDebugBreak; }
737 explicit AbortInstruction(Kind kind, std::string message = "")
738 : kind(kind), message(std::move(message)) {}
739 static const char* KindToString(Kind kind) {
740 switch (kind) {
742 return "kDebugBreak";
744 return "kUnreachable";
746 return "kAssertionFailure";
747 }
748 }
749
751 std::string message;
752};
753
754inline std::ostream& operator<<(std::ostream& os,
755 const AbortInstruction& instruction) {
756 return os << "Abort " << AbortInstruction::KindToString(instruction.kind)
757 << ", " << StringLiteralQuote(instruction.message);
758}
759
769
770inline std::ostream& operator<<(std::ostream& os,
771 const UnsafeCastInstruction& instruction) {
772 return os << "UnsafeCast " << *instruction.destination_type;
773}
774
775} // namespace v8::internal::torque
776
777#endif // V8_TORQUE_INSTRUCTIONS_H_
Builtins::Kind kind
Definition builtins.cc:40
bool operator==(const DefinitionLocation &other) const
bool IsPhiFromBlock(const Block *block) const
bool operator<(const DefinitionLocation &other) const
static DefinitionLocation Instruction(const InstructionBase *instruction, std::size_t index=0)
bool operator!=(const DefinitionLocation &other) const
static DefinitionLocation Parameter(std::size_t index)
static DefinitionLocation Phi(const Block *block, std::size_t index)
const InstructionBase * GetInstruction() const
DefinitionLocation(Kind kind, const void *location, std::size_t index)
std::unique_ptr< InstructionBase > instruction_
Instruction & operator=(const Instruction &other) V8_NOEXCEPT
void RecomputeDefinitionLocations(Stack< DefinitionLocation > *locations, Worklist< Block * > *worklist) const
const InstructionBase * operator->() const
void TypeInstruction(Stack< const Type * > *stack, ControlFlowGraph *cfg) const
Instruction(const Instruction &other) V8_NOEXCEPT
InstructionKind kind() const
Label label
#define TORQUE_INSTRUCTION_LIST(V)
#define TORQUE_INSTRUCTION_BOILERPLATE()
Instruction * instr
RpoNumber block
STL namespace.
V8_INLINE const Operation & Get(const Graph &graph, OpIndex index)
Definition graph.h:1231
std::ostream & operator<<(std::ostream &os, Identifier *id)
Definition ast.h:263
std::string StringLiteralQuote(const std::string &s)
Definition utils.cc:54
std::vector< const Type * > TypeVector
Definition types.h:85
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
Definition flags.cc:2086
Intrinsic
Definition v8-template.h:41
#define V8_NOEXCEPT
#define DCHECK(condition)
Definition logging.h:482
static const char * KindToString(Kind kind)
AbortInstruction(Kind kind, std::string message="")
bool IsBlockTerminator() const override
BranchInstruction(Block *if_true, Block *if_false)
void AppendSuccessorBlocks(std::vector< Block * > *block_list) const override
std::optional< DefinitionLocation > GetExceptionObjectDefinition() const
void AppendSuccessorBlocks(std::vector< Block * > *block_list) const override
DefinitionLocation GetValueDefinition(std::size_t index) const
CallBuiltinInstruction(bool is_tailcall, Builtin *builtin, size_t argc, std::optional< Block * > catch_block)
CallBuiltinPointerInstruction(bool is_tailcall, const BuiltinPointerType *type, size_t argc)
DefinitionLocation GetValueDefinition(std::size_t index) const
void AppendSuccessorBlocks(std::vector< Block * > *block_list) const override
DefinitionLocation GetValueDefinition(std::size_t index) const
std::optional< DefinitionLocation > GetExceptionObjectDefinition() const
DefinitionLocation GetLabelValueDefinition(std::size_t label, std::size_t index) const
std::size_t GetLabelValueDefinitionCount(std::size_t label) const
std::optional< DefinitionLocation > GetExceptionObjectDefinition() const
DefinitionLocation GetValueDefinition(std::size_t index) const
void AppendSuccessorBlocks(std::vector< Block * > *block_list) const override
std::vector< std::string > constexpr_arguments
std::vector< std::string > constexpr_arguments
DefinitionLocation GetValueDefinition(std::size_t index) const
CallRuntimeInstruction(bool is_tailcall, RuntimeFunction *runtime_function, size_t argc, std::optional< Block * > catch_block)
DefinitionLocation GetValueDefinition(std::size_t index) const
std::optional< DefinitionLocation > GetExceptionObjectDefinition() const
void AppendSuccessorBlocks(std::vector< Block * > *block_list) const override
void AppendSuccessorBlocks(std::vector< Block * > *block_list) const override
ConstexprBranchInstruction(std::string condition, Block *if_true, Block *if_false)
GotoExternalInstruction(std::string destination, std::vector< std::string > variable_names)
void AppendSuccessorBlocks(std::vector< Block * > *block_list) const override
bool IsBlockTerminator() const override
virtual void RecomputeDefinitionLocations(Stack< DefinitionLocation > *locations, Worklist< Block * > *worklist) const =0
void InvalidateTransientTypes(Stack< const Type * > *stack) const
virtual void Assign(const InstructionBase &other)=0
virtual void TypeInstruction(Stack< const Type * > *stack, ControlFlowGraph *cfg) const =0
virtual std::unique_ptr< InstructionBase > Clone() const =0
virtual void AppendSuccessorBlocks(std::vector< Block * > *block_list) const
DefinitionLocation GetValueDefinition() const
std::vector< std::string > constexpr_arguments
DefinitionLocation GetValueDefinition() const
DefinitionLocation GetValueDefinition(std::size_t index) const
std::optional< const Type * > widened_type
std::optional< const Type * > widened_type
DefinitionLocation GetValueDefinition() const