blob: 67b64bbc04a0d4cec5b5e7c8d007ebd3f4c54f8b [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_CFG_H_
#define V8_TORQUE_CFG_H_
#include <list>
#include <memory>
#include <unordered_map>
#include <vector>
#include "src/torque/ast.h"
#include "src/torque/instructions.h"
#include "src/torque/source-positions.h"
#include "src/torque/types.h"
namespace v8 {
namespace internal {
namespace torque {
class ControlFlowGraph;
class Block {
explicit Block(ControlFlowGraph* cfg, size_t id,
base::Optional<Stack<const Type*>> input_types,
bool is_deferred)
: cfg_(cfg),
is_deferred_(is_deferred) {}
void Add(Instruction instruction) {
bool HasInputTypes() const { return input_types_ != base::nullopt; }
const Stack<const Type*>& InputTypes() const { return *input_types_; }
void SetInputTypes(const Stack<const Type*>& input_types);
void Retype() {
Stack<const Type*> current_stack = InputTypes();
for (const Instruction& instruction : instructions()) {
instruction.TypeInstruction(&current_stack, cfg_);
const std::vector<Instruction>& instructions() const { return instructions_; }
bool IsComplete() const {
return !instructions_.empty() && instructions_.back()->IsBlockTerminator();
size_t id() const { return id_; }
bool IsDeferred() const { return is_deferred_; }
ControlFlowGraph* cfg_;
std::vector<Instruction> instructions_;
base::Optional<Stack<const Type*>> input_types_;
const size_t id_;
bool is_deferred_;
class ControlFlowGraph {
explicit ControlFlowGraph(Stack<const Type*> input_types) {
start_ = NewBlock(std::move(input_types), false);
Block* NewBlock(base::Optional<Stack<const Type*>> input_types,
bool is_deferred) {
blocks_.emplace_back(this, next_block_id_++, std::move(input_types),
return &blocks_.back();
void PlaceBlock(Block* block) { placed_blocks_.push_back(block); }
Block* start() const { return start_; }
base::Optional<Block*> end() const { return end_; }
void set_end(Block* end) { end_ = end; }
void SetReturnType(const Type* t) {
if (!return_type_) {
return_type_ = t;
if (t != *return_type_) {
ReportError("expected return type ", **return_type_, " instead of ", *t);
const std::vector<Block*>& blocks() const { return placed_blocks_; }
std::list<Block> blocks_;
Block* start_;
std::vector<Block*> placed_blocks_;
base::Optional<Block*> end_;
base::Optional<const Type*> return_type_;
size_t next_block_id_ = 0;
class CfgAssembler {
explicit CfgAssembler(Stack<const Type*> input_types)
: current_stack_(std::move(input_types)), cfg_(current_stack_) {}
const ControlFlowGraph& Result() {
if (!CurrentBlockIsComplete()) {
return cfg_;
Block* NewBlock(
base::Optional<Stack<const Type*>> input_types = base::nullopt,
bool is_deferred = false) {
return cfg_.NewBlock(std::move(input_types), is_deferred);
bool CurrentBlockIsComplete() const { return current_block_->IsComplete(); }
void Emit(Instruction instruction) {
instruction.TypeInstruction(&current_stack_, &cfg_);
const Stack<const Type*>& CurrentStack() const { return current_stack_; }
StackRange TopRange(size_t slot_count) const {
return CurrentStack().TopRange(slot_count);
void Bind(Block* block);
void Goto(Block* block);
// Goto block while keeping {preserved_slots} many slots on the top and
// deleting additional the slots below these to match the input type of the
// target block.
// Returns the StackRange of the preserved slots in the target block.
StackRange Goto(Block* block, size_t preserved_slots);
// The condition must be of type bool and on the top of stack. It is removed
// from the stack before branching.
void Branch(Block* if_true, Block* if_false);
// Delete the specified range of slots, moving upper slots to fill the gap.
void DeleteRange(StackRange range);
void DropTo(BottomOffset new_level);
StackRange Peek(StackRange range, base::Optional<const Type*> type);
void Poke(StackRange destination, StackRange origin,
base::Optional<const Type*> type);
void Print(std::string s);
void AssertionFailure(std::string message);
void Unreachable();
void DebugBreak();
void PrintCurrentStack(std::ostream& s) { s << "stack: " << current_stack_; }
friend class CfgAssemblerScopedTemporaryBlock;
Stack<const Type*> current_stack_;
ControlFlowGraph cfg_;
Block* current_block_ = cfg_.start();
class CfgAssemblerScopedTemporaryBlock {
CfgAssemblerScopedTemporaryBlock(CfgAssembler* assembler, Block* block)
: assembler_(assembler), saved_block_(block) {
saved_stack_ = block->InputTypes();
std::swap(saved_block_, assembler->current_block_);
std::swap(saved_stack_, assembler->current_stack_);
~CfgAssemblerScopedTemporaryBlock() {
std::swap(saved_block_, assembler_->current_block_);
std::swap(saved_stack_, assembler_->current_stack_);
CfgAssembler* assembler_;
Stack<const Type*> saved_stack_;
Block* saved_block_;
} // namespace torque
} // namespace internal
} // namespace v8
#endif // V8_TORQUE_CFG_H_