2018-10-04 20:45:31 +00:00
|
|
|
// 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 Macro;
|
|
|
|
class ModuleConstant;
|
|
|
|
class RuntimeFunction;
|
|
|
|
|
|
|
|
#define TORQUE_INSTRUCTION_LIST(V) \
|
|
|
|
V(PeekInstruction) \
|
|
|
|
V(PokeInstruction) \
|
|
|
|
V(DeleteRangeInstruction) \
|
|
|
|
V(PushUninitializedInstruction) \
|
|
|
|
V(PushCodePointerInstruction) \
|
|
|
|
V(CallCsaMacroInstruction) \
|
|
|
|
V(ModuleConstantInstruction) \
|
|
|
|
V(CallCsaMacroAndBranchInstruction) \
|
|
|
|
V(CallBuiltinInstruction) \
|
|
|
|
V(CallRuntimeInstruction) \
|
|
|
|
V(CallBuiltinPointerInstruction) \
|
|
|
|
V(BranchInstruction) \
|
|
|
|
V(ConstexprBranchInstruction) \
|
|
|
|
V(GotoInstruction) \
|
|
|
|
V(GotoExternalInstruction) \
|
|
|
|
V(ReturnInstruction) \
|
|
|
|
V(PrintConstantStringInstruction) \
|
2018-11-02 12:54:22 +00:00
|
|
|
V(AbortInstruction) \
|
2018-10-04 20:45:31 +00:00
|
|
|
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;
|
2018-10-27 11:56:57 +00:00
|
|
|
void InvalidateTransientTypes(Stack<const Type*>* stack) const;
|
2018-10-04 20:45:31 +00:00
|
|
|
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)
|
|
|
|
: kind_(other.kind_), instruction_(other.instruction_->Clone()) {}
|
|
|
|
Instruction& operator=(const Instruction& other) {
|
|
|
|
if (kind_ == other.kind_) {
|
|
|
|
instruction_->Assign(*other.instruction_);
|
|
|
|
} else {
|
|
|
|
kind_ = other.kind_;
|
|
|
|
instruction_ = other.instruction_->Clone();
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
InstructionKind kind() const { return kind_; }
|
|
|
|
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 PushCodePointerInstruction : InstructionBase {
|
|
|
|
TORQUE_INSTRUCTION_BOILERPLATE()
|
|
|
|
PushCodePointerInstruction(std::string external_name, const Type* type)
|
|
|
|
: external_name(std::move(external_name)), type(type) {
|
|
|
|
DCHECK(type->IsFunctionPointerType());
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string external_name;
|
|
|
|
const Type* type;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ModuleConstantInstruction : InstructionBase {
|
|
|
|
TORQUE_INSTRUCTION_BOILERPLATE()
|
|
|
|
explicit ModuleConstantInstruction(ModuleConstant* constant)
|
|
|
|
: constant(constant) {}
|
|
|
|
|
|
|
|
ModuleConstant* constant;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct CallCsaMacroInstruction : InstructionBase {
|
|
|
|
TORQUE_INSTRUCTION_BOILERPLATE()
|
|
|
|
CallCsaMacroInstruction(Macro* macro,
|
2018-10-31 13:00:51 +00:00
|
|
|
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);
|
|
|
|
}
|
2018-10-04 20:45:31 +00:00
|
|
|
|
|
|
|
Macro* macro;
|
|
|
|
std::vector<std::string> constexpr_arguments;
|
2018-10-31 13:00:51 +00:00
|
|
|
base::Optional<Block*> catch_block;
|
2018-10-04 20:45:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct CallCsaMacroAndBranchInstruction : InstructionBase {
|
|
|
|
TORQUE_INSTRUCTION_BOILERPLATE()
|
|
|
|
CallCsaMacroAndBranchInstruction(Macro* macro,
|
|
|
|
std::vector<std::string> constexpr_arguments,
|
|
|
|
base::Optional<Block*> return_continuation,
|
2018-10-31 13:00:51 +00:00
|
|
|
std::vector<Block*> label_blocks,
|
|
|
|
base::Optional<Block*> catch_block)
|
2018-10-04 20:45:31 +00:00
|
|
|
: macro(macro),
|
|
|
|
constexpr_arguments(constexpr_arguments),
|
|
|
|
return_continuation(return_continuation),
|
2018-10-31 13:00:51 +00:00
|
|
|
label_blocks(label_blocks),
|
|
|
|
catch_block(catch_block) {}
|
2018-10-04 20:45:31 +00:00
|
|
|
bool IsBlockTerminator() const override { return true; }
|
|
|
|
void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
|
2018-10-31 13:00:51 +00:00
|
|
|
if (catch_block) block_list->push_back(*catch_block);
|
2018-10-04 20:45:31 +00:00
|
|
|
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;
|
2018-10-31 13:00:51 +00:00
|
|
|
base::Optional<Block*> catch_block;
|
2018-10-04 20:45:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct CallBuiltinInstruction : InstructionBase {
|
|
|
|
TORQUE_INSTRUCTION_BOILERPLATE()
|
|
|
|
bool IsBlockTerminator() const override { return is_tailcall; }
|
2018-10-31 13:00:51 +00:00
|
|
|
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);
|
|
|
|
}
|
2018-10-04 20:45:31 +00:00
|
|
|
|
|
|
|
bool is_tailcall;
|
|
|
|
Builtin* builtin;
|
|
|
|
size_t argc;
|
2018-10-31 13:00:51 +00:00
|
|
|
base::Optional<Block*> catch_block;
|
2018-10-04 20:45:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct CallBuiltinPointerInstruction : InstructionBase {
|
|
|
|
TORQUE_INSTRUCTION_BOILERPLATE()
|
|
|
|
bool IsBlockTerminator() const override { return is_tailcall; }
|
2018-11-05 10:37:49 +00:00
|
|
|
CallBuiltinPointerInstruction(bool is_tailcall,
|
|
|
|
const FunctionPointerType* type, size_t argc)
|
|
|
|
: is_tailcall(is_tailcall), type(type), argc(argc) {}
|
2018-10-04 20:45:31 +00:00
|
|
|
|
|
|
|
bool is_tailcall;
|
2018-11-05 10:37:49 +00:00
|
|
|
const FunctionPointerType* type;
|
2018-10-04 20:45:31 +00:00
|
|
|
size_t argc;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct CallRuntimeInstruction : InstructionBase {
|
|
|
|
TORQUE_INSTRUCTION_BOILERPLATE()
|
2018-10-16 21:14:05 +00:00
|
|
|
bool IsBlockTerminator() const override;
|
2018-10-04 20:45:31 +00:00
|
|
|
|
|
|
|
CallRuntimeInstruction(bool is_tailcall, RuntimeFunction* runtime_function,
|
2018-10-31 13:00:51 +00:00
|
|
|
size_t argc, base::Optional<Block*> catch_block)
|
2018-10-04 20:45:31 +00:00
|
|
|
: is_tailcall(is_tailcall),
|
|
|
|
runtime_function(runtime_function),
|
2018-10-31 13:00:51 +00:00
|
|
|
argc(argc),
|
|
|
|
catch_block(catch_block) {}
|
|
|
|
void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
|
|
|
|
if (catch_block) block_list->push_back(*catch_block);
|
|
|
|
}
|
2018-10-04 20:45:31 +00:00
|
|
|
|
|
|
|
bool is_tailcall;
|
|
|
|
RuntimeFunction* runtime_function;
|
|
|
|
size_t argc;
|
2018-10-31 13:00:51 +00:00
|
|
|
base::Optional<Block*> catch_block;
|
2018-10-04 20:45:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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) {
|
|
|
|
// The normal way to write this triggers a bug in Clang on Windows.
|
|
|
|
this->message = std::move(message);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string message;
|
|
|
|
};
|
|
|
|
|
2018-11-02 12:54:22 +00:00
|
|
|
struct AbortInstruction : InstructionBase {
|
2018-10-04 20:45:31 +00:00
|
|
|
TORQUE_INSTRUCTION_BOILERPLATE()
|
2018-11-02 12:54:22 +00:00
|
|
|
enum class Kind { kDebugBreak, kUnreachable, kAssertionFailure };
|
|
|
|
bool IsBlockTerminator() const override { return kind != Kind::kDebugBreak; }
|
|
|
|
explicit AbortInstruction(Kind kind, std::string message = "") : kind(kind) {
|
|
|
|
// The normal way to write this triggers a bug in Clang on Windows.
|
|
|
|
this->message = std::move(message);
|
|
|
|
}
|
2018-10-04 20:45:31 +00:00
|
|
|
|
2018-11-02 12:54:22 +00:00
|
|
|
Kind kind;
|
|
|
|
std::string message;
|
2018-10-04 20:45:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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_
|