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