blob: 3136b58321745823f4d6e7d96f27e8e25829edce [file] [log] [blame]
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_TORQUE_INSTRUCTIONS_H_
#define V8_TORQUE_INSTRUCTIONS_H_
#include <memory>
#include "src/torque/ast.h"
#include "src/torque/source-positions.h"
#include "src/torque/types.h"
#include "src/torque/utils.h"
namespace v8 {
namespace internal {
namespace torque {
class Block;
class Builtin;
class ControlFlowGraph;
class Intrinsic;
class Macro;
class NamespaceConstant;
class RuntimeFunction;
#define TORQUE_INSTRUCTION_LIST(V) \
V(PeekInstruction) \
V(PokeInstruction) \
V(DeleteRangeInstruction) \
V(PushUninitializedInstruction) \
V(PushBuiltinPointerInstruction) \
V(CreateFieldReferenceInstruction) \
V(LoadReferenceInstruction) \
V(StoreReferenceInstruction) \
V(CallCsaMacroInstruction) \
V(CallIntrinsicInstruction) \
V(NamespaceConstantInstruction) \
V(CallCsaMacroAndBranchInstruction) \
V(CallBuiltinInstruction) \
V(CallRuntimeInstruction) \
V(CallBuiltinPointerInstruction) \
V(BranchInstruction) \
V(ConstexprBranchInstruction) \
V(GotoInstruction) \
V(GotoExternalInstruction) \
V(ReturnInstruction) \
V(PrintConstantStringInstruction) \
V(AbortInstruction) \
V(UnsafeCastInstruction)
#define TORQUE_INSTRUCTION_BOILERPLATE() \
static const InstructionKind kKind; \
std::unique_ptr<InstructionBase> Clone() const override; \
void Assign(const InstructionBase& other) override; \
void TypeInstruction(Stack<const Type*>* stack, ControlFlowGraph* cfg) \
const override;
enum class InstructionKind {
#define ENUM_ITEM(name) k##name,
TORQUE_INSTRUCTION_LIST(ENUM_ITEM)
#undef ENUM_ITEM
};
struct InstructionBase {
InstructionBase() : pos(CurrentSourcePosition::Get()) {}
virtual std::unique_ptr<InstructionBase> Clone() const = 0;
virtual void Assign(const InstructionBase& other) = 0;
virtual ~InstructionBase() = default;
virtual void TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const = 0;
void InvalidateTransientTypes(Stack<const Type*>* stack) const;
virtual bool IsBlockTerminator() const { return false; }
virtual void AppendSuccessorBlocks(std::vector<Block*>* block_list) const {}
SourcePosition pos;
};
class Instruction {
public:
template <class T>
Instruction(T instr) // NOLINT(runtime/explicit)
: kind_(T::kKind), instruction_(new T(std::move(instr))) {}
template <class T>
T& Cast() {
DCHECK(Is<T>());
return static_cast<T&>(*instruction_);
}
template <class T>
const T& Cast() const {
DCHECK(Is<T>());
return static_cast<const T&>(*instruction_);
}
template <class T>
bool Is() const {
return kind_ == T::kKind;
}
template <class T>
T* DynamicCast() {
if (Is<T>()) return &Cast<T>();
return nullptr;
}
template <class T>
const T* DynamicCast() const {
if (Is<T>()) return &Cast<T>();
return nullptr;
}
Instruction(const Instruction& other) V8_NOEXCEPT
: kind_(other.kind_),
instruction_(other.instruction_->Clone()) {}
Instruction& operator=(const Instruction& other) V8_NOEXCEPT {
if (kind_ == other.kind_) {
instruction_->Assign(*other.instruction_);
} else {
kind_ = other.kind_;
instruction_ = other.instruction_->Clone();
}
return *this;
}
InstructionKind kind() const { return kind_; }
const char* Mnemonic() const {
switch (kind()) {
#define ENUM_ITEM(name) \
case InstructionKind::k##name: \
return #name;
TORQUE_INSTRUCTION_LIST(ENUM_ITEM)
#undef ENUM_ITEM
default:
UNREACHABLE();
}
}
void TypeInstruction(Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
return instruction_->TypeInstruction(stack, cfg);
}
InstructionBase* operator->() { return instruction_.get(); }
const InstructionBase* operator->() const { return instruction_.get(); }
private:
InstructionKind kind_;
std::unique_ptr<InstructionBase> instruction_;
};
struct PeekInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
PeekInstruction(BottomOffset slot, base::Optional<const Type*> widened_type)
: slot(slot), widened_type(widened_type) {}
BottomOffset slot;
base::Optional<const Type*> widened_type;
};
struct PokeInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
PokeInstruction(BottomOffset slot, base::Optional<const Type*> widened_type)
: slot(slot), widened_type(widened_type) {}
BottomOffset slot;
base::Optional<const Type*> widened_type;
};
// Preserve the top {preserved_slots} number of slots, and delete
// {deleted_slots} number or slots below.
struct DeleteRangeInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
explicit DeleteRangeInstruction(StackRange range) : range(range) {}
StackRange range;
};
struct PushUninitializedInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
explicit PushUninitializedInstruction(const Type* type) : type(type) {}
const Type* type;
};
struct PushBuiltinPointerInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
PushBuiltinPointerInstruction(std::string external_name, const Type* type)
: external_name(std::move(external_name)), type(type) {
DCHECK(type->IsBuiltinPointerType());
}
std::string external_name;
const Type* type;
};
struct NamespaceConstantInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
explicit NamespaceConstantInstruction(NamespaceConstant* constant)
: constant(constant) {}
NamespaceConstant* constant;
};
struct CreateFieldReferenceInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
CreateFieldReferenceInstruction(const ClassType* class_type,
std::string field_name)
: class_type(class_type), field_name(std::move(field_name)) {}
const ClassType* class_type;
std::string field_name;
};
struct LoadReferenceInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
explicit LoadReferenceInstruction(const Type* type) : type(type) {}
const Type* type;
};
struct StoreReferenceInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
explicit StoreReferenceInstruction(const Type* type) : type(type) {}
const Type* type;
};
struct CallIntrinsicInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
CallIntrinsicInstruction(Intrinsic* intrinsic,
TypeVector specialization_types,
std::vector<std::string> constexpr_arguments)
: intrinsic(intrinsic),
specialization_types(std::move(specialization_types)),
constexpr_arguments(constexpr_arguments) {}
Intrinsic* intrinsic;
TypeVector specialization_types;
std::vector<std::string> constexpr_arguments;
};
struct CallCsaMacroInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
CallCsaMacroInstruction(Macro* macro,
std::vector<std::string> constexpr_arguments,
base::Optional<Block*> catch_block)
: macro(macro),
constexpr_arguments(constexpr_arguments),
catch_block(catch_block) {}
void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
if (catch_block) block_list->push_back(*catch_block);
}
Macro* macro;
std::vector<std::string> constexpr_arguments;
base::Optional<Block*> catch_block;
};
struct CallCsaMacroAndBranchInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
CallCsaMacroAndBranchInstruction(Macro* macro,
std::vector<std::string> constexpr_arguments,
base::Optional<Block*> return_continuation,
std::vector<Block*> label_blocks,
base::Optional<Block*> catch_block)
: macro(macro),
constexpr_arguments(constexpr_arguments),
return_continuation(return_continuation),
label_blocks(label_blocks),
catch_block(catch_block) {}
bool IsBlockTerminator() const override { return true; }
void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
if (catch_block) block_list->push_back(*catch_block);
if (return_continuation) block_list->push_back(*return_continuation);
for (Block* block : label_blocks) block_list->push_back(block);
}
Macro* macro;
std::vector<std::string> constexpr_arguments;
base::Optional<Block*> return_continuation;
std::vector<Block*> label_blocks;
base::Optional<Block*> catch_block;
};
struct CallBuiltinInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
bool IsBlockTerminator() const override { return is_tailcall; }
CallBuiltinInstruction(bool is_tailcall, Builtin* builtin, size_t argc,
base::Optional<Block*> catch_block)
: is_tailcall(is_tailcall),
builtin(builtin),
argc(argc),
catch_block(catch_block) {}
void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
if (catch_block) block_list->push_back(*catch_block);
}
bool is_tailcall;
Builtin* builtin;
size_t argc;
base::Optional<Block*> catch_block;
};
struct CallBuiltinPointerInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
bool IsBlockTerminator() const override { return is_tailcall; }
CallBuiltinPointerInstruction(bool is_tailcall,
const BuiltinPointerType* type, size_t argc)
: is_tailcall(is_tailcall), type(type), argc(argc) {}
bool is_tailcall;
const BuiltinPointerType* type;
size_t argc;
};
struct CallRuntimeInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
bool IsBlockTerminator() const override;
CallRuntimeInstruction(bool is_tailcall, RuntimeFunction* runtime_function,
size_t argc, base::Optional<Block*> catch_block)
: is_tailcall(is_tailcall),
runtime_function(runtime_function),
argc(argc),
catch_block(catch_block) {}
void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
if (catch_block) block_list->push_back(*catch_block);
}
bool is_tailcall;
RuntimeFunction* runtime_function;
size_t argc;
base::Optional<Block*> catch_block;
};
struct BranchInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
bool IsBlockTerminator() const override { return true; }
void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
block_list->push_back(if_true);
block_list->push_back(if_false);
}
BranchInstruction(Block* if_true, Block* if_false)
: if_true(if_true), if_false(if_false) {}
Block* if_true;
Block* if_false;
};
struct ConstexprBranchInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
bool IsBlockTerminator() const override { return true; }
void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
block_list->push_back(if_true);
block_list->push_back(if_false);
}
ConstexprBranchInstruction(std::string condition, Block* if_true,
Block* if_false)
: condition(condition), if_true(if_true), if_false(if_false) {}
std::string condition;
Block* if_true;
Block* if_false;
};
struct GotoInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
bool IsBlockTerminator() const override { return true; }
void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
block_list->push_back(destination);
}
explicit GotoInstruction(Block* destination) : destination(destination) {}
Block* destination;
};
struct GotoExternalInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
bool IsBlockTerminator() const override { return true; }
GotoExternalInstruction(std::string destination,
std::vector<std::string> variable_names)
: destination(std::move(destination)),
variable_names(std::move(variable_names)) {}
std::string destination;
std::vector<std::string> variable_names;
};
struct ReturnInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
bool IsBlockTerminator() const override { return true; }
};
struct PrintConstantStringInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
explicit PrintConstantStringInstruction(std::string message)
: message(std::move(message)) {}
std::string message;
};
struct AbortInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
enum class Kind { kDebugBreak, kUnreachable, kAssertionFailure };
bool IsBlockTerminator() const override { return kind != Kind::kDebugBreak; }
explicit AbortInstruction(Kind kind, std::string message = "")
: kind(kind), message(std::move(message)) {}
Kind kind;
std::string message;
};
struct UnsafeCastInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
explicit UnsafeCastInstruction(const Type* destination_type)
: destination_type(destination_type) {}
const Type* destination_type;
};
} // namespace torque
} // namespace internal
} // namespace v8
#endif // V8_TORQUE_INSTRUCTIONS_H_