PDBFPO: Improvements to the AST visitor

Summary:
This patch attempts to solve two issues made this code hard to follow
for me.

The first issue was that a lot of what these visitors do is mutate the
AST. The visitor pattern is not particularly good for that because by
the time you have performed the dynamic type dispatch, it's too late to
go back to the parent node, and change its pointer. The previous code
dealt with that relatively elegantly, but it still meant that one had to
perform manual type checks, which is what the visitor pattern is
supposed to avoid.

The second issue was not being able to return values from the Visit
functions, which meant that one had to store function results in member
variables (a common problem with visitor patterns).

Here, I solve both problems by making the visitor use a type switch
instead of going through double dispatch on the visited object.  This
allows one to parameterize the visitor based on the return type and pass
function results as function results. The mutation is fascilitated by
having each Visit function take two arguments -- a reference to the
object itself (with the correct dynamic type), and a reference to the
parent's pointer to this object.

Although this wasn't my explicit goal here, the fact that we're not
using virtual dispatch anymore  allows us to make the AST nodes
trivially destructible, which is a good thing, since we were not
destroying them anyway.

Reviewers: aleksandr.urakov, amccarth

Subscribers: lldb-commits

Differential Revision: https://reviews.llvm.org/D60410

llvm-svn: 358261
This commit is contained in:
Pavel Labath 2019-04-12 07:19:00 +00:00
parent b6926bdcff
commit 85ce053d7e
1 changed files with 125 additions and 147 deletions

View File

@ -25,12 +25,11 @@ using namespace lldb_private;
namespace {
class FPOProgramNode;
class FPOProgramASTVisitor;
class NodeAllocator {
public:
template <typename T, typename... Args> T *makeNode(Args &&... args) {
static_assert(std::is_trivially_destructible<T>::value,
"This object will not be destroyed!");
void *new_node_mem = m_alloc.Allocate(sizeof(T), alignof(T));
return new (new_node_mem) T(std::forward<Args>(args)...);
}
@ -53,9 +52,6 @@ protected:
FPOProgramNode(Kind kind) : m_token_kind(kind) {}
public:
virtual ~FPOProgramNode() = default;
virtual void Accept(FPOProgramASTVisitor &visitor) = 0;
Kind GetKind() const { return m_token_kind; }
private:
@ -67,8 +63,6 @@ public:
FPOProgramNodeSymbol(llvm::StringRef name)
: FPOProgramNode(Symbol), m_name(name) {}
void Accept(FPOProgramASTVisitor &visitor) override;
llvm::StringRef GetName() const { return m_name; }
static bool classof(const FPOProgramNode *node) {
@ -84,8 +78,6 @@ public:
FPOProgramNodeRegisterRef(uint32_t lldb_reg_num)
: FPOProgramNode(Register), m_lldb_reg_num(lldb_reg_num) {}
void Accept(FPOProgramASTVisitor &visitor) override;
uint32_t GetLLDBRegNum() const { return m_lldb_reg_num; }
static bool classof(const FPOProgramNode *node) {
@ -101,8 +93,6 @@ public:
FPOProgramNodeIntegerLiteral(uint32_t value)
: FPOProgramNode(IntegerLiteral), m_value(value) {}
void Accept(FPOProgramASTVisitor &visitor) override;
uint32_t GetValue() const { return m_value; }
static bool classof(const FPOProgramNode *node) {
@ -126,8 +116,6 @@ public:
: FPOProgramNode(BinaryOp), m_op_type(op_type), m_left(&left),
m_right(&right) {}
void Accept(FPOProgramASTVisitor &visitor) override;
OpType GetOpType() const { return m_op_type; }
const FPOProgramNode *Left() const { return m_left; }
@ -155,8 +143,6 @@ public:
FPOProgramNodeUnaryOp(OpType op_type, FPOProgramNode &operand)
: FPOProgramNode(UnaryOp), m_op_type(op_type), m_operand(&operand) {}
void Accept(FPOProgramASTVisitor &visitor) override;
OpType GetOpType() const { return m_op_type; }
const FPOProgramNode *Operand() const { return m_operand; }
@ -171,84 +157,108 @@ private:
FPOProgramNode *m_operand;
};
template <typename ResultT = void>
class FPOProgramASTVisitor {
public:
virtual ~FPOProgramASTVisitor() = default;
protected:
virtual ResultT Visit(FPOProgramNodeBinaryOp &binary,
FPOProgramNode *&ref) = 0;
virtual ResultT Visit(FPOProgramNodeUnaryOp &unary, FPOProgramNode *&ref) = 0;
virtual ResultT Visit(FPOProgramNodeRegisterRef &reg, FPOProgramNode *&) = 0;
virtual ResultT Visit(FPOProgramNodeIntegerLiteral &integer,
FPOProgramNode *&) = 0;
virtual ResultT Visit(FPOProgramNodeSymbol &symbol, FPOProgramNode *&ref) = 0;
ResultT Dispatch(FPOProgramNode *&node) {
switch (node->GetKind()) {
case FPOProgramNode::Register:
return Visit(llvm::cast<FPOProgramNodeRegisterRef>(*node), node);
case FPOProgramNode::Symbol:
return Visit(llvm::cast<FPOProgramNodeSymbol>(*node), node);
case FPOProgramNode::IntegerLiteral:
return Visit(llvm::cast<FPOProgramNodeIntegerLiteral>(*node), node);
case FPOProgramNode::UnaryOp:
return Visit(llvm::cast<FPOProgramNodeUnaryOp>(*node), node);
case FPOProgramNode::BinaryOp:
return Visit(llvm::cast<FPOProgramNodeBinaryOp>(*node), node);
}
llvm_unreachable("Fully covered switch!");
}
virtual void Visit(FPOProgramNodeSymbol &node) {}
virtual void Visit(FPOProgramNodeRegisterRef &node) {}
virtual void Visit(FPOProgramNodeIntegerLiteral &node) {}
virtual void Visit(FPOProgramNodeBinaryOp &node) {}
virtual void Visit(FPOProgramNodeUnaryOp &node) {}
};
void FPOProgramNodeSymbol::Accept(FPOProgramASTVisitor &visitor) {
visitor.Visit(*this);
}
void FPOProgramNodeRegisterRef::Accept(FPOProgramASTVisitor &visitor) {
visitor.Visit(*this);
}
void FPOProgramNodeIntegerLiteral::Accept(FPOProgramASTVisitor &visitor) {
visitor.Visit(*this);
}
void FPOProgramNodeBinaryOp::Accept(FPOProgramASTVisitor &visitor) {
visitor.Visit(*this);
}
void FPOProgramNodeUnaryOp::Accept(FPOProgramASTVisitor &visitor) {
visitor.Visit(*this);
}
class FPOProgramASTVisitorMergeDependent : public FPOProgramASTVisitor {
class FPOProgramASTVisitorMergeDependent : public FPOProgramASTVisitor<> {
public:
void Visit(FPOProgramNodeBinaryOp &binary, FPOProgramNode *&) override {
Dispatch(binary.Left());
Dispatch(binary.Right());
}
void Visit(FPOProgramNodeUnaryOp &unary, FPOProgramNode *&) override {
Dispatch(unary.Operand());
}
void Visit(FPOProgramNodeRegisterRef &, FPOProgramNode *&) override {}
void Visit(FPOProgramNodeIntegerLiteral &, FPOProgramNode *&) override {}
void Visit(FPOProgramNodeSymbol &symbol, FPOProgramNode *&ref) override;
static void Merge(const llvm::DenseMap<llvm::StringRef, FPOProgramNode *>
&dependent_programs,
FPOProgramNode *&ast) {
FPOProgramASTVisitorMergeDependent(dependent_programs).Dispatch(ast);
}
private:
FPOProgramASTVisitorMergeDependent(
const llvm::DenseMap<llvm::StringRef, FPOProgramNode *>
&dependent_programs)
: m_dependent_programs(dependent_programs) {}
void Merge(FPOProgramNode *&node_ref);
private:
void Visit(FPOProgramNodeBinaryOp &node) override;
void Visit(FPOProgramNodeUnaryOp &node) override;
void TryReplace(FPOProgramNode *&node_ref) const;
private:
const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> &m_dependent_programs;
};
void FPOProgramASTVisitorMergeDependent::Merge(FPOProgramNode *&node_ref) {
TryReplace(node_ref);
node_ref->Accept(*this);
void FPOProgramASTVisitorMergeDependent::Visit(FPOProgramNodeSymbol &symbol,
FPOProgramNode *&ref) {
auto it = m_dependent_programs.find(symbol.GetName());
if (it == m_dependent_programs.end())
return;
ref = it->second;
Dispatch(ref);
}
void FPOProgramASTVisitorMergeDependent::Visit(FPOProgramNodeBinaryOp &node) {
Merge(node.Left());
Merge(node.Right());
}
void FPOProgramASTVisitorMergeDependent::Visit(FPOProgramNodeUnaryOp &node) {
Merge(node.Operand());
}
void FPOProgramASTVisitorMergeDependent::TryReplace(
FPOProgramNode *&node_ref) const {
while (auto *symbol = llvm::dyn_cast<FPOProgramNodeSymbol>(node_ref)) {
auto it = m_dependent_programs.find(symbol->GetName());
if (it == m_dependent_programs.end()) {
break;
}
node_ref = it->second;
}
}
class FPOProgramASTVisitorResolveRegisterRefs : public FPOProgramASTVisitor {
class FPOProgramASTVisitorResolveRegisterRefs
: public FPOProgramASTVisitor<bool> {
public:
static bool Resolve(const llvm::DenseMap<llvm::StringRef, FPOProgramNode *>
&dependent_programs,
llvm::Triple::ArchType arch_type, NodeAllocator &alloc,
FPOProgramNode *&ast) {
return FPOProgramASTVisitorResolveRegisterRefs(dependent_programs,
arch_type, alloc)
.Dispatch(ast);
}
bool Visit(FPOProgramNodeBinaryOp &binary, FPOProgramNode *&) override {
return Dispatch(binary.Left()) && Dispatch(binary.Right());
}
bool Visit(FPOProgramNodeUnaryOp &unary, FPOProgramNode *&) override {
return Dispatch(unary.Operand());
}
bool Visit(FPOProgramNodeRegisterRef &, FPOProgramNode *&) override {
return true;
}
bool Visit(FPOProgramNodeIntegerLiteral &, FPOProgramNode *&) override {
return true;
}
bool Visit(FPOProgramNodeSymbol &symbol, FPOProgramNode *&ref) override;
private:
FPOProgramASTVisitorResolveRegisterRefs(
const llvm::DenseMap<llvm::StringRef, FPOProgramNode *>
&dependent_programs,
@ -256,27 +266,11 @@ public:
: m_dependent_programs(dependent_programs), m_arch_type(arch_type),
m_alloc(alloc) {}
bool Resolve(FPOProgramNode *&program);
private:
void Visit(FPOProgramNodeBinaryOp &node) override;
void Visit(FPOProgramNodeUnaryOp &node) override;
bool TryReplace(FPOProgramNode *&node_ref);
const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> &m_dependent_programs;
llvm::Triple::ArchType m_arch_type;
NodeAllocator &m_alloc;
bool m_no_error_flag = true;
};
bool FPOProgramASTVisitorResolveRegisterRefs::Resolve(FPOProgramNode *&program) {
if (!TryReplace(program))
return false;
program->Accept(*this);
return m_no_error_flag;
}
static uint32_t ResolveLLDBRegisterNum(llvm::StringRef reg_name, llvm::Triple::ArchType arch_type) {
// lookup register name to get lldb register number
llvm::ArrayRef<llvm::EnumEntry<uint16_t>> register_names =
@ -294,62 +288,49 @@ static uint32_t ResolveLLDBRegisterNum(llvm::StringRef reg_name, llvm::Triple::A
return npdb::GetLLDBRegisterNumber(arch_type, reg_id);
}
bool FPOProgramASTVisitorResolveRegisterRefs::TryReplace(
FPOProgramNode *&node_ref) {
auto *symbol = llvm::dyn_cast<FPOProgramNodeSymbol>(node_ref);
if (!symbol)
return true;
bool FPOProgramASTVisitorResolveRegisterRefs::Visit(
FPOProgramNodeSymbol &symbol, FPOProgramNode *&ref) {
// Look up register reference as lvalue in preceding assignments.
auto it = m_dependent_programs.find(symbol->GetName());
auto it = m_dependent_programs.find(symbol.GetName());
if (it != m_dependent_programs.end()) {
// Dependent programs are handled elsewhere.
return true;
}
uint32_t reg_num =
ResolveLLDBRegisterNum(symbol->GetName().drop_front(1), m_arch_type);
ResolveLLDBRegisterNum(symbol.GetName().drop_front(1), m_arch_type);
if (reg_num == LLDB_INVALID_REGNUM)
return false;
node_ref = m_alloc.makeNode<FPOProgramNodeRegisterRef>(reg_num);
ref = m_alloc.makeNode<FPOProgramNodeRegisterRef>(reg_num);
return true;
}
void FPOProgramASTVisitorResolveRegisterRefs::Visit(
FPOProgramNodeBinaryOp &node) {
m_no_error_flag = Resolve(node.Left()) && Resolve(node.Right());
}
void FPOProgramASTVisitorResolveRegisterRefs::Visit(
FPOProgramNodeUnaryOp &node) {
m_no_error_flag = Resolve(node.Operand());
}
class FPOProgramASTVisitorDWARFCodegen : public FPOProgramASTVisitor {
class FPOProgramASTVisitorDWARFCodegen : public FPOProgramASTVisitor<> {
public:
static void Emit(Stream &stream, FPOProgramNode *&ast) {
FPOProgramASTVisitorDWARFCodegen(stream).Dispatch(ast);
}
void Visit(FPOProgramNodeRegisterRef &reg, FPOProgramNode *&);
void Visit(FPOProgramNodeBinaryOp &binary, FPOProgramNode *&);
void Visit(FPOProgramNodeUnaryOp &unary, FPOProgramNode *&);
void Visit(FPOProgramNodeSymbol &symbol, FPOProgramNode *&) {
llvm_unreachable("Symbols should have been resolved by now!");
}
void Visit(FPOProgramNodeIntegerLiteral &integer, FPOProgramNode *&);
private:
FPOProgramASTVisitorDWARFCodegen(Stream &stream) : m_out_stream(stream) {}
void Emit(FPOProgramNode &program);
private:
void Visit(FPOProgramNodeRegisterRef &node) override;
void Visit(FPOProgramNodeIntegerLiteral &node) override;
void Visit(FPOProgramNodeBinaryOp &node) override;
void Visit(FPOProgramNodeUnaryOp &node) override;
private:
Stream &m_out_stream;
};
void FPOProgramASTVisitorDWARFCodegen::Emit(FPOProgramNode &program) {
program.Accept(*this);
}
void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeRegisterRef &reg,
FPOProgramNode *&) {
void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeRegisterRef &node) {
uint32_t reg_num = node.GetLLDBRegNum();
uint32_t reg_num = reg.GetLLDBRegNum();
lldbassert(reg_num != LLDB_INVALID_REGNUM);
if (reg_num > 31) {
@ -362,18 +343,18 @@ void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeRegisterRef &node) {
}
void FPOProgramASTVisitorDWARFCodegen::Visit(
FPOProgramNodeIntegerLiteral &node) {
uint32_t value = node.GetValue();
FPOProgramNodeIntegerLiteral &integer, FPOProgramNode *&) {
uint32_t value = integer.GetValue();
m_out_stream.PutHex8(DW_OP_constu);
m_out_stream.PutULEB128(value);
}
void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeBinaryOp &node) {
void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeBinaryOp &binary,
FPOProgramNode *&) {
Dispatch(binary.Left());
Dispatch(binary.Right());
Emit(*node.Left());
Emit(*node.Right());
switch (node.GetOpType()) {
switch (binary.GetOpType()) {
case FPOProgramNodeBinaryOp::Plus:
m_out_stream.PutHex8(DW_OP_plus);
// NOTE: can be optimized by using DW_OP_plus_uconst opcpode
@ -395,10 +376,11 @@ void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeBinaryOp &node) {
}
}
void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeUnaryOp &node) {
Emit(*node.Operand());
void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeUnaryOp &unary,
FPOProgramNode *&) {
Dispatch(unary.Operand());
switch (node.GetOpType()) {
switch (unary.GetOpType()) {
case FPOProgramNodeUnaryOp::Deref:
m_out_stream.PutHex8(DW_OP_deref);
break;
@ -523,19 +505,16 @@ static FPOProgramNode *ParseFPOProgram(llvm::StringRef program,
lldbassert(rvalue_ast);
// check & resolve assignment program
FPOProgramASTVisitorResolveRegisterRefs resolver(dependent_programs,
arch_type, alloc);
if (!resolver.Resolve(rvalue_ast)) {
if (!FPOProgramASTVisitorResolveRegisterRefs::Resolve(
dependent_programs, arch_type, alloc, rvalue_ast))
return nullptr;
}
if (lvalue_name == register_name) {
// found target assignment program - no need to parse further
// emplace valid dependent subtrees to make target assignment independent
// from predecessors
FPOProgramASTVisitorMergeDependent merger(dependent_programs);
merger.Merge(rvalue_ast);
FPOProgramASTVisitorMergeDependent::Merge(dependent_programs, rvalue_ast);
return rvalue_ast;
}
@ -557,7 +536,6 @@ bool lldb_private::npdb::TranslateFPOProgramToDWARFExpression(
return false;
}
FPOProgramASTVisitorDWARFCodegen codegen(stream);
codegen.Emit(*target_program);
FPOProgramASTVisitorDWARFCodegen::Emit(stream, target_program);
return true;
}