• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
10 #include "src/torque/ast.h"
11 #include "src/torque/source-positions.h"
12 #include "src/torque/types.h"
13 #include "src/torque/utils.h"
14 
15 namespace v8 {
16 namespace internal {
17 namespace torque {
18 
19 class Block;
20 class Builtin;
21 class ControlFlowGraph;
22 class Intrinsic;
23 class Macro;
24 class NamespaceConstant;
25 class RuntimeFunction;
26 
27 // Instructions where all backends generate code the same way.
28 #define TORQUE_BACKEND_AGNOSTIC_INSTRUCTION_LIST(V) \
29   V(PeekInstruction)                                \
30   V(PokeInstruction)                                \
31   V(DeleteRangeInstruction)
32 
33 // Instructions where different backends may generate different code.
34 #define TORQUE_BACKEND_DEPENDENT_INSTRUCTION_LIST(V) \
35   V(PushUninitializedInstruction)                    \
36   V(PushBuiltinPointerInstruction)                   \
37   V(LoadReferenceInstruction)                        \
38   V(StoreReferenceInstruction)                       \
39   V(LoadBitFieldInstruction)                         \
40   V(StoreBitFieldInstruction)                        \
41   V(CallCsaMacroInstruction)                         \
42   V(CallIntrinsicInstruction)                        \
43   V(NamespaceConstantInstruction)                    \
44   V(CallCsaMacroAndBranchInstruction)                \
45   V(CallBuiltinInstruction)                          \
46   V(CallRuntimeInstruction)                          \
47   V(CallBuiltinPointerInstruction)                   \
48   V(BranchInstruction)                               \
49   V(ConstexprBranchInstruction)                      \
50   V(GotoInstruction)                                 \
51   V(GotoExternalInstruction)                         \
52   V(ReturnInstruction)                               \
53   V(PrintConstantStringInstruction)                  \
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 
71 enum class InstructionKind {
72 #define ENUM_ITEM(name) k##name,
73   TORQUE_INSTRUCTION_LIST(ENUM_ITEM)
74 #undef ENUM_ITEM
75 };
76 
77 struct InstructionBase;
78 
79 class DefinitionLocation {
80  public:
81   enum class Kind {
82     kInvalid,
83     kParameter,
84     kPhi,
85     kInstruction,
86   };
87 
DefinitionLocation()88   DefinitionLocation() : kind_(Kind::kInvalid), location_(nullptr), index_(0) {}
89 
Parameter(std::size_t index)90   static DefinitionLocation Parameter(std::size_t index) {
91     return DefinitionLocation(Kind::kParameter, nullptr, index);
92   }
93 
Phi(const Block * block,std::size_t index)94   static DefinitionLocation Phi(const Block* block, std::size_t index) {
95     return DefinitionLocation(Kind::kPhi, block, index);
96   }
97 
98   static DefinitionLocation Instruction(const InstructionBase* instruction,
99                                         std::size_t index = 0) {
100     return DefinitionLocation(Kind::kInstruction, instruction, index);
101   }
102 
GetKind()103   Kind GetKind() const { return kind_; }
IsValid()104   bool IsValid() const { return kind_ != Kind::kInvalid; }
IsParameter()105   bool IsParameter() const { return kind_ == Kind::kParameter; }
IsPhi()106   bool IsPhi() const { return kind_ == Kind::kPhi; }
IsInstruction()107   bool IsInstruction() const { return kind_ == Kind::kInstruction; }
108 
GetParameterIndex()109   std::size_t GetParameterIndex() const {
110     DCHECK(IsParameter());
111     return index_;
112   }
113 
GetPhiBlock()114   const Block* GetPhiBlock() const {
115     DCHECK(IsPhi());
116     return reinterpret_cast<const Block*>(location_);
117   }
118 
IsPhiFromBlock(const Block * block)119   bool IsPhiFromBlock(const Block* block) const {
120     return IsPhi() && GetPhiBlock() == block;
121   }
122 
GetPhiIndex()123   std::size_t GetPhiIndex() const {
124     DCHECK(IsPhi());
125     return index_;
126   }
127 
GetInstruction()128   const InstructionBase* GetInstruction() const {
129     DCHECK(IsInstruction());
130     return reinterpret_cast<const InstructionBase*>(location_);
131   }
132 
GetInstructionIndex()133   std::size_t GetInstructionIndex() const {
134     DCHECK(IsInstruction());
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:
DefinitionLocation(Kind kind,const void * location,std::size_t index)159   DefinitionLocation(Kind kind, const void* location, std::size_t index)
160       : kind_(kind), location_(location), index_(index) {}
161 
162   Kind kind_;
163   const void* location_;
164   std::size_t index_;
165 };
166 
167 inline std::ostream& operator<<(std::ostream& stream,
168                                 const DefinitionLocation& loc) {
169   switch (loc.GetKind()) {
170     case DefinitionLocation::Kind::kInvalid:
171       return stream << "DefinitionLocation::Invalid()";
172     case DefinitionLocation::Kind::kParameter:
173       return stream << "DefinitionLocation::Parameter("
174                     << loc.GetParameterIndex() << ")";
175     case DefinitionLocation::Kind::kPhi:
176       return stream << "DefinitionLocation::Phi(" << std::hex
177                     << loc.GetPhiBlock() << std::dec << ", "
178                     << loc.GetPhiIndex() << ")";
179     case DefinitionLocation::Kind::kInstruction:
180       return stream << "DefinitionLocation::Instruction(" << std::hex
181                     << loc.GetInstruction() << std::dec << ", "
182                     << loc.GetInstructionIndex() << ")";
183   }
184 }
185 
186 struct InstructionBase {
InstructionBaseInstructionBase187   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 
192   virtual void TypeInstruction(Stack<const Type*>* stack,
193                                ControlFlowGraph* cfg) const = 0;
194   virtual void RecomputeDefinitionLocations(
195       Stack<DefinitionLocation>* locations,
196       Worklist<Block*>* worklist) const = 0;
197   void InvalidateTransientTypes(Stack<const Type*>* stack) const;
IsBlockTerminatorInstructionBase198   virtual bool IsBlockTerminator() const { return false; }
AppendSuccessorBlocksInstructionBase199   virtual void AppendSuccessorBlocks(std::vector<Block*>* block_list) const {}
200 
201   SourcePosition pos;
202 };
203 
204 class Instruction {
205  public:
206   template <class T>
Instruction(T instr)207   Instruction(T instr)  // NOLINT(runtime/explicit)
208       : kind_(T::kKind), instruction_(new T(std::move(instr))) {}
209 
210   template <class T>
Cast()211   T& Cast() {
212     DCHECK(Is<T>());
213     return static_cast<T&>(*instruction_);
214   }
215 
216   template <class T>
Cast()217   const T& Cast() const {
218     DCHECK(Is<T>());
219     return static_cast<const T&>(*instruction_);
220   }
221 
222   template <class T>
Is()223   bool Is() const {
224     return kind_ == T::kKind;
225   }
226 
227   template <class T>
DynamicCast()228   T* DynamicCast() {
229     if (Is<T>()) return &Cast<T>();
230     return nullptr;
231   }
232 
233   template <class T>
DynamicCast()234   const T* DynamicCast() const {
235     if (Is<T>()) return &Cast<T>();
236     return nullptr;
237   }
238 
Instruction(const Instruction & other)239   Instruction(const Instruction& other) V8_NOEXCEPT
240       : kind_(other.kind_),
241         instruction_(other.instruction_->Clone()) {}
242   Instruction& operator=(const Instruction& other) V8_NOEXCEPT {
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 
kind()252   InstructionKind kind() const { return kind_; }
Mnemonic()253   const char* Mnemonic() const {
254     switch (kind()) {
255 #define ENUM_ITEM(name)          \
256   case InstructionKind::k##name: \
257     return #name;
258       TORQUE_INSTRUCTION_LIST(ENUM_ITEM)
259 #undef ENUM_ITEM
260       default:
261         UNREACHABLE();
262     }
263   }
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg)264   void TypeInstruction(Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
265     return instruction_->TypeInstruction(stack, cfg);
266   }
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist)267   void RecomputeDefinitionLocations(Stack<DefinitionLocation>* locations,
268                                     Worklist<Block*>* worklist) const {
269     instruction_->RecomputeDefinitionLocations(locations, worklist);
270   }
271 
272   InstructionBase* operator->() { return instruction_.get(); }
273   const InstructionBase* operator->() const { return instruction_.get(); }
274 
275  private:
276   InstructionKind kind_;
277   std::unique_ptr<InstructionBase> instruction_;
278 };
279 
280 struct PeekInstruction : InstructionBase {
281   TORQUE_INSTRUCTION_BOILERPLATE()
282 
PeekInstructionPeekInstruction283   PeekInstruction(BottomOffset slot, base::Optional<const Type*> widened_type)
284       : slot(slot), widened_type(widened_type) {}
285 
286   BottomOffset slot;
287   base::Optional<const Type*> widened_type;
288 };
289 
290 struct PokeInstruction : InstructionBase {
291   TORQUE_INSTRUCTION_BOILERPLATE()
292 
PokeInstructionPokeInstruction293   PokeInstruction(BottomOffset slot, base::Optional<const Type*> widened_type)
294       : slot(slot), widened_type(widened_type) {}
295 
296   BottomOffset slot;
297   base::Optional<const Type*> widened_type;
298 };
299 
300 // Preserve the top {preserved_slots} number of slots, and delete
301 // {deleted_slots} number or slots below.
302 struct DeleteRangeInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATEDeleteRangeInstruction303   TORQUE_INSTRUCTION_BOILERPLATE()
304   explicit DeleteRangeInstruction(StackRange range) : range(range) {}
305 
306   StackRange range;
307 };
308 
309 struct PushUninitializedInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATEPushUninitializedInstruction310   TORQUE_INSTRUCTION_BOILERPLATE()
311   explicit PushUninitializedInstruction(const Type* type) : type(type) {}
312 
313   DefinitionLocation GetValueDefinition() const;
314 
315   const Type* type;
316 };
317 
318 struct PushBuiltinPointerInstruction : InstructionBase {
319   TORQUE_INSTRUCTION_BOILERPLATE()
PushBuiltinPointerInstructionPushBuiltinPointerInstruction320   PushBuiltinPointerInstruction(std::string external_name, const Type* type)
321       : external_name(std::move(external_name)), type(type) {
322     DCHECK(type->IsBuiltinPointerType());
323   }
324 
325   DefinitionLocation GetValueDefinition() const;
326 
327   std::string external_name;
328   const Type* type;
329 };
330 
331 struct NamespaceConstantInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATENamespaceConstantInstruction332   TORQUE_INSTRUCTION_BOILERPLATE()
333   explicit NamespaceConstantInstruction(NamespaceConstant* constant)
334       : constant(constant) {}
335 
336   std::size_t GetValueDefinitionCount() const;
337   DefinitionLocation GetValueDefinition(std::size_t index) const;
338 
339   NamespaceConstant* constant;
340 };
341 
342 struct LoadReferenceInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATELoadReferenceInstruction343   TORQUE_INSTRUCTION_BOILERPLATE()
344   explicit LoadReferenceInstruction(const Type* type) : type(type) {}
345 
346   DefinitionLocation GetValueDefinition() const;
347 
348   const Type* type;
349 };
350 
351 struct StoreReferenceInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATEStoreReferenceInstruction352   TORQUE_INSTRUCTION_BOILERPLATE()
353   explicit StoreReferenceInstruction(const Type* type) : type(type) {}
354   const Type* type;
355 };
356 
357 // Pops a bitfield struct; pushes a bitfield value extracted from it.
358 struct LoadBitFieldInstruction : InstructionBase {
359   TORQUE_INSTRUCTION_BOILERPLATE()
LoadBitFieldInstructionLoadBitFieldInstruction360   LoadBitFieldInstruction(const Type* bit_field_struct_type, BitField bit_field)
361       : bit_field_struct_type(bit_field_struct_type),
362         bit_field(std::move(bit_field)) {}
363 
364   DefinitionLocation GetValueDefinition() const;
365 
366   const Type* bit_field_struct_type;
367   BitField bit_field;
368 };
369 
370 // Pops a bitfield value and a bitfield struct; pushes a new bitfield struct
371 // containing the updated value.
372 struct StoreBitFieldInstruction : InstructionBase {
373   TORQUE_INSTRUCTION_BOILERPLATE()
StoreBitFieldInstructionStoreBitFieldInstruction374   StoreBitFieldInstruction(const Type* bit_field_struct_type,
375                            BitField bit_field, bool starts_as_zero)
376       : bit_field_struct_type(bit_field_struct_type),
377         bit_field(std::move(bit_field)),
378         starts_as_zero(starts_as_zero) {}
379 
380   DefinitionLocation GetValueDefinition() const;
381 
382   const Type* bit_field_struct_type;
383   BitField bit_field;
384   // Allows skipping the mask step if we know the starting value is zero.
385   bool starts_as_zero;
386 };
387 
388 struct CallIntrinsicInstruction : InstructionBase {
389   TORQUE_INSTRUCTION_BOILERPLATE()
CallIntrinsicInstructionCallIntrinsicInstruction390   CallIntrinsicInstruction(Intrinsic* intrinsic,
391                            TypeVector specialization_types,
392                            std::vector<std::string> constexpr_arguments)
393       : intrinsic(intrinsic),
394         specialization_types(std::move(specialization_types)),
395         constexpr_arguments(constexpr_arguments) {}
396 
397   std::size_t GetValueDefinitionCount() const;
398   DefinitionLocation GetValueDefinition(std::size_t index) const;
399 
400   Intrinsic* intrinsic;
401   TypeVector specialization_types;
402   std::vector<std::string> constexpr_arguments;
403 };
404 
405 struct CallCsaMacroInstruction : InstructionBase {
406   TORQUE_INSTRUCTION_BOILERPLATE()
CallCsaMacroInstructionCallCsaMacroInstruction407   CallCsaMacroInstruction(Macro* macro,
408                           std::vector<std::string> constexpr_arguments,
409                           base::Optional<Block*> catch_block)
410       : macro(macro),
411         constexpr_arguments(constexpr_arguments),
412         catch_block(catch_block) {}
AppendSuccessorBlocksCallCsaMacroInstruction413   void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
414     if (catch_block) block_list->push_back(*catch_block);
415   }
416 
417   base::Optional<DefinitionLocation> GetExceptionObjectDefinition() const;
418   std::size_t GetValueDefinitionCount() const;
419   DefinitionLocation GetValueDefinition(std::size_t index) const;
420 
421   Macro* macro;
422   std::vector<std::string> constexpr_arguments;
423   base::Optional<Block*> catch_block;
424 };
425 
426 struct CallCsaMacroAndBranchInstruction : InstructionBase {
427   TORQUE_INSTRUCTION_BOILERPLATE()
CallCsaMacroAndBranchInstructionCallCsaMacroAndBranchInstruction428   CallCsaMacroAndBranchInstruction(Macro* macro,
429                                    std::vector<std::string> constexpr_arguments,
430                                    base::Optional<Block*> return_continuation,
431                                    std::vector<Block*> label_blocks,
432                                    base::Optional<Block*> catch_block)
433       : macro(macro),
434         constexpr_arguments(constexpr_arguments),
435         return_continuation(return_continuation),
436         label_blocks(label_blocks),
437         catch_block(catch_block) {}
IsBlockTerminatorCallCsaMacroAndBranchInstruction438   bool IsBlockTerminator() const override { return true; }
AppendSuccessorBlocksCallCsaMacroAndBranchInstruction439   void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
440     if (catch_block) block_list->push_back(*catch_block);
441     if (return_continuation) block_list->push_back(*return_continuation);
442     for (Block* block : label_blocks) block_list->push_back(block);
443   }
444 
445   std::size_t GetLabelCount() const;
446   std::size_t GetLabelValueDefinitionCount(std::size_t label) const;
447   DefinitionLocation GetLabelValueDefinition(std::size_t label,
448                                              std::size_t index) const;
449   std::size_t GetValueDefinitionCount() const;
450   DefinitionLocation GetValueDefinition(std::size_t index) const;
451   base::Optional<DefinitionLocation> GetExceptionObjectDefinition() const;
452 
453   Macro* macro;
454   std::vector<std::string> constexpr_arguments;
455   base::Optional<Block*> return_continuation;
456   std::vector<Block*> label_blocks;
457   base::Optional<Block*> catch_block;
458 };
459 
460 struct CallBuiltinInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATECallBuiltinInstruction461   TORQUE_INSTRUCTION_BOILERPLATE()
462   bool IsBlockTerminator() const override { return is_tailcall; }
CallBuiltinInstructionCallBuiltinInstruction463   CallBuiltinInstruction(bool is_tailcall, Builtin* builtin, size_t argc,
464                          base::Optional<Block*> catch_block)
465       : is_tailcall(is_tailcall),
466         builtin(builtin),
467         argc(argc),
468         catch_block(catch_block) {}
AppendSuccessorBlocksCallBuiltinInstruction469   void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
470     if (catch_block) block_list->push_back(*catch_block);
471   }
472 
473   std::size_t GetValueDefinitionCount() const;
474   DefinitionLocation GetValueDefinition(std::size_t index) const;
475   base::Optional<DefinitionLocation> GetExceptionObjectDefinition() const;
476 
477   bool is_tailcall;
478   Builtin* builtin;
479   size_t argc;
480   base::Optional<Block*> catch_block;
481 };
482 
483 struct CallBuiltinPointerInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATECallBuiltinPointerInstruction484   TORQUE_INSTRUCTION_BOILERPLATE()
485   bool IsBlockTerminator() const override { return is_tailcall; }
CallBuiltinPointerInstructionCallBuiltinPointerInstruction486   CallBuiltinPointerInstruction(bool is_tailcall,
487                                 const BuiltinPointerType* type, size_t argc)
488       : is_tailcall(is_tailcall), type(type), argc(argc) {}
489 
490   std::size_t GetValueDefinitionCount() const;
491   DefinitionLocation GetValueDefinition(std::size_t index) const;
492 
493   bool is_tailcall;
494   const BuiltinPointerType* type;
495   size_t argc;
496 };
497 
498 struct CallRuntimeInstruction : InstructionBase {
499   TORQUE_INSTRUCTION_BOILERPLATE()
500   bool IsBlockTerminator() const override;
501 
CallRuntimeInstructionCallRuntimeInstruction502   CallRuntimeInstruction(bool is_tailcall, RuntimeFunction* runtime_function,
503                          size_t argc, base::Optional<Block*> catch_block)
504       : is_tailcall(is_tailcall),
505         runtime_function(runtime_function),
506         argc(argc),
507         catch_block(catch_block) {}
AppendSuccessorBlocksCallRuntimeInstruction508   void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
509     if (catch_block) block_list->push_back(*catch_block);
510   }
511 
512   std::size_t GetValueDefinitionCount() const;
513   DefinitionLocation GetValueDefinition(std::size_t index) const;
514   base::Optional<DefinitionLocation> GetExceptionObjectDefinition() const;
515 
516   bool is_tailcall;
517   RuntimeFunction* runtime_function;
518   size_t argc;
519   base::Optional<Block*> catch_block;
520 };
521 
522 struct BranchInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATEBranchInstruction523   TORQUE_INSTRUCTION_BOILERPLATE()
524   bool IsBlockTerminator() const override { return true; }
AppendSuccessorBlocksBranchInstruction525   void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
526     block_list->push_back(if_true);
527     block_list->push_back(if_false);
528   }
529 
BranchInstructionBranchInstruction530   BranchInstruction(Block* if_true, Block* if_false)
531       : if_true(if_true), if_false(if_false) {}
532 
533   Block* if_true;
534   Block* if_false;
535 };
536 
537 struct ConstexprBranchInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATEConstexprBranchInstruction538   TORQUE_INSTRUCTION_BOILERPLATE()
539   bool IsBlockTerminator() const override { return true; }
AppendSuccessorBlocksConstexprBranchInstruction540   void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
541     block_list->push_back(if_true);
542     block_list->push_back(if_false);
543   }
544 
ConstexprBranchInstructionConstexprBranchInstruction545   ConstexprBranchInstruction(std::string condition, Block* if_true,
546                              Block* if_false)
547       : condition(condition), if_true(if_true), if_false(if_false) {}
548 
549   std::string condition;
550   Block* if_true;
551   Block* if_false;
552 };
553 
554 struct GotoInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATEGotoInstruction555   TORQUE_INSTRUCTION_BOILERPLATE()
556   bool IsBlockTerminator() const override { return true; }
AppendSuccessorBlocksGotoInstruction557   void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
558     block_list->push_back(destination);
559   }
560 
GotoInstructionGotoInstruction561   explicit GotoInstruction(Block* destination) : destination(destination) {}
562 
563   Block* destination;
564 };
565 
566 struct GotoExternalInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATEGotoExternalInstruction567   TORQUE_INSTRUCTION_BOILERPLATE()
568   bool IsBlockTerminator() const override { return true; }
569 
GotoExternalInstructionGotoExternalInstruction570   GotoExternalInstruction(std::string destination,
571                           std::vector<std::string> variable_names)
572       : destination(std::move(destination)),
573         variable_names(std::move(variable_names)) {}
574 
575   std::string destination;
576   std::vector<std::string> variable_names;
577 };
578 
579 struct ReturnInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATEReturnInstruction580   TORQUE_INSTRUCTION_BOILERPLATE()
581   bool IsBlockTerminator() const override { return true; }
582 };
583 
584 struct PrintConstantStringInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATEPrintConstantStringInstruction585   TORQUE_INSTRUCTION_BOILERPLATE()
586   explicit PrintConstantStringInstruction(std::string message)
587       : message(std::move(message)) {}
588 
589   std::string message;
590 };
591 
592 struct AbortInstruction : InstructionBase {
593   TORQUE_INSTRUCTION_BOILERPLATE()
594   enum class Kind { kDebugBreak, kUnreachable, kAssertionFailure };
IsBlockTerminatorAbortInstruction595   bool IsBlockTerminator() const override { return kind != Kind::kDebugBreak; }
596   explicit AbortInstruction(Kind kind, std::string message = "")
kindAbortInstruction597       : kind(kind), message(std::move(message)) {}
598 
599   Kind kind;
600   std::string message;
601 };
602 
603 struct UnsafeCastInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATEUnsafeCastInstruction604   TORQUE_INSTRUCTION_BOILERPLATE()
605   explicit UnsafeCastInstruction(const Type* destination_type)
606       : destination_type(destination_type) {}
607 
608   DefinitionLocation GetValueDefinition() const;
609 
610   const Type* destination_type;
611 };
612 
613 }  // namespace torque
614 }  // namespace internal
615 }  // namespace v8
616 
617 #endif  // V8_TORQUE_INSTRUCTIONS_H_
618