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(MakeLazyNodeInstruction) \ 53 V(ReturnInstruction) \ 54 V(PrintConstantStringInstruction) \ 55 V(AbortInstruction) \ 56 V(UnsafeCastInstruction) 57 58 #define TORQUE_INSTRUCTION_LIST(V) \ 59 TORQUE_BACKEND_AGNOSTIC_INSTRUCTION_LIST(V) \ 60 TORQUE_BACKEND_DEPENDENT_INSTRUCTION_LIST(V) 61 62 #define TORQUE_INSTRUCTION_BOILERPLATE() \ 63 static const InstructionKind kKind; \ 64 std::unique_ptr<InstructionBase> Clone() const override; \ 65 void Assign(const InstructionBase& other) override; \ 66 void TypeInstruction(Stack<const Type*>* stack, ControlFlowGraph* cfg) \ 67 const override; \ 68 void RecomputeDefinitionLocations(Stack<DefinitionLocation>* locations, \ 69 Worklist<Block*>* worklist) \ 70 const override; 71 72 enum class InstructionKind { 73 #define ENUM_ITEM(name) k##name, 74 TORQUE_INSTRUCTION_LIST(ENUM_ITEM) 75 #undef ENUM_ITEM 76 }; 77 78 struct InstructionBase; 79 80 class DefinitionLocation { 81 public: 82 enum class Kind { 83 kInvalid, 84 kParameter, 85 kPhi, 86 kInstruction, 87 }; 88 DefinitionLocation()89 DefinitionLocation() : kind_(Kind::kInvalid), location_(nullptr), index_(0) {} 90 Parameter(std::size_t index)91 static DefinitionLocation Parameter(std::size_t index) { 92 return DefinitionLocation(Kind::kParameter, nullptr, index); 93 } 94 Phi(const Block * block,std::size_t index)95 static DefinitionLocation Phi(const Block* block, std::size_t index) { 96 return DefinitionLocation(Kind::kPhi, block, index); 97 } 98 99 static DefinitionLocation Instruction(const InstructionBase* instruction, 100 std::size_t index = 0) { 101 return DefinitionLocation(Kind::kInstruction, instruction, index); 102 } 103 GetKind()104 Kind GetKind() const { return kind_; } IsValid()105 bool IsValid() const { return kind_ != Kind::kInvalid; } IsParameter()106 bool IsParameter() const { return kind_ == Kind::kParameter; } IsPhi()107 bool IsPhi() const { return kind_ == Kind::kPhi; } IsInstruction()108 bool IsInstruction() const { return kind_ == Kind::kInstruction; } 109 GetParameterIndex()110 std::size_t GetParameterIndex() const { 111 DCHECK(IsParameter()); 112 return index_; 113 } 114 GetPhiBlock()115 const Block* GetPhiBlock() const { 116 DCHECK(IsPhi()); 117 return reinterpret_cast<const Block*>(location_); 118 } 119 IsPhiFromBlock(const Block * block)120 bool IsPhiFromBlock(const Block* block) const { 121 return IsPhi() && GetPhiBlock() == block; 122 } 123 GetPhiIndex()124 std::size_t GetPhiIndex() const { 125 DCHECK(IsPhi()); 126 return index_; 127 } 128 GetInstruction()129 const InstructionBase* GetInstruction() const { 130 DCHECK(IsInstruction()); 131 return reinterpret_cast<const InstructionBase*>(location_); 132 } 133 GetInstructionIndex()134 std::size_t GetInstructionIndex() const { 135 DCHECK(IsInstruction()); 136 return index_; 137 } 138 139 bool operator==(const DefinitionLocation& other) const { 140 if (kind_ != other.kind_) return false; 141 if (location_ != other.location_) return false; 142 return index_ == other.index_; 143 } 144 145 bool operator!=(const DefinitionLocation& other) const { 146 return !operator==(other); 147 } 148 149 bool operator<(const DefinitionLocation& other) const { 150 if (kind_ != other.kind_) { 151 return static_cast<int>(kind_) < static_cast<int>(other.kind_); 152 } 153 if (location_ != other.location_) { 154 return location_ < other.location_; 155 } 156 return index_ < other.index_; 157 } 158 159 private: DefinitionLocation(Kind kind,const void * location,std::size_t index)160 DefinitionLocation(Kind kind, const void* location, std::size_t index) 161 : kind_(kind), location_(location), index_(index) {} 162 163 Kind kind_; 164 const void* location_; 165 std::size_t index_; 166 }; 167 168 inline std::ostream& operator<<(std::ostream& stream, 169 const DefinitionLocation& loc) { 170 switch (loc.GetKind()) { 171 case DefinitionLocation::Kind::kInvalid: 172 return stream << "DefinitionLocation::Invalid()"; 173 case DefinitionLocation::Kind::kParameter: 174 return stream << "DefinitionLocation::Parameter(" 175 << loc.GetParameterIndex() << ")"; 176 case DefinitionLocation::Kind::kPhi: 177 return stream << "DefinitionLocation::Phi(" << std::hex 178 << loc.GetPhiBlock() << std::dec << ", " 179 << loc.GetPhiIndex() << ")"; 180 case DefinitionLocation::Kind::kInstruction: 181 return stream << "DefinitionLocation::Instruction(" << std::hex 182 << loc.GetInstruction() << std::dec << ", " 183 << loc.GetInstructionIndex() << ")"; 184 } 185 } 186 187 struct InstructionBase { InstructionBaseInstructionBase188 InstructionBase() : pos(CurrentSourcePosition::Get()) {} 189 virtual std::unique_ptr<InstructionBase> Clone() const = 0; 190 virtual void Assign(const InstructionBase& other) = 0; 191 virtual ~InstructionBase() = default; 192 193 virtual void TypeInstruction(Stack<const Type*>* stack, 194 ControlFlowGraph* cfg) const = 0; 195 virtual void RecomputeDefinitionLocations( 196 Stack<DefinitionLocation>* locations, 197 Worklist<Block*>* worklist) const = 0; 198 void InvalidateTransientTypes(Stack<const Type*>* stack) const; IsBlockTerminatorInstructionBase199 virtual bool IsBlockTerminator() const { return false; } AppendSuccessorBlocksInstructionBase200 virtual void AppendSuccessorBlocks(std::vector<Block*>* block_list) const {} 201 202 SourcePosition pos; 203 }; 204 205 class Instruction { 206 public: 207 template <class T> Instruction(T instr)208 Instruction(T instr) // NOLINT(runtime/explicit) 209 : kind_(T::kKind), instruction_(new T(std::move(instr))) {} 210 211 template <class T> Cast()212 T& Cast() { 213 DCHECK(Is<T>()); 214 return static_cast<T&>(*instruction_); 215 } 216 217 template <class T> Cast()218 const T& Cast() const { 219 DCHECK(Is<T>()); 220 return static_cast<const T&>(*instruction_); 221 } 222 223 template <class T> Is()224 bool Is() const { 225 return kind_ == T::kKind; 226 } 227 228 template <class T> DynamicCast()229 T* DynamicCast() { 230 if (Is<T>()) return &Cast<T>(); 231 return nullptr; 232 } 233 234 template <class T> DynamicCast()235 const T* DynamicCast() const { 236 if (Is<T>()) return &Cast<T>(); 237 return nullptr; 238 } 239 Instruction(const Instruction & other)240 Instruction(const Instruction& other) V8_NOEXCEPT 241 : kind_(other.kind_), 242 instruction_(other.instruction_->Clone()) {} 243 Instruction& operator=(const Instruction& other) V8_NOEXCEPT { 244 if (kind_ == other.kind_) { 245 instruction_->Assign(*other.instruction_); 246 } else { 247 kind_ = other.kind_; 248 instruction_ = other.instruction_->Clone(); 249 } 250 return *this; 251 } 252 kind()253 InstructionKind kind() const { return kind_; } Mnemonic()254 const char* Mnemonic() const { 255 switch (kind()) { 256 #define ENUM_ITEM(name) \ 257 case InstructionKind::k##name: \ 258 return #name; 259 TORQUE_INSTRUCTION_LIST(ENUM_ITEM) 260 #undef ENUM_ITEM 261 default: 262 UNREACHABLE(); 263 } 264 } TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg)265 void TypeInstruction(Stack<const Type*>* stack, ControlFlowGraph* cfg) const { 266 return instruction_->TypeInstruction(stack, cfg); 267 } RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist)268 void RecomputeDefinitionLocations(Stack<DefinitionLocation>* locations, 269 Worklist<Block*>* worklist) const { 270 instruction_->RecomputeDefinitionLocations(locations, worklist); 271 } 272 273 InstructionBase* operator->() { return instruction_.get(); } 274 const InstructionBase* operator->() const { return instruction_.get(); } 275 276 private: 277 InstructionKind kind_; 278 std::unique_ptr<InstructionBase> instruction_; 279 }; 280 281 struct PeekInstruction : InstructionBase { 282 TORQUE_INSTRUCTION_BOILERPLATE() 283 PeekInstructionPeekInstruction284 PeekInstruction(BottomOffset slot, base::Optional<const Type*> widened_type) 285 : slot(slot), widened_type(widened_type) {} 286 287 BottomOffset slot; 288 base::Optional<const Type*> widened_type; 289 }; 290 291 inline std::ostream& operator<<(std::ostream& os, 292 const PeekInstruction& instruction) { 293 os << "Peek " << instruction.slot; 294 if (instruction.widened_type) { 295 os << ", " << **instruction.widened_type; 296 } 297 return os; 298 } 299 300 struct PokeInstruction : InstructionBase { 301 TORQUE_INSTRUCTION_BOILERPLATE() 302 PokeInstructionPokeInstruction303 PokeInstruction(BottomOffset slot, base::Optional<const Type*> widened_type) 304 : slot(slot), widened_type(widened_type) {} 305 306 BottomOffset slot; 307 base::Optional<const Type*> widened_type; 308 }; 309 310 inline std::ostream& operator<<(std::ostream& os, 311 const PokeInstruction& instruction) { 312 os << "Poke " << instruction.slot; 313 if (instruction.widened_type) { 314 os << ", " << **instruction.widened_type; 315 } 316 return os; 317 } 318 319 // Preserve the top {preserved_slots} number of slots, and delete 320 // {deleted_slots} number or slots below. 321 struct DeleteRangeInstruction : InstructionBase { TORQUE_INSTRUCTION_BOILERPLATEDeleteRangeInstruction322 TORQUE_INSTRUCTION_BOILERPLATE() 323 explicit DeleteRangeInstruction(StackRange range) : range(range) {} 324 325 StackRange range; 326 }; 327 328 inline std::ostream& operator<<(std::ostream& os, 329 const DeleteRangeInstruction& instruction) { 330 return os << "DeleteRange " << instruction.range; 331 } 332 333 struct PushUninitializedInstruction : InstructionBase { TORQUE_INSTRUCTION_BOILERPLATEPushUninitializedInstruction334 TORQUE_INSTRUCTION_BOILERPLATE() 335 explicit PushUninitializedInstruction(const Type* type) : type(type) {} 336 337 DefinitionLocation GetValueDefinition() const; 338 339 const Type* type; 340 }; 341 342 inline std::ostream& operator<<( 343 std::ostream& os, const PushUninitializedInstruction& instruction) { 344 return os << "PushUninitialized " << *instruction.type; 345 } 346 347 struct PushBuiltinPointerInstruction : InstructionBase { 348 TORQUE_INSTRUCTION_BOILERPLATE() PushBuiltinPointerInstructionPushBuiltinPointerInstruction349 PushBuiltinPointerInstruction(std::string external_name, const Type* type) 350 : external_name(std::move(external_name)), type(type) { 351 DCHECK(type->IsBuiltinPointerType()); 352 } 353 354 DefinitionLocation GetValueDefinition() const; 355 356 std::string external_name; 357 const Type* type; 358 }; 359 360 inline std::ostream& operator<<( 361 std::ostream& os, const PushBuiltinPointerInstruction& instruction) { 362 return os << "PushBuiltinPointer " 363 << StringLiteralQuote(instruction.external_name) << ", " 364 << *instruction.type; 365 } 366 367 struct NamespaceConstantInstruction : InstructionBase { TORQUE_INSTRUCTION_BOILERPLATENamespaceConstantInstruction368 TORQUE_INSTRUCTION_BOILERPLATE() 369 explicit NamespaceConstantInstruction(NamespaceConstant* constant) 370 : constant(constant) {} 371 372 std::size_t GetValueDefinitionCount() const; 373 DefinitionLocation GetValueDefinition(std::size_t index) const; 374 375 NamespaceConstant* constant; 376 }; 377 378 std::ostream& operator<<(std::ostream& os, 379 const NamespaceConstantInstruction& instruction); 380 381 struct LoadReferenceInstruction : InstructionBase { TORQUE_INSTRUCTION_BOILERPLATELoadReferenceInstruction382 TORQUE_INSTRUCTION_BOILERPLATE() 383 explicit LoadReferenceInstruction(const Type* type) : type(type) {} 384 385 DefinitionLocation GetValueDefinition() const; 386 387 const Type* type; 388 }; 389 390 inline std::ostream& operator<<(std::ostream& os, 391 const LoadReferenceInstruction& instruction) { 392 return os << "LoadReference " << *instruction.type; 393 } 394 395 struct StoreReferenceInstruction : InstructionBase { TORQUE_INSTRUCTION_BOILERPLATEStoreReferenceInstruction396 TORQUE_INSTRUCTION_BOILERPLATE() 397 explicit StoreReferenceInstruction(const Type* type) : type(type) {} 398 const Type* type; 399 }; 400 401 inline std::ostream& operator<<(std::ostream& os, 402 const StoreReferenceInstruction& instruction) { 403 return os << "StoreReference " << *instruction.type; 404 } 405 406 // Pops a bitfield struct; pushes a bitfield value extracted from it. 407 struct LoadBitFieldInstruction : InstructionBase { 408 TORQUE_INSTRUCTION_BOILERPLATE() LoadBitFieldInstructionLoadBitFieldInstruction409 LoadBitFieldInstruction(const Type* bit_field_struct_type, BitField bit_field) 410 : bit_field_struct_type(bit_field_struct_type), 411 bit_field(std::move(bit_field)) {} 412 413 DefinitionLocation GetValueDefinition() const; 414 415 const Type* bit_field_struct_type; 416 BitField bit_field; 417 }; 418 419 inline std::ostream& operator<<(std::ostream& os, 420 const LoadBitFieldInstruction& instruction) { 421 return os << "LoadBitField " << *instruction.bit_field_struct_type << ", " 422 << instruction.bit_field.name_and_type.name; 423 } 424 425 // Pops a bitfield value and a bitfield struct; pushes a new bitfield struct 426 // containing the updated value. 427 struct StoreBitFieldInstruction : InstructionBase { 428 TORQUE_INSTRUCTION_BOILERPLATE() StoreBitFieldInstructionStoreBitFieldInstruction429 StoreBitFieldInstruction(const Type* bit_field_struct_type, 430 BitField bit_field, bool starts_as_zero) 431 : bit_field_struct_type(bit_field_struct_type), 432 bit_field(std::move(bit_field)), 433 starts_as_zero(starts_as_zero) {} 434 435 DefinitionLocation GetValueDefinition() const; 436 437 const Type* bit_field_struct_type; 438 BitField bit_field; 439 // Allows skipping the mask step if we know the starting value is zero. 440 bool starts_as_zero; 441 }; 442 443 inline std::ostream& operator<<(std::ostream& os, 444 const StoreBitFieldInstruction& instruction) { 445 os << "StoreBitField " << *instruction.bit_field_struct_type << ", " 446 << instruction.bit_field.name_and_type.name; 447 if (instruction.starts_as_zero) { 448 os << ", starts_as_zero"; 449 } 450 return os; 451 } 452 453 struct CallIntrinsicInstruction : InstructionBase { 454 TORQUE_INSTRUCTION_BOILERPLATE() CallIntrinsicInstructionCallIntrinsicInstruction455 CallIntrinsicInstruction(Intrinsic* intrinsic, 456 TypeVector specialization_types, 457 std::vector<std::string> constexpr_arguments) 458 : intrinsic(intrinsic), 459 specialization_types(std::move(specialization_types)), 460 constexpr_arguments(constexpr_arguments) {} 461 462 std::size_t GetValueDefinitionCount() const; 463 DefinitionLocation GetValueDefinition(std::size_t index) const; 464 465 Intrinsic* intrinsic; 466 TypeVector specialization_types; 467 std::vector<std::string> constexpr_arguments; 468 }; 469 470 std::ostream& operator<<(std::ostream& os, 471 const CallIntrinsicInstruction& instruction); 472 473 struct CallCsaMacroInstruction : InstructionBase { 474 TORQUE_INSTRUCTION_BOILERPLATE() CallCsaMacroInstructionCallCsaMacroInstruction475 CallCsaMacroInstruction(Macro* macro, 476 std::vector<std::string> constexpr_arguments, 477 base::Optional<Block*> catch_block) 478 : macro(macro), 479 constexpr_arguments(constexpr_arguments), 480 catch_block(catch_block) {} AppendSuccessorBlocksCallCsaMacroInstruction481 void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override { 482 if (catch_block) block_list->push_back(*catch_block); 483 } 484 485 base::Optional<DefinitionLocation> GetExceptionObjectDefinition() const; 486 std::size_t GetValueDefinitionCount() const; 487 DefinitionLocation GetValueDefinition(std::size_t index) const; 488 489 Macro* macro; 490 std::vector<std::string> constexpr_arguments; 491 base::Optional<Block*> catch_block; 492 }; 493 494 std::ostream& operator<<(std::ostream& os, 495 const CallCsaMacroInstruction& instruction); 496 497 struct CallCsaMacroAndBranchInstruction : InstructionBase { 498 TORQUE_INSTRUCTION_BOILERPLATE() CallCsaMacroAndBranchInstructionCallCsaMacroAndBranchInstruction499 CallCsaMacroAndBranchInstruction(Macro* macro, 500 std::vector<std::string> constexpr_arguments, 501 base::Optional<Block*> return_continuation, 502 std::vector<Block*> label_blocks, 503 base::Optional<Block*> catch_block) 504 : macro(macro), 505 constexpr_arguments(constexpr_arguments), 506 return_continuation(return_continuation), 507 label_blocks(label_blocks), 508 catch_block(catch_block) {} IsBlockTerminatorCallCsaMacroAndBranchInstruction509 bool IsBlockTerminator() const override { return true; } AppendSuccessorBlocksCallCsaMacroAndBranchInstruction510 void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override { 511 if (catch_block) block_list->push_back(*catch_block); 512 if (return_continuation) block_list->push_back(*return_continuation); 513 for (Block* block : label_blocks) block_list->push_back(block); 514 } 515 516 std::size_t GetLabelCount() const; 517 std::size_t GetLabelValueDefinitionCount(std::size_t label) const; 518 DefinitionLocation GetLabelValueDefinition(std::size_t label, 519 std::size_t index) const; 520 std::size_t GetValueDefinitionCount() const; 521 DefinitionLocation GetValueDefinition(std::size_t index) const; 522 base::Optional<DefinitionLocation> GetExceptionObjectDefinition() const; 523 524 Macro* macro; 525 std::vector<std::string> constexpr_arguments; 526 base::Optional<Block*> return_continuation; 527 std::vector<Block*> label_blocks; 528 base::Optional<Block*> catch_block; 529 }; 530 531 std::ostream& operator<<(std::ostream& os, 532 const CallCsaMacroAndBranchInstruction& instruction); 533 534 struct MakeLazyNodeInstruction : InstructionBase { 535 TORQUE_INSTRUCTION_BOILERPLATE() MakeLazyNodeInstructionMakeLazyNodeInstruction536 MakeLazyNodeInstruction(Macro* macro, const Type* result_type, 537 std::vector<std::string> constexpr_arguments) 538 : macro(macro), 539 result_type(result_type), 540 constexpr_arguments(std::move(constexpr_arguments)) {} 541 542 DefinitionLocation GetValueDefinition() const; 543 544 Macro* macro; 545 const Type* result_type; 546 std::vector<std::string> constexpr_arguments; 547 }; 548 549 std::ostream& operator<<(std::ostream& os, 550 const MakeLazyNodeInstruction& instruction); 551 552 struct CallBuiltinInstruction : InstructionBase { TORQUE_INSTRUCTION_BOILERPLATECallBuiltinInstruction553 TORQUE_INSTRUCTION_BOILERPLATE() 554 bool IsBlockTerminator() const override { return is_tailcall; } CallBuiltinInstructionCallBuiltinInstruction555 CallBuiltinInstruction(bool is_tailcall, Builtin* builtin, size_t argc, 556 base::Optional<Block*> catch_block) 557 : is_tailcall(is_tailcall), 558 builtin(builtin), 559 argc(argc), 560 catch_block(catch_block) {} AppendSuccessorBlocksCallBuiltinInstruction561 void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override { 562 if (catch_block) block_list->push_back(*catch_block); 563 } 564 565 std::size_t GetValueDefinitionCount() const; 566 DefinitionLocation GetValueDefinition(std::size_t index) const; 567 base::Optional<DefinitionLocation> GetExceptionObjectDefinition() const; 568 569 bool is_tailcall; 570 Builtin* builtin; 571 size_t argc; 572 base::Optional<Block*> catch_block; 573 }; 574 575 std::ostream& operator<<(std::ostream& os, 576 const CallBuiltinInstruction& instruction); 577 578 struct CallBuiltinPointerInstruction : InstructionBase { TORQUE_INSTRUCTION_BOILERPLATECallBuiltinPointerInstruction579 TORQUE_INSTRUCTION_BOILERPLATE() 580 bool IsBlockTerminator() const override { return is_tailcall; } CallBuiltinPointerInstructionCallBuiltinPointerInstruction581 CallBuiltinPointerInstruction(bool is_tailcall, 582 const BuiltinPointerType* type, size_t argc) 583 : is_tailcall(is_tailcall), type(type), argc(argc) {} 584 585 std::size_t GetValueDefinitionCount() const; 586 DefinitionLocation GetValueDefinition(std::size_t index) const; 587 588 bool is_tailcall; 589 const BuiltinPointerType* type; 590 size_t argc; 591 }; 592 593 inline std::ostream& operator<<( 594 std::ostream& os, const CallBuiltinPointerInstruction& instruction) { 595 os << "CallBuiltinPointer " << *instruction.type 596 << ", argc: " << instruction.argc; 597 if (instruction.is_tailcall) { 598 os << ", is_tailcall"; 599 } 600 return os; 601 } 602 603 struct CallRuntimeInstruction : InstructionBase { 604 TORQUE_INSTRUCTION_BOILERPLATE() 605 bool IsBlockTerminator() const override; 606 CallRuntimeInstructionCallRuntimeInstruction607 CallRuntimeInstruction(bool is_tailcall, RuntimeFunction* runtime_function, 608 size_t argc, base::Optional<Block*> catch_block) 609 : is_tailcall(is_tailcall), 610 runtime_function(runtime_function), 611 argc(argc), 612 catch_block(catch_block) {} AppendSuccessorBlocksCallRuntimeInstruction613 void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override { 614 if (catch_block) block_list->push_back(*catch_block); 615 } 616 617 std::size_t GetValueDefinitionCount() const; 618 DefinitionLocation GetValueDefinition(std::size_t index) const; 619 base::Optional<DefinitionLocation> GetExceptionObjectDefinition() const; 620 621 bool is_tailcall; 622 RuntimeFunction* runtime_function; 623 size_t argc; 624 base::Optional<Block*> catch_block; 625 }; 626 627 std::ostream& operator<<(std::ostream& os, 628 const CallRuntimeInstruction& instruction); 629 630 struct BranchInstruction : InstructionBase { TORQUE_INSTRUCTION_BOILERPLATEBranchInstruction631 TORQUE_INSTRUCTION_BOILERPLATE() 632 bool IsBlockTerminator() const override { return true; } AppendSuccessorBlocksBranchInstruction633 void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override { 634 block_list->push_back(if_true); 635 block_list->push_back(if_false); 636 } 637 BranchInstructionBranchInstruction638 BranchInstruction(Block* if_true, Block* if_false) 639 : if_true(if_true), if_false(if_false) {} 640 641 Block* if_true; 642 Block* if_false; 643 }; 644 645 std::ostream& operator<<(std::ostream& os, 646 const BranchInstruction& instruction); 647 648 struct ConstexprBranchInstruction : InstructionBase { TORQUE_INSTRUCTION_BOILERPLATEConstexprBranchInstruction649 TORQUE_INSTRUCTION_BOILERPLATE() 650 bool IsBlockTerminator() const override { return true; } AppendSuccessorBlocksConstexprBranchInstruction651 void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override { 652 block_list->push_back(if_true); 653 block_list->push_back(if_false); 654 } 655 ConstexprBranchInstructionConstexprBranchInstruction656 ConstexprBranchInstruction(std::string condition, Block* if_true, 657 Block* if_false) 658 : condition(condition), if_true(if_true), if_false(if_false) {} 659 660 std::string condition; 661 Block* if_true; 662 Block* if_false; 663 }; 664 665 std::ostream& operator<<(std::ostream& os, 666 const ConstexprBranchInstruction& instruction); 667 668 struct GotoInstruction : InstructionBase { TORQUE_INSTRUCTION_BOILERPLATEGotoInstruction669 TORQUE_INSTRUCTION_BOILERPLATE() 670 bool IsBlockTerminator() const override { return true; } AppendSuccessorBlocksGotoInstruction671 void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override { 672 block_list->push_back(destination); 673 } 674 GotoInstructionGotoInstruction675 explicit GotoInstruction(Block* destination) : destination(destination) {} 676 677 Block* destination; 678 }; 679 680 std::ostream& operator<<(std::ostream& os, const GotoInstruction& instruction); 681 682 struct GotoExternalInstruction : InstructionBase { TORQUE_INSTRUCTION_BOILERPLATEGotoExternalInstruction683 TORQUE_INSTRUCTION_BOILERPLATE() 684 bool IsBlockTerminator() const override { return true; } 685 GotoExternalInstructionGotoExternalInstruction686 GotoExternalInstruction(std::string destination, 687 std::vector<std::string> variable_names) 688 : destination(std::move(destination)), 689 variable_names(std::move(variable_names)) {} 690 691 std::string destination; 692 std::vector<std::string> variable_names; 693 }; 694 695 inline std::ostream& operator<<(std::ostream& os, 696 const GotoExternalInstruction& instruction) { 697 os << "GotoExternal " << instruction.destination; 698 for (const std::string& name : instruction.variable_names) { 699 os << ", " << name; 700 } 701 return os; 702 } 703 704 struct ReturnInstruction : InstructionBase { TORQUE_INSTRUCTION_BOILERPLATEReturnInstruction705 TORQUE_INSTRUCTION_BOILERPLATE() 706 explicit ReturnInstruction(size_t count) : count(count) {} IsBlockTerminatorReturnInstruction707 bool IsBlockTerminator() const override { return true; } 708 709 size_t count; // How many values to return. 710 }; 711 712 inline std::ostream& operator<<(std::ostream& os, 713 const ReturnInstruction& instruction) { 714 return os << "Return count: " << instruction.count; 715 } 716 717 struct PrintConstantStringInstruction : InstructionBase { TORQUE_INSTRUCTION_BOILERPLATEPrintConstantStringInstruction718 TORQUE_INSTRUCTION_BOILERPLATE() 719 explicit PrintConstantStringInstruction(std::string message) 720 : message(std::move(message)) {} 721 722 std::string message; 723 }; 724 725 inline std::ostream& operator<<( 726 std::ostream& os, const PrintConstantStringInstruction& instruction) { 727 return os << "PrintConstantString " 728 << StringLiteralQuote(instruction.message); 729 } 730 731 struct AbortInstruction : InstructionBase { 732 TORQUE_INSTRUCTION_BOILERPLATE() 733 enum class Kind { kDebugBreak, kUnreachable, kAssertionFailure }; IsBlockTerminatorAbortInstruction734 bool IsBlockTerminator() const override { return kind != Kind::kDebugBreak; } 735 explicit AbortInstruction(Kind kind, std::string message = "") kindAbortInstruction736 : kind(kind), message(std::move(message)) {} KindToStringAbortInstruction737 static const char* KindToString(Kind kind) { 738 switch (kind) { 739 case Kind::kDebugBreak: 740 return "kDebugBreak"; 741 case Kind::kUnreachable: 742 return "kUnreachable"; 743 case Kind::kAssertionFailure: 744 return "kAssertionFailure"; 745 } 746 } 747 748 Kind kind; 749 std::string message; 750 }; 751 752 inline std::ostream& operator<<(std::ostream& os, 753 const AbortInstruction& instruction) { 754 return os << "Abort " << AbortInstruction::KindToString(instruction.kind) 755 << ", " << StringLiteralQuote(instruction.message); 756 } 757 758 struct UnsafeCastInstruction : InstructionBase { TORQUE_INSTRUCTION_BOILERPLATEUnsafeCastInstruction759 TORQUE_INSTRUCTION_BOILERPLATE() 760 explicit UnsafeCastInstruction(const Type* destination_type) 761 : destination_type(destination_type) {} 762 763 DefinitionLocation GetValueDefinition() const; 764 765 const Type* destination_type; 766 }; 767 768 inline std::ostream& operator<<(std::ostream& os, 769 const UnsafeCastInstruction& instruction) { 770 return os << "UnsafeCast " << *instruction.destination_type; 771 } 772 773 } // namespace torque 774 } // namespace internal 775 } // namespace v8 776 777 #endif // V8_TORQUE_INSTRUCTIONS_H_ 778