Commit a4008bf0 authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

[torque] add an intermediate representation to Torque

Bug: v8:7793
Change-Id: I5261122faf422987968ee1e405966f878ff910a1
Reviewed-on: https://chromium-review.googlesource.com/c/1245766
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarDaniel Clifford <danno@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56391}
parent 42f17e7d
......@@ -2498,6 +2498,7 @@ v8_source_set("v8_base") {
"src/strtod.cc",
"src/strtod.h",
"src/third_party/utf8-decoder/utf8-decoder.h",
"src/torque-assembler.h",
"src/tracing/trace-event.cc",
"src/tracing/trace-event.h",
"src/tracing/traced-value.cc",
......@@ -2993,7 +2994,11 @@ v8_source_set("torque_base") {
sources = [
"src/torque/ast.h",
"src/torque/cfg.cc",
"src/torque/cfg.h",
"src/torque/contextual.h",
"src/torque/csa-generator.cc",
"src/torque/csa-generator.h",
"src/torque/declarable.cc",
"src/torque/declarable.h",
"src/torque/declaration-visitor.cc",
......@@ -3007,6 +3012,8 @@ v8_source_set("torque_base") {
"src/torque/global-context.h",
"src/torque/implementation-visitor.cc",
"src/torque/implementation-visitor.h",
"src/torque/instructions.cc",
"src/torque/instructions.h",
"src/torque/scope.cc",
"src/torque/scope.h",
"src/torque/source-positions.cc",
......
......@@ -277,6 +277,12 @@ struct Use {
(void)unused_tmp_array_for_use_macro; \
} while (false)
// Evaluate the instantiations of an expression with parameter packs.
// Since USE has left-to-right evaluation order of it's arguments,
// the parameter pack is iterated from left to right and side effects
// have defined behavior.
#define ITERATE_PACK(...) USE(0, ((__VA_ARGS__), 0)...)
} // namespace base
} // namespace v8
......
......@@ -1754,6 +1754,43 @@ void CodeAssemblerLabel::UpdateVariablesAfterBind() {
bound_ = true;
}
void CodeAssemblerParameterizedLabelBase::AddInputs(std::vector<Node*> inputs) {
if (!phi_nodes_.empty()) {
DCHECK_EQ(inputs.size(), phi_nodes_.size());
for (size_t i = 0; i < inputs.size(); ++i) {
state_->raw_assembler_->AppendPhiInput(phi_nodes_[i], inputs[i]);
}
} else {
DCHECK_EQ(inputs.size(), phi_inputs_.size());
for (size_t i = 0; i < inputs.size(); ++i) {
phi_inputs_[i].push_back(inputs[i]);
}
}
}
Node* CodeAssemblerParameterizedLabelBase::CreatePhi(
MachineRepresentation rep, const std::vector<Node*>& inputs) {
for (Node* input : inputs) {
// We use {nullptr} as a sentinel for an uninitialized value. We must not
// create phi nodes for these.
if (input == nullptr) return nullptr;
}
return state_->raw_assembler_->Phi(rep, static_cast<int>(inputs.size()),
&inputs.front());
}
const std::vector<Node*>& CodeAssemblerParameterizedLabelBase::CreatePhis(
std::vector<MachineRepresentation> representations) {
DCHECK(is_used());
DCHECK(phi_nodes_.empty());
phi_nodes_.reserve(phi_inputs_.size());
DCHECK_EQ(representations.size(), phi_inputs_.size());
for (size_t i = 0; i < phi_inputs_.size(); ++i) {
phi_nodes_.push_back(CreatePhi(representations[i], phi_inputs_[i]));
}
return phi_nodes_;
}
} // namespace compiler
Smi* CheckObjectType(Object* value, Smi* type, String* location) {
......
......@@ -52,6 +52,7 @@ class PromiseFulfillReactionJobTask;
class PromiseReaction;
class PromiseReactionJobTask;
class PromiseRejectReactionJobTask;
class TorqueAssembler;
class Zone;
template <typename T>
......@@ -1421,6 +1422,60 @@ class CodeAssemblerLabel {
std::map<CodeAssemblerVariable::Impl*, std::vector<Node*>> variable_merges_;
};
class CodeAssemblerParameterizedLabelBase {
public:
bool is_used() const { return plain_label_.is_used(); }
explicit CodeAssemblerParameterizedLabelBase(CodeAssembler* assembler,
size_t arity,
CodeAssemblerLabel::Type type)
: state_(assembler->state()),
phi_inputs_(arity),
plain_label_(assembler, type) {}
protected:
CodeAssemblerLabel* plain_label() { return &plain_label_; }
void AddInputs(std::vector<Node*> inputs);
Node* CreatePhi(MachineRepresentation rep, const std::vector<Node*>& inputs);
const std::vector<Node*>& CreatePhis(
std::vector<MachineRepresentation> representations);
private:
CodeAssemblerState* state_;
std::vector<std::vector<Node*>> phi_inputs_;
std::vector<Node*> phi_nodes_;
CodeAssemblerLabel plain_label_;
};
template <class... Types>
class CodeAssemblerParameterizedLabel
: public CodeAssemblerParameterizedLabelBase {
public:
static constexpr size_t kArity = sizeof...(Types);
explicit CodeAssemblerParameterizedLabel(CodeAssembler* assembler,
CodeAssemblerLabel::Type type)
: CodeAssemblerParameterizedLabelBase(assembler, kArity, type) {}
private:
friend class internal::TorqueAssembler;
void AddInputs(TNode<Types>... inputs) {
CodeAssemblerParameterizedLabelBase::AddInputs(
std::vector<Node*>{inputs...});
}
void CreatePhis(TNode<Types>*... results) {
const std::vector<Node*>& phi_nodes =
CodeAssemblerParameterizedLabelBase::CreatePhis(
{MachineRepresentationOf<Types>::value...});
auto it = phi_nodes.begin();
USE(it);
ITERATE_PACK(AssignPhi(results, *(it++)));
}
template <class T>
static void AssignPhi(TNode<T>* result, Node* phi) {
if (phi != nullptr) *result = TNode<T>::UncheckedCast(phi);
}
};
class V8_EXPORT_PRIVATE CodeAssemblerState {
public:
// Create with CallStub linkage.
......@@ -1454,6 +1509,7 @@ class V8_EXPORT_PRIVATE CodeAssemblerState {
friend class CodeAssemblerLabel;
friend class CodeAssemblerVariable;
friend class CodeAssemblerTester;
friend class CodeAssemblerParameterizedLabelBase;
CodeAssemblerState(Isolate* isolate, Zone* zone,
CallDescriptor* call_descriptor, Code::Kind kind,
......
// 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_ASSEMBLER_H_
#define V8_TORQUE_ASSEMBLER_H_
#include <deque>
#include <vector>
#include "src/code-stub-assembler.h"
#include "src/base/optional.h"
namespace v8 {
namespace internal {
class TorqueAssembler : public CodeStubAssembler {
public:
using CodeStubAssembler::CodeStubAssembler;
protected:
template <class... Ts>
using PLabel = compiler::CodeAssemblerParameterizedLabel<Ts...>;
template <class T>
TNode<T> Uninitialized() {
return {};
}
template <class... T, class... Args>
void Goto(PLabel<T...>* label, Args... args) {
label->AddInputs(args...);
CodeStubAssembler::Goto(label->plain_label());
}
using CodeStubAssembler::Goto;
template <class... T>
void Bind(PLabel<T...>* label, TNode<T>*... phis) {
Bind(label->plain_label());
label->CreatePhis(phis...);
}
void Bind(Label* label) { CodeAssembler::Bind(label); }
using CodeStubAssembler::Bind;
template <class... T, class... Args>
void Branch(TNode<BoolT> condition, PLabel<T...>* if_true,
PLabel<T...>* if_false, Args... args) {
if_true->AddInputs(args...);
if_false->AddInputs(args...);
CodeStubAssembler::Branch(condition, if_true->plain_label(),
if_false->plain_label());
}
using CodeStubAssembler::Branch;
};
} // namespace internal
} // namespace v8
#endif // V8_TORQUE_ASSEMBLER_H_
// 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.
#include "src/torque/cfg.h"
#include "src/torque/type-oracle.h"
namespace v8 {
namespace internal {
namespace torque {
void Block::SetInputTypes(const Stack<const Type*>& input_types) {
if (!input_types_) {
input_types_ = input_types;
} else if (*input_types_ != input_types) {
std::stringstream error;
error << "incompatible types at branch:\n";
for (intptr_t i = std::max(input_types_->Size(), input_types.Size()) - 1;
i >= 0; --i) {
base::Optional<const Type*> left;
base::Optional<const Type*> right;
if (static_cast<size_t>(i) < input_types.Size()) {
left = input_types.Peek(BottomOffset{static_cast<size_t>(i)});
}
if (static_cast<size_t>(i) < input_types_->Size()) {
right = input_types_->Peek(BottomOffset{static_cast<size_t>(i)});
}
if (left && right && *left == *right) {
error << **left << "\n";
} else {
if (left) {
error << **left;
} else {
error << "/*missing*/";
}
error << " => ";
if (right) {
error << **right;
} else {
error << "/*missing*/";
}
error << "\n";
}
}
ReportError(error.str());
}
}
void CfgAssembler::Bind(Block* block) {
DCHECK(current_block_->IsComplete());
DCHECK(block->instructions().empty());
DCHECK(block->HasInputTypes());
current_block_ = block;
current_stack_ = block->InputTypes();
cfg_.PlaceBlock(block);
}
void CfgAssembler::Goto(Block* block) {
if (block->HasInputTypes()) {
DropTo(block->InputTypes().AboveTop());
}
Emit(GotoInstruction{block});
}
StackRange CfgAssembler::Goto(Block* block, size_t preserved_slots) {
DCHECK(block->HasInputTypes());
DCHECK_GE(CurrentStack().Size(), block->InputTypes().Size());
Emit(DeleteRangeInstruction{
StackRange{block->InputTypes().AboveTop() - preserved_slots,
CurrentStack().AboveTop() - preserved_slots}});
StackRange preserved_slot_range = TopRange(preserved_slots);
Emit(GotoInstruction{block});
return preserved_slot_range;
}
void CfgAssembler::Branch(Block* if_true, Block* if_false) {
Emit(BranchInstruction{if_true, if_false});
}
// Delete the specified range of slots, moving upper slots to fill the gap.
void CfgAssembler::DeleteRange(StackRange range) {
DCHECK_LE(range.end(), current_stack_.AboveTop());
if (range.Size() == 0) return;
Emit(DeleteRangeInstruction{range});
}
void CfgAssembler::DropTo(BottomOffset new_level) {
DeleteRange(StackRange{new_level, CurrentStack().AboveTop()});
}
StackRange CfgAssembler::Peek(StackRange range,
base::Optional<const Type*> type) {
std::vector<const Type*> lowered_types;
if (type) {
lowered_types = LowerType(*type);
DCHECK_EQ(lowered_types.size(), range.Size());
}
for (size_t i = 0; i < range.Size(); ++i) {
Emit(PeekInstruction{
range.begin() + i,
type ? lowered_types[i] : base::Optional<const Type*>{}});
}
return TopRange(range.Size());
}
void CfgAssembler::Poke(StackRange destination, StackRange origin,
base::Optional<const Type*> type) {
DCHECK_EQ(destination.Size(), origin.Size());
DCHECK_LE(destination.end(), origin.begin());
DCHECK_EQ(origin.end(), CurrentStack().AboveTop());
std::vector<const Type*> lowered_types;
if (type) {
lowered_types = LowerType(*type);
DCHECK_EQ(lowered_types.size(), origin.Size());
}
for (intptr_t i = origin.Size() - 1; i >= 0; --i) {
Emit(PokeInstruction{
destination.begin() + i,
type ? lowered_types[i] : base::Optional<const Type*>{}});
}
}
void CfgAssembler::Print(std::string s) {
Emit(PrintConstantStringInstruction{std::move(s)});
}
void CfgAssembler::Unreachable() { Emit(DebugBreakInstruction{true}); }
void CfgAssembler::DebugBreak() { Emit(DebugBreakInstruction{false}); }
} // namespace torque
} // namespace internal
} // namespace v8
// 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 Block {
public:
explicit Block(size_t id, base::Optional<Stack<const Type*>> input_types,
bool is_deferred)
: input_types_(std::move(input_types)),
id_(id),
is_deferred_(is_deferred) {}
void Add(Instruction instruction) {
DCHECK(!IsComplete());
instructions_.push_back(std::move(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);
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_; }
private:
std::vector<Instruction> instructions_;
base::Optional<Stack<const Type*>> input_types_;
const size_t id_;
bool is_deferred_;
};
class ControlFlowGraph {
public:
explicit ControlFlowGraph(Stack<const Type*> input_types) {
start_ = NewBlock(std::move(input_types), false);
PlaceBlock(start_);
}
Block* NewBlock(base::Optional<Stack<const Type*>> input_types,
bool is_deferred) {
blocks_.emplace_back(next_block_id_++, std::move(input_types), is_deferred);
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;
return;
}
if (t != *return_type_) {
ReportError("expected return type ", **return_type_, " instead of ", *t);
}
}
const std::vector<Block*>& blocks() const { return placed_blocks_; }
private:
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 {
public:
explicit CfgAssembler(Stack<const Type*> input_types)
: current_stack_(std::move(input_types)), cfg_(current_stack_) {}
const ControlFlowGraph& Result() {
if (!CurrentBlockIsComplete()) {
cfg_.set_end(current_block_);
}
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_);
current_block_->Add(std::move(instruction));
}
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 Unreachable();
void DebugBreak();
private:
Stack<const Type*> current_stack_;
ControlFlowGraph cfg_;
Block* current_block_ = cfg_.start();
};
} // namespace torque
} // namespace internal
} // namespace v8
#endif // V8_TORQUE_CFG_H_
This diff is collapsed.
// 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_CSA_GENERATOR_H_
#define V8_TORQUE_CSA_GENERATOR_H_
#include <iostream>
#include "src/torque/cfg.h"
#include "src/torque/declarable.h"
namespace v8 {
namespace internal {
namespace torque {
class CSAGenerator {
public:
CSAGenerator(const ControlFlowGraph& cfg, std::ostream& out,
base::Optional<Builtin::Kind> linkage = base::nullopt)
: cfg_(cfg), out_(out), linkage_(linkage) {}
base::Optional<Stack<std::string>> EmitGraph(Stack<std::string> parameters);
static constexpr const char* ARGUMENTS_VARIABLE_STRING = "arguments";
static void EmitCSAValue(VisitResult result, const Stack<std::string>& values,
std::ostream& out);
private:
const ControlFlowGraph& cfg_;
std::ostream& out_;
size_t fresh_id_ = 0;
base::Optional<Builtin::Kind> linkage_;
std::string FreshNodeName() { return "tmp" + std::to_string(fresh_id_++); }
std::string BlockName(const Block* block) {
return "block" + std::to_string(block->id());
}
Stack<std::string> EmitBlock(const Block* block);
void EmitInstruction(const Instruction& instruction,
Stack<std::string>* stack);
#define EMIT_INSTRUCTION_DECLARATION(T) \
void EmitInstruction(const T& instruction, Stack<std::string>* stack);
TORQUE_INSTRUCTION_LIST(EMIT_INSTRUCTION_DECLARATION)
#undef EMIT_INSTRUCTION_DECLARATION
};
} // namespace torque
} // namespace internal
} // namespace v8
#endif // V8_TORQUE_CSA_GENERATOR_H_
......@@ -34,18 +34,6 @@ std::ostream& operator<<(std::ostream& os, const RuntimeFunction& b) {
return os;
}
std::string Variable::RValue() const {
if (!IsDefined()) {
ReportError("Reading uninitialized variable.");
}
if (type()->IsStructType()) {
return value();
}
std::string result = "(*" + value() + ")";
if (!IsConst()) result += ".value()";
return result;
}
void PrintLabel(std::ostream& os, const Label& l, bool with_names) {
os << l.name();
if (l.GetParameterCount() != 0) {
......
......@@ -18,9 +18,10 @@ namespace v8 {
namespace internal {
namespace torque {
class Block;
class Generic;
class Scope;
class ScopeChain;
class Generic;
class Declarable {
public:
......@@ -88,13 +89,17 @@ class Declarable {
class Value : public Declarable {
public:
DECLARE_DECLARABLE_BOILERPLATE(Value, value);
const std::string& name() const { return name_; }
virtual bool IsConst() const { return true; }
virtual std::string value() const = 0;
virtual std::string RValue() const { return value(); }
DECLARE_DECLARABLE_BOILERPLATE(Value, value);
VisitResult value() const { return *value_; }
const Type* type() const { return type_; }
void set_value(VisitResult value) {
DCHECK(!value_);
value_ = value;
}
protected:
Value(Kind kind, const Type* type, const std::string& name)
: Declarable(kind), type_(type), name_(name) {}
......@@ -102,40 +107,44 @@ class Value : public Declarable {
private:
const Type* type_;
std::string name_;
base::Optional<VisitResult> value_;
};
class Parameter : public Value {
public:
DECLARE_DECLARABLE_BOILERPLATE(Parameter, parameter);
std::string value() const override { return var_name_; }
const std::string& external_name() const { return external_name_; }
private:
friend class Declarations;
Parameter(const std::string& name, const Type* type,
const std::string& var_name)
: Value(Declarable::kParameter, type, name), var_name_(var_name) {}
Parameter(const std::string& name, std::string external_name,
const Type* type)
: Value(Declarable::kParameter, type, name),
external_name_(external_name) {}
std::string var_name_;
std::string external_name_;
};
class ModuleConstant : public Value {
public:
DECLARE_DECLARABLE_BOILERPLATE(ModuleConstant, constant);
std::string value() const override { UNREACHABLE(); }
std::string RValue() const override { return name() + "()"; }
const std::string& constant_name() const { return constant_name_; }
private:
friend class Declarations;
explicit ModuleConstant(const std::string& name, const Type* type)
: Value(Declarable::kModuleConstant, type, name) {}
explicit ModuleConstant(std::string constant_name, const Type* type)
: Value(Declarable::kModuleConstant, type, constant_name),
constant_name_(std::move(constant_name)) {}
std::string constant_name_;
};
class Variable : public Value {
public:
DECLARE_DECLARABLE_BOILERPLATE(Variable, variable);
bool IsConst() const override { return const_; }
std::string value() const override { return value_; }
std::string RValue() const override;
void Define() {
if (defined_ && IsConst()) {
ReportError("Cannot re-define a const-bound variable.");
......@@ -146,10 +155,8 @@ class Variable : public Value {
private:
friend class Declarations;
Variable(const std::string& name, const std::string& value, const Type* type,
bool is_const)
Variable(std::string name, const Type* type, bool is_const)
: Value(Declarable::kVariable, type, name),
value_(value),
defined_(false),
const_(is_const) {
DCHECK_IMPLIES(type->IsConstexpr(), IsConst());
......@@ -163,8 +170,20 @@ class Variable : public Value {
class Label : public Declarable {
public:
void AddVariable(Variable* var) { parameters_.push_back(var); }
std::string name() const { return name_; }
std::string generated() const { return generated_; }
Block* block() const { return *block_; }
void set_block(Block* block) {
DCHECK(!block_);
block_ = block;
}
const std::string& external_label_name() const {
return *external_label_name_;
}
const std::string& name() const { return name_; }
void set_external_label_name(std::string external_label_name) {
DCHECK(!block_);
DCHECK(!external_label_name_);
external_label_name_ = std::move(external_label_name);
}
Variable* GetParameter(size_t i) const { return parameters_[i]; }
size_t GetParameterCount() const { return parameters_.size(); }
const std::vector<Variable*>& GetParameters() const { return parameters_; }
......@@ -176,15 +195,15 @@ class Label : public Declarable {
private:
friend class Declarations;
explicit Label(const std::string& name, bool deferred = false)
explicit Label(std::string name, bool deferred = false)
: Declarable(Declarable::kLabel),
name_(name),
generated_("label_" + name + "_" + std::to_string(next_id_++)),
name_(std::move(name)),
used_(false),
deferred_(deferred) {}
std::string name_;
std::string generated_;
base::Optional<Block*> block_;
base::Optional<std::string> external_label_name_;
std::vector<Variable*> parameters_;
static size_t next_id_;
bool used_;
......@@ -194,15 +213,13 @@ class Label : public Declarable {
class ExternConstant : public Value {
public:
DECLARE_DECLARABLE_BOILERPLATE(ExternConstant, constant);
std::string value() const override { return value_; }
private:
friend class Declarations;
explicit ExternConstant(const std::string& name, const Type* type,
const std::string& value)
: Value(Declarable::kExternConstant, type, name), value_(value) {}
std::string value_;
explicit ExternConstant(std::string name, const Type* type, std::string value)
: Value(Declarable::kExternConstant, type, std::move(name)) {
set_value(VisitResult(type, std::move(value)));
}
};
class Callable : public Declarable {
......
......@@ -174,22 +174,10 @@ void DeclarationVisitor::Visit(TorqueMacroDeclaration* decl,
CurrentCallableActivator activator(global_context_, macro, decl);
DeclareSignature(signature);
Variable* return_variable = nullptr;
if (!signature.return_type->IsVoidOrNever()) {
return_variable =
DeclareVariable(kReturnValueVariable, signature.return_type,
signature.return_type->IsConstexpr());
}
PushControlSplit();
if (body != nullptr) {
Visit(body);
}
auto changed_vars = PopControlSplit();
if (return_variable) changed_vars.insert(return_variable);
global_context_.AddControlSplitChangedVariables(
decl, declarations()->GetCurrentSpecializationTypeNamesVector(),
changed_vars);
}
void DeclarationVisitor::Visit(ConstDeclaration* decl) {
......@@ -273,28 +261,13 @@ void DeclarationVisitor::Visit(ReturnStatement* stmt) {
Variable* DeclarationVisitor::DeclareVariable(const std::string& name,
const Type* type, bool is_const) {
Variable* result = declarations()->DeclareVariable(name, type, is_const);
if (type->IsStructType()) {
const StructType* struct_type = StructType::cast(type);
for (auto& field : struct_type->fields()) {
std::string field_var_name = name + "." + field.name;
DeclareVariable(field_var_name, field.type, is_const);
}
}
return result;
}
Parameter* DeclarationVisitor::DeclareParameter(const std::string& name,
const Type* type) {
Parameter* result = declarations()->DeclareParameter(
return declarations()->DeclareParameter(
name, GetParameterVariableFromName(name), type);
if (type->IsStructType()) {
const StructType* struct_type = StructType::cast(type);
for (auto& field : struct_type->fields()) {
std::string field_var_name = name + "." + field.name;
DeclareParameter(field_var_name, field.type);
}
}
return result;
}
void DeclarationVisitor::Visit(VarDeclarationStatement* stmt) {
......@@ -389,39 +362,20 @@ void DeclarationVisitor::DeclareExpressionForBranch(
void DeclarationVisitor::Visit(ConditionalExpression* expr) {
DeclareExpressionForBranch(expr->condition);
PushControlSplit();
Visit(expr->if_true);
Visit(expr->if_false);
auto changed_vars = PopControlSplit();
global_context_.AddControlSplitChangedVariables(
expr, declarations()->GetCurrentSpecializationTypeNamesVector(),
changed_vars);
}
void DeclarationVisitor::Visit(IfStatement* stmt) {
if (!stmt->is_constexpr) {
PushControlSplit();
}
DeclareExpressionForBranch(stmt->condition, stmt->if_true, stmt->if_false);
Visit(stmt->if_true);
if (stmt->if_false) Visit(*stmt->if_false);
if (!stmt->is_constexpr) {
auto changed_vars = PopControlSplit();
global_context_.AddControlSplitChangedVariables(
stmt, declarations()->GetCurrentSpecializationTypeNamesVector(),
changed_vars);
}
}
void DeclarationVisitor::Visit(WhileStatement* stmt) {
Declarations::NodeScopeActivator scope(declarations(), stmt);
DeclareExpressionForBranch(stmt->condition);
PushControlSplit();
Visit(stmt->body);
auto changed_vars = PopControlSplit();
global_context_.AddControlSplitChangedVariables(
stmt, declarations()->GetCurrentSpecializationTypeNamesVector(),
changed_vars);
}
void DeclarationVisitor::Visit(ForOfLoopStatement* stmt) {
......@@ -431,18 +385,12 @@ void DeclarationVisitor::Visit(ForOfLoopStatement* stmt) {
Visit(stmt->iterable);
if (stmt->begin) Visit(*stmt->begin);
if (stmt->end) Visit(*stmt->end);
PushControlSplit();
Visit(stmt->body);
auto changed_vars = PopControlSplit();
global_context_.AddControlSplitChangedVariables(
stmt, declarations()->GetCurrentSpecializationTypeNamesVector(),
changed_vars);
}
void DeclarationVisitor::Visit(ForLoopStatement* stmt) {
Declarations::NodeScopeActivator scope(declarations(), stmt);
if (stmt->var_declaration) Visit(*stmt->var_declaration);
PushControlSplit();
// Same as DeclareExpressionForBranch, but without the extra scope.
// If no test expression is present we can not use it for the scope.
......@@ -452,10 +400,6 @@ void DeclarationVisitor::Visit(ForLoopStatement* stmt) {
Visit(stmt->body);
if (stmt->action) Visit(*stmt->action);
auto changed_vars = PopControlSplit();
global_context_.AddControlSplitChangedVariables(
stmt, declarations()->GetCurrentSpecializationTypeNamesVector(),
changed_vars);
}
void DeclarationVisitor::Visit(TryLabelStatement* stmt) {
......@@ -592,34 +536,6 @@ void DeclarationVisitor::Visit(TypeDeclaration* decl) {
}
}
void DeclarationVisitor::MarkLocationModified(Expression* location) {
if (IdentifierExpression* id = IdentifierExpression::cast(location)) {
const Value* value = declarations()->LookupValue(id->name);
if (value->IsVariable()) {
const Variable* variable = Variable::cast(value);
bool was_live = MarkVariableModified(variable);
if (was_live && global_context_.verbose()) {
std::cout << *variable << " was modified in control split at "
<< PositionAsString(id->pos) << "\n";
}
}
}
}
bool DeclarationVisitor::MarkVariableModified(const Variable* variable) {
auto e = live_and_changed_variables_.rend();
auto c = live_and_changed_variables_.rbegin();
bool was_live_in_preceeding_split = false;
while (c != e) {
if (c->live.find(variable) != c->live.end()) {
c->changed.insert(variable);
was_live_in_preceeding_split = true;
}
c++;
}
return was_live_in_preceeding_split;
}
void DeclarationVisitor::DeclareSignature(const Signature& signature) {
auto type_iterator = signature.parameter_types.types.begin();
for (const auto& name : signature.parameter_names) {
......@@ -631,6 +547,7 @@ void DeclarationVisitor::DeclareSignature(const Signature& signature) {
for (auto& label : signature.labels) {
auto label_params = label.types;
Label* new_label = declarations()->DeclareLabel(label.name);
new_label->set_external_label_name("label_" + label.name);
size_t i = 0;
for (auto var_type : label_params) {
if (var_type->IsConstexpr()) {
......
......@@ -124,7 +124,6 @@ class DeclarationVisitor : public FileVisitor {
void Visit(ForOfLoopStatement* stmt);
void Visit(AssignmentExpression* expr) {
MarkLocationModified(expr->location);
Visit(expr->location);
Visit(expr->value);
}
......@@ -135,7 +134,6 @@ class DeclarationVisitor : public FileVisitor {
void Visit(ForLoopStatement* stmt);
void Visit(IncrementDecrementExpression* expr) {
MarkLocationModified(expr->location);
Visit(expr->location);
}
......@@ -145,29 +143,10 @@ class DeclarationVisitor : public FileVisitor {
void GenerateHeader(std::string& file_name);
private:
struct LiveAndChanged {
std::set<const Variable*> live;
std::set<const Variable*> changed;
};
void PushControlSplit() {
LiveAndChanged live_and_changed;
live_and_changed.live = declarations()->GetLiveVariables();
live_and_changed_variables_.push_back(live_and_changed);
}
Variable* DeclareVariable(const std::string& name, const Type* type,
bool is_const);
Parameter* DeclareParameter(const std::string& name, const Type* type);
std::set<const Variable*> PopControlSplit() {
auto result = live_and_changed_variables_.back().changed;
live_and_changed_variables_.pop_back();
return result;
}
void MarkLocationModified(Expression* location);
bool MarkVariableModified(const Variable* variable);
void DeclareSignature(const Signature& signature);
void DeclareSpecializedTypes(const SpecializationKey& key);
......@@ -177,7 +156,6 @@ class DeclarationVisitor : public FileVisitor {
Declarations::ModuleScopeActivator scope_;
std::vector<Builtin*> torque_builtins_;
std::vector<LiveAndChanged> live_and_changed_variables_;
};
} // namespace torque
......
......@@ -306,45 +306,29 @@ RuntimeFunction* Declarations::DeclareRuntimeFunction(
Variable* Declarations::CreateVariable(const std::string& var, const Type* type,
bool is_const) {
std::string name(var + "_" +
std::to_string(GetNextUniqueDeclarationNumber()));
std::replace(name.begin(), name.end(), '.', '_');
return RegisterDeclarable(
std::unique_ptr<Variable>(new Variable(var, name, type, is_const)));
std::unique_ptr<Variable>(new Variable(var, type, is_const)));
}
Variable* Declarations::DeclareVariable(const std::string& var,
const Type* type, bool is_const) {
std::string name(var + "_" +
std::to_string(GetNextUniqueDeclarationNumber()));
std::replace(name.begin(), name.end(), '.', '_');
CheckAlreadyDeclared(var, "variable");
Variable* result = new Variable(var, name, type, is_const);
Variable* result = new Variable(var, type, is_const);
Declare(var, std::unique_ptr<Declarable>(result));
return result;
}
Parameter* Declarations::DeclareParameter(const std::string& name,
const std::string& var_name,
std::string external_name,
const Type* type) {
CheckAlreadyDeclared(name, "parameter");
Parameter* result = new Parameter(name, type, var_name);
Declare(name, std::unique_ptr<Declarable>(result));
return result;
}
Label* Declarations::DeclarePrivateLabel(const std::string& raw_name) {
std::string name =
raw_name + "_" + std::to_string(GetNextUniqueDeclarationNumber());
CheckAlreadyDeclared(name, "label");
Label* result = new Label(name);
Parameter* result = new Parameter(name, std::move(external_name), type);
Declare(name, std::unique_ptr<Declarable>(result));
return result;
}
void Declarations::DeclareExternConstant(const std::string& name,
const Type* type,
const std::string& value) {
const Type* type, std::string value) {
CheckAlreadyDeclared(name, "constant, parameter or arguments");
ExternConstant* result = new ExternConstant(name, type, value);
Declare(name, std::unique_ptr<Declarable>(result));
......
......@@ -97,13 +97,10 @@ class Declarations {
bool is_const);
Parameter* DeclareParameter(const std::string& name,
const std::string& mangled_name,
const Type* type);
Label* DeclarePrivateLabel(const std::string& name);
std::string external_name, const Type* type);
void DeclareExternConstant(const std::string& name, const Type* type,
const std::string& value);
std::string value);
ModuleConstant* DeclareModuleConstant(const std::string& name,
const Type* type);
......
......@@ -51,10 +51,6 @@ class FileVisitor {
};
protected:
static constexpr const char* kReturnValueVariable = "_return";
static constexpr const char* kDoneLabelName = "_done";
static constexpr const char* kForIndexValueVariable = "_for_index";
Module* CurrentModule() const { return module_; }
friend class ScopedModuleActivator;
......
......@@ -65,34 +65,12 @@ class GlobalContext {
void SetVerbose() { verbose_ = true; }
bool verbose() const { return verbose_; }
void AddControlSplitChangedVariables(const AstNode* node,
const TypeVector& specialization_types,
const std::set<const Variable*>& vars) {
auto key = std::make_pair(node, specialization_types);
control_split_changed_variables_[key] = vars;
}
const std::set<const Variable*>& GetControlSplitChangedVariables(
const AstNode* node, const TypeVector& specialization_types) {
auto key = std::make_pair(node, specialization_types);
assert(control_split_changed_variables_.find(key) !=
control_split_changed_variables_.end());
return control_split_changed_variables_.find(key)->second;
}
void MarkVariableChanged(const AstNode* node,
const TypeVector& specialization_types,
Variable* var) {
auto key = std::make_pair(node, specialization_types);
control_split_changed_variables_[key].insert(var);
}
friend class CurrentCallableActivator;
friend class BreakContinueActivator;
Callable* GetCurrentCallable() const { return current_callable_; }
Label* GetCurrentBreak() const { return break_continue_stack_.back().first; }
Label* GetCurrentContinue() const {
Block* GetCurrentBreak() const { return break_continue_stack_.back().first; }
Block* GetCurrentContinue() const {
return break_continue_stack_.back().second;
}
......@@ -104,11 +82,9 @@ class GlobalContext {
int next_label_number_;
Declarations declarations_;
Callable* current_callable_;
std::vector<std::pair<Label*, Label*>> break_continue_stack_;
std::vector<std::pair<Block*, Block*>> break_continue_stack_;
std::map<std::string, std::unique_ptr<Module>> modules_;
Module* default_module_;
std::map<std::pair<const AstNode*, TypeVector>, std::set<const Variable*>>
control_split_changed_variables_;
Ast ast_;
};
......@@ -132,10 +108,10 @@ class CurrentCallableActivator {
class BreakContinueActivator {
public:
BreakContinueActivator(GlobalContext& context, Label* break_label,
Label* continue_label)
BreakContinueActivator(GlobalContext& context, Block* break_block,
Block* continue_block)
: context_(context) {
context_.break_continue_stack_.push_back({break_label, continue_label});
context_.break_continue_stack_.push_back({break_block, continue_block});
}
~BreakContinueActivator() { context_.break_continue_stack_.pop_back(); }
......
This diff is collapsed.
This diff is collapsed.
// 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.
#include "src/torque/instructions.h"
#include "src/torque/cfg.h"
#include "src/torque/type-oracle.h"
namespace v8 {
namespace internal {
namespace torque {
#define TORQUE_INSTRUCTION_BOILERPLATE_DEFINITIONS(Name) \
const InstructionKind Name::kKind = InstructionKind::k##Name; \
std::unique_ptr<InstructionBase> Name::Clone() const { \
return std::unique_ptr<InstructionBase>(new Name(*this)); \
} \
void Name::Assign(const InstructionBase& other) { \
*this = static_cast<const Name&>(other); \
}
TORQUE_INSTRUCTION_LIST(TORQUE_INSTRUCTION_BOILERPLATE_DEFINITIONS)
#undef TORQUE_INSTRUCTION_BOILERPLATE_DEFINITIONS
void PeekInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
const Type* type = stack->Peek(slot);
if (widened_type) {
if (!type->IsSubtypeOf(*widened_type)) {
ReportError("type ", type, " is not a subtype of ", *widened_type);
}
type = *widened_type;
}
stack->Push(type);
}
void PokeInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
const Type* type = stack->Top();
if (widened_type) {
if (!type->IsSubtypeOf(*widened_type)) {
ReportError("type ", type, " is not a subtype of ", *widened_type);
}
type = *widened_type;
}
stack->Poke(slot, type);
stack->Pop();
}
void DeleteRangeInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
stack->DeleteRange(range);
}
void PushUninitializedInstruction::TypeInstruction(
Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
stack->Push(type);
}
void PushCodePointerInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
stack->Push(type);
}
void ModuleConstantInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
stack->PushMany(LowerType(constant->type()));
}
void CallCsaMacroInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
std::vector<const Type*> parameter_types =
LowerParameterTypes(macro->signature().parameter_types);
for (intptr_t i = parameter_types.size() - 1; i >= 0; --i) {
const Type* arg_type = stack->Pop();
const Type* parameter_type = parameter_types.back();
parameter_types.pop_back();
if (arg_type != parameter_type) {
ReportError("parameter ", i, ": expected type ", *parameter_type,
" but found type ", *arg_type);
}
}
if (!parameter_types.empty()) ReportError("missing arguments");
stack->PushMany(LowerType(macro->signature().return_type));
}
void CallCsaMacroAndBranchInstruction::TypeInstruction(
Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
std::vector<const Type*> parameter_types =
LowerParameterTypes(macro->signature().parameter_types);
for (intptr_t i = parameter_types.size() - 1; i >= 0; --i) {
const Type* arg_type = stack->Pop();
const Type* parameter_type = parameter_types.back();
parameter_types.pop_back();
if (arg_type != parameter_type) {
ReportError("parameter ", i, ": expected type ", *parameter_type,
" but found type ", *arg_type);
}
}
if (!parameter_types.empty()) ReportError("missing arguments");
if (label_blocks.size() != macro->signature().labels.size()) {
ReportError("wrong number of labels");
}
for (size_t i = 0; i < label_blocks.size(); ++i) {
Stack<const Type*> continuation_stack = *stack;
continuation_stack.PushMany(
LowerParameterTypes(macro->signature().labels[i].types));
label_blocks[i]->SetInputTypes(std::move(continuation_stack));
}
if (macro->signature().return_type != TypeOracle::GetNeverType()) {
Stack<const Type*> return_stack = *stack;
return_stack.PushMany(LowerType(macro->signature().return_type));
if (return_continuation == base::nullopt) {
ReportError("missing return continuation.");
}
(*return_continuation)->SetInputTypes(return_stack);
} else {
if (return_continuation != base::nullopt) {
ReportError("unreachable return continuation.");
}
}
}
void CallBuiltinInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
std::vector<const Type*> argument_types = stack->PopMany(argc);
if (argument_types !=
LowerParameterTypes(builtin->signature().parameter_types)) {
ReportError("wrong argument types");
}
stack->PushMany(LowerType(builtin->signature().return_type));
}
void CallBuiltinPointerInstruction::TypeInstruction(
Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
std::vector<const Type*> argument_types = stack->PopMany(argc);
const FunctionPointerType* f = FunctionPointerType::DynamicCast(stack->Pop());
if (!f) ReportError("expected function pointer type");
if (argument_types != LowerParameterTypes(f->parameter_types())) {
ReportError("wrong argument types");
}
stack->PushMany(LowerType(f->return_type()));
}
void CallRuntimeInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
std::vector<const Type*> argument_types = stack->PopMany(argc);
if (argument_types !=
LowerParameterTypes(runtime_function->signature().parameter_types,
argc)) {
ReportError("wrong argument types");
}
stack->PushMany(LowerType(runtime_function->signature().return_type));
}
void BranchInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
const Type* condition_type = stack->Pop();
if (condition_type != TypeOracle::GetBoolType()) {
ReportError("condition has to have type bool");
}
if_true->SetInputTypes(*stack);
if_false->SetInputTypes(*stack);
}
void ConstexprBranchInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
if_true->SetInputTypes(*stack);
if_false->SetInputTypes(*stack);
}
void GotoInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
destination->SetInputTypes(*stack);
}
void GotoExternalInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
if (variable_names.size() != stack->Size()) {
ReportError("goto external label with wrong parameter count.");
}
}
void ReturnInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
cfg->SetReturnType(stack->Pop());
}
void PrintConstantStringInstruction::TypeInstruction(
Stack<const Type*>* stack, ControlFlowGraph* cfg) const {}
void DebugBreakInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {}
void UnsafeCastInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
stack->Poke(stack->AboveTop() - 1, destination_type);
}
} // namespace torque
} // namespace internal
} // namespace v8
This diff is collapsed.
......@@ -293,28 +293,66 @@ bool operator<(const Type& a, const Type& b) {
return a.MangledName() < b.MangledName();
}
VisitResult::VisitResult(const Type* type, const Value* declarable)
: type_(type), value_(), declarable_(declarable) {}
std::string VisitResult::LValue() const {
return std::string("*") + (declarable_ ? (*declarable_)->value() : value_);
VisitResult ProjectStructField(VisitResult structure,
const std::string& fieldname) {
DCHECK(structure.IsOnStack());
BottomOffset begin = structure.stack_range().begin();
const StructType* type = StructType::cast(structure.type());
for (auto& field : type->fields()) {
BottomOffset end = begin + LoweredSlotCount(field.type);
if (field.name == fieldname) {
return VisitResult(field.type, StackRange{begin, end});
}
begin = end;
}
UNREACHABLE();
}
std::string VisitResult::RValue() const {
std::string result;
if (declarable()) {
auto value = *declarable();
if (value->IsVariable() && !Variable::cast(value)->IsDefined()) {
std::stringstream s;
s << "\"" << value->name() << "\" is used before it is defined";
ReportError(s.str());
namespace {
void AppendLoweredTypes(const Type* type, std::vector<const Type*>* result) {
DCHECK_NE(type, TypeOracle::GetNeverType());
if (type->IsConstexpr()) return;
if (type == TypeOracle::GetVoidType()) return;
if (auto* s = StructType::DynamicCast(type)) {
for (const NameAndType& field : s->fields()) {
AppendLoweredTypes(field.type, result);
}
result = value->RValue();
} else {
result = value_;
result->push_back(type);
}
}
} // namespace
TypeVector LowerType(const Type* type) {
TypeVector result;
AppendLoweredTypes(type, &result);
return result;
}
size_t LoweredSlotCount(const Type* type) { return LowerType(type).size(); }
TypeVector LowerParameterTypes(const TypeVector& parameters) {
std::vector<const Type*> result;
for (const Type* t : parameters) {
AppendLoweredTypes(t, &result);
}
return result;
}
TypeVector LowerParameterTypes(const ParameterTypes& parameter_types,
size_t arg_count) {
std::vector<const Type*> result = LowerParameterTypes(parameter_types.types);
for (size_t i = parameter_types.types.size(); i < arg_count; ++i) {
DCHECK(parameter_types.var_args);
AppendLoweredTypes(TypeOracle::GetObjectType(), &result);
}
return "implicit_cast<" + type()->GetGeneratedTypeName() + ">(" + result +
")";
return result;
}
VisitResult VisitResult::NeverResult() {
VisitResult result;
result.type_ = TypeOracle::GetNeverType();
return result;
}
} // namespace torque
......
......@@ -345,21 +345,34 @@ inline std::ostream& operator<<(std::ostream& os, const Type& t) {
class VisitResult {
public:
VisitResult() = default;
VisitResult(const Type* type, const std::string& value)
: type_(type), value_(value), declarable_{} {}
VisitResult(const Type* type, const Value* declarable);
VisitResult(const Type* type, const std::string& constexpr_value)
: type_(type), constexpr_value_(constexpr_value) {
DCHECK(type->IsConstexpr());
}
static VisitResult NeverResult();
VisitResult(const Type* type, StackRange stack_range)
: type_(type), stack_range_(stack_range) {
DCHECK(!type->IsConstexpr());
}
const Type* type() const { return type_; }
base::Optional<const Value*> declarable() const { return declarable_; }
std::string LValue() const;
std::string RValue() const;
const std::string& constexpr_value() const { return *constexpr_value_; }
const StackRange& stack_range() const { return *stack_range_; }
void SetType(const Type* new_type) { type_ = new_type; }
bool IsOnStack() const { return stack_range_ != base::nullopt; }
bool operator==(const VisitResult& other) const {
return type_ == other.type_ && constexpr_value_ == other.constexpr_value_ &&
stack_range_ == other.stack_range_;
}
private:
const Type* type_ = nullptr;
std::string value_;
base::Optional<const Value*> declarable_;
base::Optional<std::string> constexpr_value_;
base::Optional<StackRange> stack_range_;
};
VisitResult ProjectStructField(VisitResult structure,
const std::string& fieldname);
class VisitResultVector : public std::vector<VisitResult> {
public:
VisitResultVector() : std::vector<VisitResult>() {}
......@@ -420,6 +433,12 @@ bool IsAssignableFrom(const Type* to, const Type* from);
bool IsCompatibleSignature(const Signature& sig, const TypeVector& types,
const std::vector<Label*>& labels);
TypeVector LowerType(const Type* type);
size_t LoweredSlotCount(const Type* type);
TypeVector LowerParameterTypes(const TypeVector& parameters);
TypeVector LowerParameterTypes(const ParameterTypes& parameter_types,
size_t vararg_count = 0);
} // namespace torque
} // namespace internal
} // namespace v8
......
......@@ -7,6 +7,7 @@
#include <iostream>
#include <string>
#include "src/base/logging.h"
#include "src/torque/ast.h"
#include "src/torque/utils.h"
......@@ -78,9 +79,9 @@ std::string CurrentPositionAsString() {
DEFINE_CONTEXTUAL_VARIABLE(LintErrorStatus)
[[noreturn]] void ReportError(const std::string& error) {
[[noreturn]] void ReportErrorString(const std::string& error) {
std::cerr << CurrentPositionAsString() << ": Torque error: " << error << "\n";
std::abort();
v8::base::OS::Abort();
}
void LintError(const std::string& error) {
......
......@@ -32,7 +32,6 @@ class LintErrorStatus : public ContextualClass<LintErrorStatus> {
bool has_lint_errors_;
};
[[noreturn]] void ReportError(const std::string& error);
void LintError(const std::string& error);
// Prints a LintError with the format "{type} '{name}' doesn't follow
......@@ -46,6 +45,14 @@ bool IsSnakeCase(const std::string& s);
bool IsValidModuleConstName(const std::string& s);
bool IsValidTypeName(const std::string& s);
[[noreturn]] void ReportErrorString(const std::string& error);
template <class... Args>
[[noreturn]] void ReportError(Args&&... args) {
std::stringstream s;
USE((s << std::forward<Args>(args))...);
ReportErrorString(s.str());
}
std::string CamelifyString(const std::string& underscore_string);
std::string DashifyString(const std::string& underscore_string);
......@@ -106,6 +113,149 @@ void PrintCommaSeparatedList(std::ostream& os, const T& list) {
}
}
struct BottomOffset {
size_t offset;
BottomOffset& operator++() {
++offset;
return *this;
}
BottomOffset operator+(size_t x) const { return BottomOffset{offset + x}; }
BottomOffset operator-(size_t x) const {
DCHECK_LE(x, offset);
return BottomOffset{offset - x};
}
bool operator<(const BottomOffset& other) const {
return offset < other.offset;
}
bool operator<=(const BottomOffset& other) const {
return offset <= other.offset;
}
bool operator==(const BottomOffset& other) const {
return offset == other.offset;
}
bool operator!=(const BottomOffset& other) const {
return offset != other.offset;
}
};
inline std::ostream& operator<<(std::ostream& out, BottomOffset from_bottom) {
return out << "BottomOffset{" << from_bottom.offset << "}";
}
// An iterator-style range of stack slots.
class StackRange {
public:
StackRange(BottomOffset begin, BottomOffset end) : begin_(begin), end_(end) {
DCHECK_LE(begin_, end_);
}
bool operator==(const StackRange& other) const {
return begin_ == other.begin_ && end_ == other.end_;
}
void Extend(StackRange adjacent) {
DCHECK_EQ(end_, adjacent.begin_);
end_ = adjacent.end_;
}
size_t Size() const { return end_.offset - begin_.offset; }
BottomOffset begin() const { return begin_; }
BottomOffset end() const { return end_; }
private:
BottomOffset begin_;
BottomOffset end_;
};
template <class T>
class Stack {
public:
using value_type = T;
Stack() = default;
Stack(std::initializer_list<T> initializer)
: Stack(std::vector<T>(initializer)) {}
explicit Stack(std::vector<T> v) : elements_(std::move(v)) {}
size_t Size() const { return elements_.size(); }
const T& Peek(BottomOffset from_bottom) const {
return elements_.at(from_bottom.offset);
}
void Poke(BottomOffset from_bottom, T x) {
elements_.at(from_bottom.offset) = std::move(x);
}
void Push(T x) { elements_.push_back(std::move(x)); }
StackRange TopRange(size_t slot_count) const {
DCHECK_GE(Size(), slot_count);
return StackRange{AboveTop() - slot_count, AboveTop()};
}
StackRange PushMany(const std::vector<T>& v) {
for (const T& x : v) {
Push(x);
}
return TopRange(v.size());
}
const T& Top() const { return Peek(AboveTop() - 1); }
T Pop() {
T result = std::move(elements_.back());
elements_.pop_back();
return result;
}
std::vector<T> PopMany(size_t count) {
DCHECK_GE(elements_.size(), count);
std::vector<T> result;
result.reserve(count);
for (auto it = elements_.end() - count; it != elements_.end(); ++it) {
result.push_back(std::move(*it));
}
elements_.resize(elements_.size() - count);
return result;
}
// The invalid offset above the top element. This is useful for StackRange.
BottomOffset AboveTop() const { return BottomOffset{Size()}; }
// Delete the slots in {range}, moving higher slots to fill the gap.
void DeleteRange(StackRange range) {
DCHECK_LE(range.end(), AboveTop());
for (BottomOffset i = range.begin();
i < std::min(range.end(), AboveTop() - range.Size()); ++i) {
elements_[i.offset] = std::move(elements_[i.offset + range.Size()]);
}
elements_.resize(elements_.size() - range.Size());
}
bool operator==(const Stack& other) const {
return elements_ == other.elements_;
}
bool operator!=(const Stack& other) const {
return elements_ != other.elements_;
}
T* begin() { return elements_.data(); }
T* end() { return begin() + elements_.size(); }
const T* begin() const { return elements_.data(); }
const T* end() const { return begin() + elements_.size(); }
private:
std::vector<T> elements_;
};
template <class T>
T* CheckNotNull(T* x) {
CHECK_NOT_NULL(x);
return x;
}
class ToString {
public:
template <class T>
ToString& operator<<(T&& x) {
s_ << std::forward<T>(x);
return *this;
}
operator std::string() { return s_.str(); }
private:
std::stringstream s_;
};
} // namespace torque
} // namespace internal
} // namespace v8
......
// Copyright 2012 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.
......
......@@ -143,11 +143,12 @@ module test {
GenericMacroTestWithLabels<Object>(param2: Object): Object
labels Y {
return param2;
return Cast<Smi>(param2) otherwise Y;
}
macro TestMacroSpecialization() {
try {
const smi0: Smi = 0;
check(GenericMacroTest<Smi>(0) == Undefined);
check(GenericMacroTest<Smi>(1) == Undefined);
check(GenericMacroTest<Object>(Null) == Null);
......@@ -155,8 +156,11 @@ module test {
check(GenericMacroTest<Object>(True) == True);
check(GenericMacroTestWithLabels<Smi>(0) otherwise Fail == Undefined);
check(GenericMacroTestWithLabels<Smi>(0) otherwise Fail == Undefined);
check(GenericMacroTestWithLabels<Object>(Null) otherwise Fail == Null);
check(GenericMacroTestWithLabels<Object>(False) otherwise Fail == False);
check(GenericMacroTestWithLabels<Object>(smi0) otherwise Fail == smi0);
try {
GenericMacroTestWithLabels<Object>(False) otherwise Expected;
}
label Expected {}
}
label Fail {
unreachable;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment