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
15namespace v8 {
16namespace internal {
17namespace torque {
18
19class Block;
20class Builtin;
21class ControlFlowGraph;
22class Intrinsic;
23class Macro;
24class NamespaceConstant;
25class RuntimeFunction;
26
27#define TORQUE_INSTRUCTION_LIST(V) \
28 V(PeekInstruction) \
29 V(PokeInstruction) \
30 V(DeleteRangeInstruction) \
31 V(PushUninitializedInstruction) \
32 V(PushBuiltinPointerInstruction) \
33 V(CreateFieldReferenceInstruction) \
34 V(LoadReferenceInstruction) \
35 V(StoreReferenceInstruction) \
36 V(CallCsaMacroInstruction) \
37 V(CallIntrinsicInstruction) \
38 V(NamespaceConstantInstruction) \
39 V(CallCsaMacroAndBranchInstruction) \
40 V(CallBuiltinInstruction) \
41 V(CallRuntimeInstruction) \
42 V(CallBuiltinPointerInstruction) \
43 V(BranchInstruction) \
44 V(ConstexprBranchInstruction) \
45 V(GotoInstruction) \
46 V(GotoExternalInstruction) \
47 V(ReturnInstruction) \
48 V(PrintConstantStringInstruction) \
49 V(AbortInstruction) \
50 V(UnsafeCastInstruction)
51
52#define TORQUE_INSTRUCTION_BOILERPLATE() \
53 static const InstructionKind kKind; \
54 std::unique_ptr<InstructionBase> Clone() const override; \
55 void Assign(const InstructionBase& other) override; \
56 void TypeInstruction(Stack<const Type*>* stack, ControlFlowGraph* cfg) \
57 const override;
58
59enum class InstructionKind {
60#define ENUM_ITEM(name) k##name,
61 TORQUE_INSTRUCTION_LIST(ENUM_ITEM)
62#undef ENUM_ITEM
63};
64
65struct InstructionBase {
66 InstructionBase() : pos(CurrentSourcePosition::Get()) {}
67 virtual std::unique_ptr<InstructionBase> Clone() const = 0;
68 virtual void Assign(const InstructionBase& other) = 0;
69 virtual ~InstructionBase() = default;
70
71 virtual void TypeInstruction(Stack<const Type*>* stack,
72 ControlFlowGraph* cfg) const = 0;
73 void InvalidateTransientTypes(Stack<const Type*>* stack) const;
74 virtual bool IsBlockTerminator() const { return false; }
75 virtual void AppendSuccessorBlocks(std::vector<Block*>* block_list) const {}
76
77 SourcePosition pos;
78};
79
80class Instruction {
81 public:
82 template <class T>
83 Instruction(T instr) // NOLINT(runtime/explicit)
84 : kind_(T::kKind), instruction_(new T(std::move(instr))) {}
85
86 template <class T>
87 T& Cast() {
88 DCHECK(Is<T>());
89 return static_cast<T&>(*instruction_);
90 }
91
92 template <class T>
93 const T& Cast() const {
94 DCHECK(Is<T>());
95 return static_cast<const T&>(*instruction_);
96 }
97
98 template <class T>
99 bool Is() const {
100 return kind_ == T::kKind;
101 }
102
103 template <class T>
104 T* DynamicCast() {
105 if (Is<T>()) return &Cast<T>();
106 return nullptr;
107 }
108
109 template <class T>
110 const T* DynamicCast() const {
111 if (Is<T>()) return &Cast<T>();
112 return nullptr;
113 }
114
115 Instruction(const Instruction& other) V8_NOEXCEPT
116 : kind_(other.kind_),
117 instruction_(other.instruction_->Clone()) {}
118 Instruction& operator=(const Instruction& other) V8_NOEXCEPT {
119 if (kind_ == other.kind_) {
120 instruction_->Assign(*other.instruction_);
121 } else {
122 kind_ = other.kind_;
123 instruction_ = other.instruction_->Clone();
124 }
125 return *this;
126 }
127
128 InstructionKind kind() const { return kind_; }
129 const char* Mnemonic() const {
130 switch (kind()) {
131#define ENUM_ITEM(name) \
132 case InstructionKind::k##name: \
133 return #name;
134 TORQUE_INSTRUCTION_LIST(ENUM_ITEM)
135#undef ENUM_ITEM
136 default:
137 UNREACHABLE();
138 }
139 }
140 void TypeInstruction(Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
141 return instruction_->TypeInstruction(stack, cfg);
142 }
143
144 InstructionBase* operator->() { return instruction_.get(); }
145 const InstructionBase* operator->() const { return instruction_.get(); }
146
147 private:
148 InstructionKind kind_;
149 std::unique_ptr<InstructionBase> instruction_;
150};
151
152struct PeekInstruction : InstructionBase {
153 TORQUE_INSTRUCTION_BOILERPLATE()
154
155 PeekInstruction(BottomOffset slot, base::Optional<const Type*> widened_type)
156 : slot(slot), widened_type(widened_type) {}
157
158 BottomOffset slot;
159 base::Optional<const Type*> widened_type;
160};
161
162struct PokeInstruction : InstructionBase {
163 TORQUE_INSTRUCTION_BOILERPLATE()
164
165 PokeInstruction(BottomOffset slot, base::Optional<const Type*> widened_type)
166 : slot(slot), widened_type(widened_type) {}
167
168 BottomOffset slot;
169 base::Optional<const Type*> widened_type;
170};
171
172// Preserve the top {preserved_slots} number of slots, and delete
173// {deleted_slots} number or slots below.
174struct DeleteRangeInstruction : InstructionBase {
175 TORQUE_INSTRUCTION_BOILERPLATE()
176 explicit DeleteRangeInstruction(StackRange range) : range(range) {}
177
178 StackRange range;
179};
180
181struct PushUninitializedInstruction : InstructionBase {
182 TORQUE_INSTRUCTION_BOILERPLATE()
183 explicit PushUninitializedInstruction(const Type* type) : type(type) {}
184
185 const Type* type;
186};
187
188struct PushBuiltinPointerInstruction : InstructionBase {
189 TORQUE_INSTRUCTION_BOILERPLATE()
190 PushBuiltinPointerInstruction(std::string external_name, const Type* type)
191 : external_name(std::move(external_name)), type(type) {
192 DCHECK(type->IsBuiltinPointerType());
193 }
194
195 std::string external_name;
196 const Type* type;
197};
198
199struct NamespaceConstantInstruction : InstructionBase {
200 TORQUE_INSTRUCTION_BOILERPLATE()
201 explicit NamespaceConstantInstruction(NamespaceConstant* constant)
202 : constant(constant) {}
203
204 NamespaceConstant* constant;
205};
206
207struct CreateFieldReferenceInstruction : InstructionBase {
208 TORQUE_INSTRUCTION_BOILERPLATE()
209 CreateFieldReferenceInstruction(const ClassType* class_type,
210 std::string field_name)
211 : class_type(class_type), field_name(std::move(field_name)) {}
212 const ClassType* class_type;
213 std::string field_name;
214};
215
216struct LoadReferenceInstruction : InstructionBase {
217 TORQUE_INSTRUCTION_BOILERPLATE()
218 explicit LoadReferenceInstruction(const Type* type) : type(type) {}
219 const Type* type;
220};
221
222struct StoreReferenceInstruction : InstructionBase {
223 TORQUE_INSTRUCTION_BOILERPLATE()
224 explicit StoreReferenceInstruction(const Type* type) : type(type) {}
225 const Type* type;
226};
227
228struct CallIntrinsicInstruction : InstructionBase {
229 TORQUE_INSTRUCTION_BOILERPLATE()
230 CallIntrinsicInstruction(Intrinsic* intrinsic,
231 TypeVector specialization_types,
232 std::vector<std::string> constexpr_arguments)
233 : intrinsic(intrinsic),
234 specialization_types(std::move(specialization_types)),
235 constexpr_arguments(constexpr_arguments) {}
236
237 Intrinsic* intrinsic;
238 TypeVector specialization_types;
239 std::vector<std::string> constexpr_arguments;
240};
241
242struct CallCsaMacroInstruction : InstructionBase {
243 TORQUE_INSTRUCTION_BOILERPLATE()
244 CallCsaMacroInstruction(Macro* macro,
245 std::vector<std::string> constexpr_arguments,
246 base::Optional<Block*> catch_block)
247 : macro(macro),
248 constexpr_arguments(constexpr_arguments),
249 catch_block(catch_block) {}
250 void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
251 if (catch_block) block_list->push_back(*catch_block);
252 }
253
254 Macro* macro;
255 std::vector<std::string> constexpr_arguments;
256 base::Optional<Block*> catch_block;
257};
258
259struct CallCsaMacroAndBranchInstruction : InstructionBase {
260 TORQUE_INSTRUCTION_BOILERPLATE()
261 CallCsaMacroAndBranchInstruction(Macro* macro,
262 std::vector<std::string> constexpr_arguments,
263 base::Optional<Block*> return_continuation,
264 std::vector<Block*> label_blocks,
265 base::Optional<Block*> catch_block)
266 : macro(macro),
267 constexpr_arguments(constexpr_arguments),
268 return_continuation(return_continuation),
269 label_blocks(label_blocks),
270 catch_block(catch_block) {}
271 bool IsBlockTerminator() const override { return true; }
272 void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
273 if (catch_block) block_list->push_back(*catch_block);
274 if (return_continuation) block_list->push_back(*return_continuation);
275 for (Block* block : label_blocks) block_list->push_back(block);
276 }
277
278 Macro* macro;
279 std::vector<std::string> constexpr_arguments;
280 base::Optional<Block*> return_continuation;
281 std::vector<Block*> label_blocks;
282 base::Optional<Block*> catch_block;
283};
284
285struct CallBuiltinInstruction : InstructionBase {
286 TORQUE_INSTRUCTION_BOILERPLATE()
287 bool IsBlockTerminator() const override { return is_tailcall; }
288 CallBuiltinInstruction(bool is_tailcall, Builtin* builtin, size_t argc,
289 base::Optional<Block*> catch_block)
290 : is_tailcall(is_tailcall),
291 builtin(builtin),
292 argc(argc),
293 catch_block(catch_block) {}
294 void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
295 if (catch_block) block_list->push_back(*catch_block);
296 }
297
298 bool is_tailcall;
299 Builtin* builtin;
300 size_t argc;
301 base::Optional<Block*> catch_block;
302};
303
304struct CallBuiltinPointerInstruction : InstructionBase {
305 TORQUE_INSTRUCTION_BOILERPLATE()
306 bool IsBlockTerminator() const override { return is_tailcall; }
307 CallBuiltinPointerInstruction(bool is_tailcall,
308 const BuiltinPointerType* type, size_t argc)
309 : is_tailcall(is_tailcall), type(type), argc(argc) {}
310
311 bool is_tailcall;
312 const BuiltinPointerType* type;
313 size_t argc;
314};
315
316struct CallRuntimeInstruction : InstructionBase {
317 TORQUE_INSTRUCTION_BOILERPLATE()
318 bool IsBlockTerminator() const override;
319
320 CallRuntimeInstruction(bool is_tailcall, RuntimeFunction* runtime_function,
321 size_t argc, base::Optional<Block*> catch_block)
322 : is_tailcall(is_tailcall),
323 runtime_function(runtime_function),
324 argc(argc),
325 catch_block(catch_block) {}
326 void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
327 if (catch_block) block_list->push_back(*catch_block);
328 }
329
330 bool is_tailcall;
331 RuntimeFunction* runtime_function;
332 size_t argc;
333 base::Optional<Block*> catch_block;
334};
335
336struct BranchInstruction : InstructionBase {
337 TORQUE_INSTRUCTION_BOILERPLATE()
338 bool IsBlockTerminator() const override { return true; }
339 void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
340 block_list->push_back(if_true);
341 block_list->push_back(if_false);
342 }
343
344 BranchInstruction(Block* if_true, Block* if_false)
345 : if_true(if_true), if_false(if_false) {}
346
347 Block* if_true;
348 Block* if_false;
349};
350
351struct ConstexprBranchInstruction : InstructionBase {
352 TORQUE_INSTRUCTION_BOILERPLATE()
353 bool IsBlockTerminator() const override { return true; }
354 void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
355 block_list->push_back(if_true);
356 block_list->push_back(if_false);
357 }
358
359 ConstexprBranchInstruction(std::string condition, Block* if_true,
360 Block* if_false)
361 : condition(condition), if_true(if_true), if_false(if_false) {}
362
363 std::string condition;
364 Block* if_true;
365 Block* if_false;
366};
367
368struct GotoInstruction : InstructionBase {
369 TORQUE_INSTRUCTION_BOILERPLATE()
370 bool IsBlockTerminator() const override { return true; }
371 void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
372 block_list->push_back(destination);
373 }
374
375 explicit GotoInstruction(Block* destination) : destination(destination) {}
376
377 Block* destination;
378};
379
380struct GotoExternalInstruction : InstructionBase {
381 TORQUE_INSTRUCTION_BOILERPLATE()
382 bool IsBlockTerminator() const override { return true; }
383
384 GotoExternalInstruction(std::string destination,
385 std::vector<std::string> variable_names)
386 : destination(std::move(destination)),
387 variable_names(std::move(variable_names)) {}
388
389 std::string destination;
390 std::vector<std::string> variable_names;
391};
392
393struct ReturnInstruction : InstructionBase {
394 TORQUE_INSTRUCTION_BOILERPLATE()
395 bool IsBlockTerminator() const override { return true; }
396};
397
398struct PrintConstantStringInstruction : InstructionBase {
399 TORQUE_INSTRUCTION_BOILERPLATE()
400 explicit PrintConstantStringInstruction(std::string message)
401 : message(std::move(message)) {}
402
403 std::string message;
404};
405
406struct AbortInstruction : InstructionBase {
407 TORQUE_INSTRUCTION_BOILERPLATE()
408 enum class Kind { kDebugBreak, kUnreachable, kAssertionFailure };
409 bool IsBlockTerminator() const override { return kind != Kind::kDebugBreak; }
410 explicit AbortInstruction(Kind kind, std::string message = "")
411 : kind(kind), message(std::move(message)) {}
412
413 Kind kind;
414 std::string message;
415};
416
417struct UnsafeCastInstruction : InstructionBase {
418 TORQUE_INSTRUCTION_BOILERPLATE()
419 explicit UnsafeCastInstruction(const Type* destination_type)
420 : destination_type(destination_type) {}
421
422 const Type* destination_type;
423};
424
425} // namespace torque
426} // namespace internal
427} // namespace v8
428
429#endif // V8_TORQUE_INSTRUCTIONS_H_
430