escape: Remove previously existing analysis.
* Make-lang.in (GO_OBJS): Remove go/dataflow.o, go/escape.o. Reviewed-on: https://go-review.googlesource.com/18261 From-SVN: r235649
This commit is contained in:
parent
52d11a4bbf
commit
e49aacaf30
|
@ -1,3 +1,7 @@
|
||||||
|
2016-04-29 Chris Manghane <cmang@google.com>
|
||||||
|
|
||||||
|
* Make-lang.in (GO_OBJS): Remove go/dataflow.o, go/escape.o.
|
||||||
|
|
||||||
2016-04-18 Michael Matz <matz@suse.de>
|
2016-04-18 Michael Matz <matz@suse.de>
|
||||||
|
|
||||||
* go-gcc.cc (Gcc_backend::implicit_variable): Use SET_DECL_ALIGN.
|
* go-gcc.cc (Gcc_backend::implicit_variable): Use SET_DECL_ALIGN.
|
||||||
|
|
|
@ -50,8 +50,6 @@ go-warn = $(STRICT_WARN)
|
||||||
|
|
||||||
GO_OBJS = \
|
GO_OBJS = \
|
||||||
go/ast-dump.o \
|
go/ast-dump.o \
|
||||||
go/dataflow.o \
|
|
||||||
go/escape.o \
|
|
||||||
go/export.o \
|
go/export.o \
|
||||||
go/expressions.o \
|
go/expressions.o \
|
||||||
go/go-backend.o \
|
go/go-backend.o \
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
50b2b468a85045c66d60112dc094c31ec4897123
|
46b108136c0d102f181f0cc7c398e3db8c4d08a3
|
||||||
|
|
||||||
The first line of this file holds the git revision number of the last
|
The first line of this file holds the git revision number of the last
|
||||||
merge done from the gofrontend repository.
|
merge done from the gofrontend repository.
|
||||||
|
|
|
@ -1,299 +0,0 @@
|
||||||
// dataflow.cc -- Go frontend dataflow.
|
|
||||||
|
|
||||||
// Copyright 2009 The Go 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 "go-system.h"
|
|
||||||
|
|
||||||
#include "gogo.h"
|
|
||||||
#include "expressions.h"
|
|
||||||
#include "statements.h"
|
|
||||||
#include "dataflow.h"
|
|
||||||
|
|
||||||
// This class is used to traverse the tree to look for uses of
|
|
||||||
// variables.
|
|
||||||
|
|
||||||
class Dataflow_traverse_expressions : public Traverse
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Dataflow_traverse_expressions(Dataflow* dataflow, Statement* statement)
|
|
||||||
: Traverse(traverse_blocks | traverse_expressions),
|
|
||||||
dataflow_(dataflow), statement_(statement)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// Only look at top-level expressions: do not descend into blocks.
|
|
||||||
// They will be examined via Dataflow_traverse_statements.
|
|
||||||
int
|
|
||||||
block(Block*)
|
|
||||||
{ return TRAVERSE_SKIP_COMPONENTS; }
|
|
||||||
|
|
||||||
int
|
|
||||||
expression(Expression**);
|
|
||||||
|
|
||||||
private:
|
|
||||||
// The dataflow information.
|
|
||||||
Dataflow* dataflow_;
|
|
||||||
// The Statement in which we are looking.
|
|
||||||
Statement* statement_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Given an expression, return the Named_object that it refers to, if
|
|
||||||
// it is a local variable.
|
|
||||||
|
|
||||||
static Named_object*
|
|
||||||
get_var(Expression* expr)
|
|
||||||
{
|
|
||||||
Var_expression* ve = expr->var_expression();
|
|
||||||
if (ve == NULL)
|
|
||||||
return NULL;
|
|
||||||
Named_object* no = ve->named_object();
|
|
||||||
go_assert(no->is_variable() || no->is_result_variable());
|
|
||||||
if (no->is_variable() && no->var_value()->is_global())
|
|
||||||
return NULL;
|
|
||||||
return no;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look for a reference to a variable in an expression.
|
|
||||||
|
|
||||||
int
|
|
||||||
Dataflow_traverse_expressions::expression(Expression** expr)
|
|
||||||
{
|
|
||||||
Named_object* no = get_var(*expr);
|
|
||||||
if (no != NULL)
|
|
||||||
this->dataflow_->add_ref(no, this->statement_);
|
|
||||||
return TRAVERSE_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This class is used to handle an assignment statement.
|
|
||||||
|
|
||||||
class Dataflow_traverse_assignment : public Traverse_assignments
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Dataflow_traverse_assignment(Dataflow* dataflow, Statement* statement)
|
|
||||||
: dataflow_(dataflow), statement_(statement)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void
|
|
||||||
initialize_variable(Named_object*);
|
|
||||||
|
|
||||||
void
|
|
||||||
assignment(Expression** lhs, Expression** rhs);
|
|
||||||
|
|
||||||
void
|
|
||||||
value(Expression**, bool, bool);
|
|
||||||
|
|
||||||
private:
|
|
||||||
// The dataflow information.
|
|
||||||
Dataflow* dataflow_;
|
|
||||||
// The Statement in which we are looking.
|
|
||||||
Statement* statement_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handle a variable initialization.
|
|
||||||
|
|
||||||
void
|
|
||||||
Dataflow_traverse_assignment::initialize_variable(Named_object* var)
|
|
||||||
{
|
|
||||||
Expression* init = var->var_value()->init();
|
|
||||||
this->dataflow_->add_def(var, init, this->statement_, true);
|
|
||||||
if (init != NULL)
|
|
||||||
{
|
|
||||||
Expression* e = init;
|
|
||||||
this->value(&e, true, true);
|
|
||||||
go_assert(e == init);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle an assignment in a statement.
|
|
||||||
|
|
||||||
void
|
|
||||||
Dataflow_traverse_assignment::assignment(Expression** plhs, Expression** prhs)
|
|
||||||
{
|
|
||||||
Named_object* no = get_var(*plhs);
|
|
||||||
if (no != NULL)
|
|
||||||
{
|
|
||||||
Expression* rhs = prhs == NULL ? NULL : *prhs;
|
|
||||||
this->dataflow_->add_def(no, rhs, this->statement_, false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If this is not a variable it may be some computed lvalue, and
|
|
||||||
// we want to look for references to variables in that lvalue.
|
|
||||||
this->value(plhs, false, false);
|
|
||||||
}
|
|
||||||
if (prhs != NULL)
|
|
||||||
this->value(prhs, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle a value in a statement.
|
|
||||||
|
|
||||||
void
|
|
||||||
Dataflow_traverse_assignment::value(Expression** pexpr, bool, bool)
|
|
||||||
{
|
|
||||||
Named_object* no = get_var(*pexpr);
|
|
||||||
if (no != NULL)
|
|
||||||
this->dataflow_->add_ref(no, this->statement_);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Dataflow_traverse_expressions dte(this->dataflow_, this->statement_);
|
|
||||||
Expression::traverse(pexpr, &dte);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This class is used to traverse the tree to look for statements.
|
|
||||||
|
|
||||||
class Dataflow_traverse_statements : public Traverse
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Dataflow_traverse_statements(Dataflow* dataflow)
|
|
||||||
: Traverse(traverse_statements),
|
|
||||||
dataflow_(dataflow)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
int
|
|
||||||
statement(Block*, size_t* pindex, Statement*);
|
|
||||||
|
|
||||||
private:
|
|
||||||
// The dataflow information.
|
|
||||||
Dataflow* dataflow_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// For each Statement, we look for expressions.
|
|
||||||
|
|
||||||
int
|
|
||||||
Dataflow_traverse_statements::statement(Block* block, size_t* pindex,
|
|
||||||
Statement *statement)
|
|
||||||
{
|
|
||||||
Dataflow_traverse_assignment dta(this->dataflow_, statement);
|
|
||||||
|
|
||||||
// For thunk statements, make sure to traverse the call expression to
|
|
||||||
// find any reference to a variable being used as an argument.
|
|
||||||
if (!statement->traverse_assignments(&dta)
|
|
||||||
|| statement->thunk_statement() != NULL)
|
|
||||||
{
|
|
||||||
// Case statements in selects will be lowered into temporaries at this
|
|
||||||
// point so our dataflow analysis will miss references between a/c and ch
|
|
||||||
// in case statements of the form a,c := <-ch. Do a special dataflow
|
|
||||||
// analysis for select statements here; the analysis for the blocks will
|
|
||||||
// be handled as usual.
|
|
||||||
if (statement->select_statement() != NULL)
|
|
||||||
statement->select_statement()->analyze_dataflow(this->dataflow_);
|
|
||||||
|
|
||||||
Dataflow_traverse_expressions dte(this->dataflow_, statement);
|
|
||||||
statement->traverse(block, pindex, &dte);
|
|
||||||
}
|
|
||||||
return TRAVERSE_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare variables.
|
|
||||||
|
|
||||||
bool
|
|
||||||
Dataflow::Compare_vars::operator()(const Named_object* no1,
|
|
||||||
const Named_object* no2) const
|
|
||||||
{
|
|
||||||
if (no1->name() < no2->name())
|
|
||||||
return true;
|
|
||||||
if (no1->name() > no2->name())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// We can have two different variables with the same name.
|
|
||||||
Location loc1 = no1->location();
|
|
||||||
Location loc2 = no2->location();
|
|
||||||
if (loc1 < loc2)
|
|
||||||
return false;
|
|
||||||
if (loc1 > loc2)
|
|
||||||
return true;
|
|
||||||
if (Linemap::is_predeclared_location(loc1))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (no1 == no2
|
|
||||||
|| (no1->is_result_variable()
|
|
||||||
&& no2->is_result_variable())
|
|
||||||
|| ((no1->is_variable()
|
|
||||||
&& no1->var_value()->is_type_switch_var())
|
|
||||||
&& (no2->is_variable()
|
|
||||||
&& no2->var_value()->is_type_switch_var())))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// We can't have two variables with the same name in the same
|
|
||||||
// location unless they are type switch variables which share the same
|
|
||||||
// fake location.
|
|
||||||
go_unreachable();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Class Dataflow.
|
|
||||||
|
|
||||||
Dataflow::Dataflow()
|
|
||||||
: defs_(), refs_()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the dataflow information.
|
|
||||||
|
|
||||||
void
|
|
||||||
Dataflow::initialize(Gogo* gogo)
|
|
||||||
{
|
|
||||||
Dataflow_traverse_statements dts(this);
|
|
||||||
gogo->traverse(&dts);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a definition of a variable.
|
|
||||||
|
|
||||||
void
|
|
||||||
Dataflow::add_def(Named_object* var, Expression* val, Statement* statement,
|
|
||||||
bool is_init)
|
|
||||||
{
|
|
||||||
Defs* defnull = NULL;
|
|
||||||
std::pair<Defmap::iterator, bool> ins =
|
|
||||||
this->defs_.insert(std::make_pair(var, defnull));
|
|
||||||
if (ins.second)
|
|
||||||
ins.first->second = new Defs;
|
|
||||||
Def def;
|
|
||||||
def.statement = statement;
|
|
||||||
def.val = val;
|
|
||||||
def.is_init = is_init;
|
|
||||||
ins.first->second->push_back(def);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a reference to a variable.
|
|
||||||
|
|
||||||
void
|
|
||||||
Dataflow::add_ref(Named_object* var, Statement* statement)
|
|
||||||
{
|
|
||||||
Refs* refnull = NULL;
|
|
||||||
std::pair<Refmap::iterator, bool> ins =
|
|
||||||
this->refs_.insert(std::make_pair(var, refnull));
|
|
||||||
if (ins.second)
|
|
||||||
ins.first->second = new Refs;
|
|
||||||
Ref ref;
|
|
||||||
ref.statement = statement;
|
|
||||||
ins.first->second->push_back(ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the definitions of a variable.
|
|
||||||
|
|
||||||
const Dataflow::Defs*
|
|
||||||
Dataflow::find_defs(Named_object* var) const
|
|
||||||
{
|
|
||||||
Defmap::const_iterator p = this->defs_.find(var);
|
|
||||||
if (p == this->defs_.end())
|
|
||||||
return NULL;
|
|
||||||
else
|
|
||||||
return p->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the references of a variable.
|
|
||||||
|
|
||||||
const Dataflow::Refs*
|
|
||||||
Dataflow::find_refs(Named_object* var) const
|
|
||||||
{
|
|
||||||
Refmap::const_iterator p = this->refs_.find(var);
|
|
||||||
if (p == this->refs_.end())
|
|
||||||
return NULL;
|
|
||||||
else
|
|
||||||
return p->second;
|
|
||||||
}
|
|
|
@ -1,91 +0,0 @@
|
||||||
// dataflow.h -- Go frontend dataflow. -*- C++ -*-
|
|
||||||
|
|
||||||
// Copyright 2009 The Go 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 GO_DATAFLOW_H
|
|
||||||
#define GO_DATAFLOW_H
|
|
||||||
|
|
||||||
class Expression;
|
|
||||||
class Named_object;
|
|
||||||
class Statement;
|
|
||||||
|
|
||||||
// Dataflow information about the Go program.
|
|
||||||
|
|
||||||
class Dataflow
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// A variable definition.
|
|
||||||
struct Def
|
|
||||||
{
|
|
||||||
// The statement where the variable is defined.
|
|
||||||
Statement* statement;
|
|
||||||
// The value to which the variable is set. This may be NULL.
|
|
||||||
Expression* val;
|
|
||||||
// Whether this is an initialization of the variable.
|
|
||||||
bool is_init;
|
|
||||||
};
|
|
||||||
|
|
||||||
// A variable reference.
|
|
||||||
struct Ref
|
|
||||||
{
|
|
||||||
// The statement where the variable is referenced.
|
|
||||||
Statement* statement;
|
|
||||||
};
|
|
||||||
|
|
||||||
// A list of defs.
|
|
||||||
typedef std::vector<Def> Defs;
|
|
||||||
|
|
||||||
// A list of refs.
|
|
||||||
typedef std::vector<Ref> Refs;
|
|
||||||
|
|
||||||
Dataflow();
|
|
||||||
|
|
||||||
// Initialize the dataflow information.
|
|
||||||
void
|
|
||||||
initialize(Gogo*);
|
|
||||||
|
|
||||||
// Add a definition of a variable. STATEMENT assigns a value to
|
|
||||||
// VAR. VAL is the value if it is known, NULL otherwise.
|
|
||||||
void
|
|
||||||
add_def(Named_object* var, Expression* val, Statement* statement,
|
|
||||||
bool is_init);
|
|
||||||
|
|
||||||
// Add a reference to a variable. VAR is the variable, and
|
|
||||||
// STATEMENT is the statement which refers to it.
|
|
||||||
void
|
|
||||||
add_ref(Named_object* var, Statement* statement);
|
|
||||||
|
|
||||||
// Return the definitions of VAR--the places where it is set.
|
|
||||||
const Defs*
|
|
||||||
find_defs(Named_object* var) const;
|
|
||||||
|
|
||||||
// Return the references to VAR--the places where it is used.
|
|
||||||
const Refs*
|
|
||||||
find_refs(Named_object* var) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Order variables in the map.
|
|
||||||
struct Compare_vars
|
|
||||||
{
|
|
||||||
bool
|
|
||||||
operator()(const Named_object*, const Named_object*) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Map from variables to a list of defs of the variable. We use a
|
|
||||||
// map rather than a hash table because the order in which we
|
|
||||||
// process variables may affect the resulting code.
|
|
||||||
typedef std::map<Named_object*, Defs*, Compare_vars> Defmap;
|
|
||||||
|
|
||||||
// Map from variables to a list of refs to the vairable.
|
|
||||||
typedef std::map<Named_object*, Refs*, Compare_vars> Refmap;
|
|
||||||
|
|
||||||
// Variable defs.
|
|
||||||
Defmap defs_;
|
|
||||||
// Variable refs;
|
|
||||||
Refmap refs_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif // !defined(GO_DATAFLOW_H)
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,310 +0,0 @@
|
||||||
// escape.h -- Go frontend escape analysis. -*- C++ -*-
|
|
||||||
|
|
||||||
// Copyright 2015 The Go 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 GO_ESCAPE_H
|
|
||||||
#define GO_ESCAPE_H
|
|
||||||
|
|
||||||
#include "go-system.h"
|
|
||||||
#include "string-dump.h"
|
|
||||||
|
|
||||||
class Call_node;
|
|
||||||
class Connection_node;
|
|
||||||
class Connection_dump_context;
|
|
||||||
class Gogo;
|
|
||||||
class Named_object;
|
|
||||||
|
|
||||||
// A basic escape analysis implementation for the Go frontend based on the
|
|
||||||
// algorithm from "Escape Analysis for Java" by Choi et. al in OOPSLA '99.
|
|
||||||
// This is a simplified version of the flow insensitive analysis with the goal
|
|
||||||
// of reducing the overhead cost of garbage collection by allocating objects
|
|
||||||
// on the stack when they do not escape the function they were created in.
|
|
||||||
//
|
|
||||||
// A major simplification is that the analysis only implements what Choi refers
|
|
||||||
// to as "deferred edges" which are used to used model assignments that copy
|
|
||||||
// references from one variable to another e.g. a := b. It is unnecessary to
|
|
||||||
// consider assignments to the fields of an object because, in general, if a
|
|
||||||
// field of an object escapes and must be heap-allocated, there is no way to
|
|
||||||
// heap-allocate that escaping field without heap-allocating the entire object.
|
|
||||||
// That is, for some globally escaping object GVAR, if there is an assignment
|
|
||||||
// of the form GVAR = t.f such that field f of object t escapes, it is likely
|
|
||||||
// that t must be heap-allocated as well. In the analysis, this assignment
|
|
||||||
// will be simplified to GVAR = t, which is imprecise but has the same effect.
|
|
||||||
|
|
||||||
// This is a general graph node representing a named object used in a call graph
|
|
||||||
// or connection graph. In a call graph, each named object is either a Function
|
|
||||||
// or Function_declaration representing a function called during the program
|
|
||||||
// execution (which isn't necessarily every function declared). In a connection
|
|
||||||
// graph, there is a node for each node in the call graph, which forms the root
|
|
||||||
// of that connection graph. Each connection graph root contains nodes whose
|
|
||||||
// objects are either variables used in the function defintion or are nested
|
|
||||||
// closures created within the function definition. The connection graph is
|
|
||||||
// a way of modeling the connectivity between all objects created in a given
|
|
||||||
// function as well as understanding the relationship between input arguments
|
|
||||||
// in the caller and the formal parameters in the callee.
|
|
||||||
|
|
||||||
class Node
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum Node_classification
|
|
||||||
{
|
|
||||||
NODE_CALL,
|
|
||||||
NODE_CONNECTION
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual ~Node();
|
|
||||||
|
|
||||||
// Make a call node for FUNCTION.
|
|
||||||
static Node*
|
|
||||||
make_call(Named_object* function);
|
|
||||||
|
|
||||||
// Make a connection node for OBJECT.
|
|
||||||
// Note: values in this enum appear in export data, and therefore MUST NOT
|
|
||||||
// change.
|
|
||||||
enum Escapement_lattice
|
|
||||||
{
|
|
||||||
// ESCAPE_GLOBAL means that the object escapes all functions globally.
|
|
||||||
ESCAPE_GLOBAL = 0,
|
|
||||||
// ESCAPE_ARG with respect to a function means that the object escapes that
|
|
||||||
// function it is created in via the function's arguments or results.
|
|
||||||
ESCAPE_ARG = 1,
|
|
||||||
// ESCAPE_NONE means that the object does not escape the function in which
|
|
||||||
// it was created.
|
|
||||||
ESCAPE_NONE = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
// A list of states usually corresponding to a list of function parameters.
|
|
||||||
typedef std::vector<Escapement_lattice> Escape_states;
|
|
||||||
|
|
||||||
static Node*
|
|
||||||
make_connection(Named_object* object, Escapement_lattice e);
|
|
||||||
|
|
||||||
// Return the node classification.
|
|
||||||
Node_classification
|
|
||||||
classification() const
|
|
||||||
{ return this->classification_; }
|
|
||||||
|
|
||||||
// Return whether this is a call node.
|
|
||||||
bool
|
|
||||||
is_call() const
|
|
||||||
{ return this->classification_ == NODE_CALL; }
|
|
||||||
|
|
||||||
// Return whether this is a connection node.
|
|
||||||
bool
|
|
||||||
is_connection() const
|
|
||||||
{ return this->classification_ == NODE_CONNECTION; }
|
|
||||||
|
|
||||||
// If this is a connection node, return the Connection_node.
|
|
||||||
// Otherwise, return NULL.
|
|
||||||
Connection_node*
|
|
||||||
connection_node()
|
|
||||||
{ return this->convert<Connection_node, NODE_CONNECTION>(); }
|
|
||||||
|
|
||||||
// Return this node's unique id.
|
|
||||||
unsigned int
|
|
||||||
id() const
|
|
||||||
{ return this->id_; }
|
|
||||||
|
|
||||||
// Return this node's generated name for GraphViz.
|
|
||||||
virtual const std::string&
|
|
||||||
name() = 0;
|
|
||||||
|
|
||||||
// Return this node's generated label for GraphViz.
|
|
||||||
virtual const std::string&
|
|
||||||
label();
|
|
||||||
|
|
||||||
// Return the object this node represents.
|
|
||||||
Named_object*
|
|
||||||
object() const
|
|
||||||
{ return this->object_; }
|
|
||||||
|
|
||||||
void
|
|
||||||
add_edge(Node* v)
|
|
||||||
{ this->edges_.insert(v); }
|
|
||||||
|
|
||||||
const std::set<Node*>&
|
|
||||||
edges() const
|
|
||||||
{ return this->edges_; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Node(Node_classification, Named_object* object);
|
|
||||||
|
|
||||||
const std::string&
|
|
||||||
get_name() const
|
|
||||||
{ return this->name_; }
|
|
||||||
|
|
||||||
void
|
|
||||||
set_name(const std::string& name)
|
|
||||||
{ this->name_ = name; }
|
|
||||||
|
|
||||||
const std::string&
|
|
||||||
get_label() const
|
|
||||||
{ return this->label_; }
|
|
||||||
|
|
||||||
void
|
|
||||||
set_label(const std::string& label)
|
|
||||||
{ this->label_ = label; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
template<typename Node_class,
|
|
||||||
Node_classification node_classification>
|
|
||||||
const Node_class*
|
|
||||||
convert() const
|
|
||||||
{
|
|
||||||
return (this->classification_ == node_classification
|
|
||||||
? static_cast<const Node_class*>(this)
|
|
||||||
: NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Node_class,
|
|
||||||
Node_classification node_classification>
|
|
||||||
Node_class*
|
|
||||||
convert()
|
|
||||||
{
|
|
||||||
return (this->classification_ == node_classification
|
|
||||||
? static_cast<Node_class*>(this)
|
|
||||||
: NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The classification of this node.
|
|
||||||
Node_classification classification_;
|
|
||||||
// A unique ID for this node.
|
|
||||||
unsigned int id_;
|
|
||||||
// The name for this node e.g. "Node<ID>" used as a GraphViz identifier.
|
|
||||||
std::string name_;
|
|
||||||
// The label for this node in the GraphViz representation.
|
|
||||||
std::string label_;
|
|
||||||
// The object represented by this node.
|
|
||||||
Named_object* object_;
|
|
||||||
// A distinct set of nodes that this node has edges to.
|
|
||||||
std::set<Node*> edges_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// A node representing a function that might be called during program execution.
|
|
||||||
|
|
||||||
class Call_node : public Node
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Call_node(Named_object* function);
|
|
||||||
|
|
||||||
const std::string&
|
|
||||||
name();
|
|
||||||
};
|
|
||||||
|
|
||||||
// A node representing an object in the connection graph built for each function
|
|
||||||
// in the call graph.
|
|
||||||
|
|
||||||
class Connection_node : public Node
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Connection_node(Named_object* object, Escapement_lattice e)
|
|
||||||
: Node(NODE_CONNECTION, object),
|
|
||||||
escape_state_(e)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
// Return this node's generated name for GraphViz.
|
|
||||||
const std::string&
|
|
||||||
name();
|
|
||||||
|
|
||||||
// Return this node's generated label for GraphViz.
|
|
||||||
const std::string&
|
|
||||||
label();
|
|
||||||
|
|
||||||
// Return the escape state for this node.
|
|
||||||
Escapement_lattice
|
|
||||||
escape_state() const
|
|
||||||
{ return this->escape_state_; }
|
|
||||||
|
|
||||||
// Set the escape state for this node.
|
|
||||||
void
|
|
||||||
set_escape_state(Escapement_lattice e)
|
|
||||||
{ this->escape_state_ = e; }
|
|
||||||
|
|
||||||
// Return the objects inside of this connection graph.
|
|
||||||
// This is empty for all connection nodes that are not the root of a
|
|
||||||
// connection graph. Each node in the call graph is a root of a connection
|
|
||||||
// graph.
|
|
||||||
const std::set<Node*>&
|
|
||||||
objects() const
|
|
||||||
{ return this->objects_; }
|
|
||||||
|
|
||||||
void
|
|
||||||
add_object(Node* object)
|
|
||||||
{ this->objects_.insert(object); }
|
|
||||||
|
|
||||||
void
|
|
||||||
dump_connection(Connection_dump_context*);
|
|
||||||
|
|
||||||
private:
|
|
||||||
// The escapement of this node.
|
|
||||||
Escapement_lattice escape_state_;
|
|
||||||
// The set of nodes contained within this connection node. If this node is
|
|
||||||
// not a root of a connection graph, this will be empty.
|
|
||||||
std::set<Node*> objects_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// This class implements fgo-dump-calls. The Call graph dump of a Go program.
|
|
||||||
|
|
||||||
class Call_dump_context : public String_dump
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Call_dump_context(std::ostream* out = NULL);
|
|
||||||
|
|
||||||
// Initialize the dump context.
|
|
||||||
void
|
|
||||||
dump(Gogo*, const char* basename);
|
|
||||||
|
|
||||||
// Get dump output stream.
|
|
||||||
std::ostream&
|
|
||||||
ostream()
|
|
||||||
{ return *this->ostream_; }
|
|
||||||
|
|
||||||
// Implementation of String_dump interface.
|
|
||||||
void
|
|
||||||
write_c_string(const char*);
|
|
||||||
|
|
||||||
void
|
|
||||||
write_string(const std::string&);
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Stream on output dump file.
|
|
||||||
std::ostream* ostream_;
|
|
||||||
|
|
||||||
Gogo* gogo_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// This class implements fgo-dump-conns. The connection graph dump of
|
|
||||||
// the functions called in a Go program.
|
|
||||||
|
|
||||||
class Connection_dump_context : public String_dump
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Connection_dump_context(std::ostream* out = NULL);
|
|
||||||
|
|
||||||
// Initialize the dump context.
|
|
||||||
void
|
|
||||||
dump(Gogo*, const char* basename);
|
|
||||||
|
|
||||||
// Get dump output stream.
|
|
||||||
std::ostream&
|
|
||||||
ostream()
|
|
||||||
{ return *this->ostream_; }
|
|
||||||
|
|
||||||
// Implementation of String_dump interface.
|
|
||||||
void
|
|
||||||
write_c_string(const char*);
|
|
||||||
|
|
||||||
void
|
|
||||||
write_string(const std::string&);
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Stream on output dump file.
|
|
||||||
std::ostream* ostream_;
|
|
||||||
|
|
||||||
Gogo* gogo_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // !defined(GO_ESCAPE_H)
|
|
|
@ -436,17 +436,6 @@ Export::write_type(const Type* type)
|
||||||
this->type_refs_[type] = index;
|
this->type_refs_[type] = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export escape information.
|
|
||||||
|
|
||||||
void
|
|
||||||
Export::write_escape(const Node::Escapement_lattice& e)
|
|
||||||
{
|
|
||||||
char buf[30];
|
|
||||||
snprintf(buf, sizeof buf, "<escape %d>", e);
|
|
||||||
this->write_c_string(buf);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the builtin types to the export table.
|
// Add the builtin types to the export table.
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#ifndef GO_EXPORT_H
|
#ifndef GO_EXPORT_H
|
||||||
#define GO_EXPORT_H
|
#define GO_EXPORT_H
|
||||||
|
|
||||||
#include "escape.h"
|
|
||||||
#include "string-dump.h"
|
#include "string-dump.h"
|
||||||
|
|
||||||
struct sha1_ctx;
|
struct sha1_ctx;
|
||||||
|
@ -162,10 +161,6 @@ class Export : public String_dump
|
||||||
void
|
void
|
||||||
write_type(const Type*);
|
write_type(const Type*);
|
||||||
|
|
||||||
// Write out escape information.
|
|
||||||
void
|
|
||||||
write_escape(const Node::Escapement_lattice& e);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Export(const Export&);
|
Export(const Export&);
|
||||||
Export& operator=(const Export&);
|
Export& operator=(const Export&);
|
||||||
|
|
|
@ -110,10 +110,6 @@ go_parse_input_files(const char** filenames, unsigned int filename_count,
|
||||||
if (only_check_syntax)
|
if (only_check_syntax)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Consider escape analysis information when deciding if a variable should
|
|
||||||
// live on the heap or on the stack.
|
|
||||||
::gogo->optimize_allocations(filenames);
|
|
||||||
|
|
||||||
// Export global identifiers as appropriate.
|
// Export global identifiers as appropriate.
|
||||||
::gogo->do_exports();
|
::gogo->do_exports();
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
#include "import.h"
|
#include "import.h"
|
||||||
#include "export.h"
|
#include "export.h"
|
||||||
#include "escape.h"
|
|
||||||
#include "backend.h"
|
#include "backend.h"
|
||||||
#include "gogo.h"
|
#include "gogo.h"
|
||||||
|
|
||||||
|
@ -156,19 +155,11 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size)
|
||||||
Function_type* new_type = Type::make_function_type(NULL, NULL, NULL, loc);
|
Function_type* new_type = Type::make_function_type(NULL, NULL, NULL, loc);
|
||||||
new_type->set_is_varargs();
|
new_type->set_is_varargs();
|
||||||
new_type->set_is_builtin();
|
new_type->set_is_builtin();
|
||||||
Node::Escape_states* new_escapes =
|
|
||||||
new Node::Escape_states(1, Node::ESCAPE_NONE);
|
|
||||||
new_type->set_parameter_escape_states(new_escapes);
|
|
||||||
new_type->set_has_escape_info();
|
|
||||||
this->globals_->add_function_declaration("new", NULL, new_type, loc);
|
this->globals_->add_function_declaration("new", NULL, new_type, loc);
|
||||||
|
|
||||||
Function_type* make_type = Type::make_function_type(NULL, NULL, NULL, loc);
|
Function_type* make_type = Type::make_function_type(NULL, NULL, NULL, loc);
|
||||||
make_type->set_is_varargs();
|
make_type->set_is_varargs();
|
||||||
make_type->set_is_builtin();
|
make_type->set_is_builtin();
|
||||||
Node::Escape_states* make_escapes =
|
|
||||||
new Node::Escape_states(2, Node::ESCAPE_NONE);
|
|
||||||
make_type->set_parameter_escape_states(make_escapes);
|
|
||||||
make_type->set_has_escape_info();
|
|
||||||
this->globals_->add_function_declaration("make", NULL, make_type, loc);
|
this->globals_->add_function_declaration("make", NULL, make_type, loc);
|
||||||
|
|
||||||
Typed_identifier_list* len_result = new Typed_identifier_list();
|
Typed_identifier_list* len_result = new Typed_identifier_list();
|
||||||
|
@ -176,10 +167,6 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size)
|
||||||
Function_type* len_type = Type::make_function_type(NULL, NULL, len_result,
|
Function_type* len_type = Type::make_function_type(NULL, NULL, len_result,
|
||||||
loc);
|
loc);
|
||||||
len_type->set_is_builtin();
|
len_type->set_is_builtin();
|
||||||
Node::Escape_states* len_escapes =
|
|
||||||
new Node::Escape_states(1, Node::ESCAPE_NONE);
|
|
||||||
len_type->set_parameter_escape_states(len_escapes);
|
|
||||||
len_type->set_has_escape_info();
|
|
||||||
this->globals_->add_function_declaration("len", NULL, len_type, loc);
|
this->globals_->add_function_declaration("len", NULL, len_type, loc);
|
||||||
|
|
||||||
Typed_identifier_list* cap_result = new Typed_identifier_list();
|
Typed_identifier_list* cap_result = new Typed_identifier_list();
|
||||||
|
@ -187,26 +174,16 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size)
|
||||||
Function_type* cap_type = Type::make_function_type(NULL, NULL, len_result,
|
Function_type* cap_type = Type::make_function_type(NULL, NULL, len_result,
|
||||||
loc);
|
loc);
|
||||||
cap_type->set_is_builtin();
|
cap_type->set_is_builtin();
|
||||||
Node::Escape_states* cap_escapes =
|
|
||||||
new Node::Escape_states(1, Node::ESCAPE_NONE);
|
|
||||||
cap_type->set_parameter_escape_states(cap_escapes);
|
|
||||||
cap_type->set_has_escape_info();
|
|
||||||
this->globals_->add_function_declaration("cap", NULL, cap_type, loc);
|
this->globals_->add_function_declaration("cap", NULL, cap_type, loc);
|
||||||
|
|
||||||
Function_type* print_type = Type::make_function_type(NULL, NULL, NULL, loc);
|
Function_type* print_type = Type::make_function_type(NULL, NULL, NULL, loc);
|
||||||
print_type->set_is_varargs();
|
print_type->set_is_varargs();
|
||||||
print_type->set_is_builtin();
|
print_type->set_is_builtin();
|
||||||
Node::Escape_states* print_escapes =
|
|
||||||
new Node::Escape_states(1, Node::ESCAPE_NONE);
|
|
||||||
print_type->set_parameter_escape_states(print_escapes);
|
|
||||||
print_type->set_has_escape_info();
|
|
||||||
this->globals_->add_function_declaration("print", NULL, print_type, loc);
|
this->globals_->add_function_declaration("print", NULL, print_type, loc);
|
||||||
|
|
||||||
print_type = Type::make_function_type(NULL, NULL, NULL, loc);
|
print_type = Type::make_function_type(NULL, NULL, NULL, loc);
|
||||||
print_type->set_is_varargs();
|
print_type->set_is_varargs();
|
||||||
print_type->set_is_builtin();
|
print_type->set_is_builtin();
|
||||||
print_type->set_parameter_escape_states(print_escapes);
|
|
||||||
print_type->set_has_escape_info();
|
|
||||||
this->globals_->add_function_declaration("println", NULL, print_type, loc);
|
this->globals_->add_function_declaration("println", NULL, print_type, loc);
|
||||||
|
|
||||||
Type *empty = Type::make_empty_interface_type(loc);
|
Type *empty = Type::make_empty_interface_type(loc);
|
||||||
|
@ -215,10 +192,6 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size)
|
||||||
Function_type *panic_type = Type::make_function_type(NULL, panic_parms,
|
Function_type *panic_type = Type::make_function_type(NULL, panic_parms,
|
||||||
NULL, loc);
|
NULL, loc);
|
||||||
panic_type->set_is_builtin();
|
panic_type->set_is_builtin();
|
||||||
Node::Escape_states* panic_escapes =
|
|
||||||
new Node::Escape_states(1, Node::ESCAPE_ARG);
|
|
||||||
panic_type->set_parameter_escape_states(panic_escapes);
|
|
||||||
panic_type->set_has_escape_info();
|
|
||||||
this->globals_->add_function_declaration("panic", NULL, panic_type, loc);
|
this->globals_->add_function_declaration("panic", NULL, panic_type, loc);
|
||||||
|
|
||||||
Typed_identifier_list* recover_result = new Typed_identifier_list();
|
Typed_identifier_list* recover_result = new Typed_identifier_list();
|
||||||
|
@ -232,10 +205,6 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size)
|
||||||
Function_type* close_type = Type::make_function_type(NULL, NULL, NULL, loc);
|
Function_type* close_type = Type::make_function_type(NULL, NULL, NULL, loc);
|
||||||
close_type->set_is_varargs();
|
close_type->set_is_varargs();
|
||||||
close_type->set_is_builtin();
|
close_type->set_is_builtin();
|
||||||
Node::Escape_states* close_escapes =
|
|
||||||
new Node::Escape_states(1, Node::ESCAPE_NONE);
|
|
||||||
close_type->set_parameter_escape_states(close_escapes);
|
|
||||||
close_type->set_has_escape_info();
|
|
||||||
this->globals_->add_function_declaration("close", NULL, close_type, loc);
|
this->globals_->add_function_declaration("close", NULL, close_type, loc);
|
||||||
|
|
||||||
Typed_identifier_list* copy_result = new Typed_identifier_list();
|
Typed_identifier_list* copy_result = new Typed_identifier_list();
|
||||||
|
@ -244,56 +213,31 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size)
|
||||||
copy_result, loc);
|
copy_result, loc);
|
||||||
copy_type->set_is_varargs();
|
copy_type->set_is_varargs();
|
||||||
copy_type->set_is_builtin();
|
copy_type->set_is_builtin();
|
||||||
Node::Escape_states* copy_escapes =
|
|
||||||
new Node::Escape_states(2, Node::ESCAPE_NONE);
|
|
||||||
copy_type->set_parameter_escape_states(copy_escapes);
|
|
||||||
copy_type->set_has_escape_info();
|
|
||||||
this->globals_->add_function_declaration("copy", NULL, copy_type, loc);
|
this->globals_->add_function_declaration("copy", NULL, copy_type, loc);
|
||||||
|
|
||||||
Function_type* append_type = Type::make_function_type(NULL, NULL, NULL, loc);
|
Function_type* append_type = Type::make_function_type(NULL, NULL, NULL, loc);
|
||||||
append_type->set_is_varargs();
|
append_type->set_is_varargs();
|
||||||
append_type->set_is_builtin();
|
append_type->set_is_builtin();
|
||||||
Node::Escape_states* append_escapes = new Node::Escape_states;
|
|
||||||
append_escapes->push_back(Node::ESCAPE_ARG);
|
|
||||||
append_escapes->push_back(Node::ESCAPE_NONE);
|
|
||||||
append_type->set_parameter_escape_states(append_escapes);
|
|
||||||
append_type->set_has_escape_info();
|
|
||||||
this->globals_->add_function_declaration("append", NULL, append_type, loc);
|
this->globals_->add_function_declaration("append", NULL, append_type, loc);
|
||||||
|
|
||||||
Function_type* complex_type = Type::make_function_type(NULL, NULL, NULL, loc);
|
Function_type* complex_type = Type::make_function_type(NULL, NULL, NULL, loc);
|
||||||
complex_type->set_is_varargs();
|
complex_type->set_is_varargs();
|
||||||
complex_type->set_is_builtin();
|
complex_type->set_is_builtin();
|
||||||
Node::Escape_states* complex_escapes =
|
|
||||||
new Node::Escape_states(2, Node::ESCAPE_NONE);
|
|
||||||
complex_type->set_parameter_escape_states(complex_escapes);
|
|
||||||
complex_type->set_has_escape_info();
|
|
||||||
this->globals_->add_function_declaration("complex", NULL, complex_type, loc);
|
this->globals_->add_function_declaration("complex", NULL, complex_type, loc);
|
||||||
|
|
||||||
Function_type* real_type = Type::make_function_type(NULL, NULL, NULL, loc);
|
Function_type* real_type = Type::make_function_type(NULL, NULL, NULL, loc);
|
||||||
real_type->set_is_varargs();
|
real_type->set_is_varargs();
|
||||||
real_type->set_is_builtin();
|
real_type->set_is_builtin();
|
||||||
Node::Escape_states* real_escapes =
|
|
||||||
new Node::Escape_states(1, Node::ESCAPE_NONE);
|
|
||||||
real_type->set_parameter_escape_states(real_escapes);
|
|
||||||
real_type->set_has_escape_info();
|
|
||||||
this->globals_->add_function_declaration("real", NULL, real_type, loc);
|
this->globals_->add_function_declaration("real", NULL, real_type, loc);
|
||||||
|
|
||||||
Function_type* imag_type = Type::make_function_type(NULL, NULL, NULL, loc);
|
Function_type* imag_type = Type::make_function_type(NULL, NULL, NULL, loc);
|
||||||
imag_type->set_is_varargs();
|
imag_type->set_is_varargs();
|
||||||
imag_type->set_is_builtin();
|
imag_type->set_is_builtin();
|
||||||
Node::Escape_states* imag_escapes =
|
|
||||||
new Node::Escape_states(1, Node::ESCAPE_NONE);
|
|
||||||
imag_type->set_parameter_escape_states(imag_escapes);
|
|
||||||
imag_type->set_has_escape_info();
|
|
||||||
this->globals_->add_function_declaration("imag", NULL, imag_type, loc);
|
this->globals_->add_function_declaration("imag", NULL, imag_type, loc);
|
||||||
|
|
||||||
Function_type* delete_type = Type::make_function_type(NULL, NULL, NULL, loc);
|
Function_type* delete_type = Type::make_function_type(NULL, NULL, NULL, loc);
|
||||||
delete_type->set_is_varargs();
|
delete_type->set_is_varargs();
|
||||||
delete_type->set_is_builtin();
|
delete_type->set_is_builtin();
|
||||||
Node::Escape_states* delete_escapes =
|
|
||||||
new Node::Escape_states(2, Node::ESCAPE_NONE);
|
|
||||||
delete_type->set_parameter_escape_states(delete_escapes);
|
|
||||||
delete_type->set_has_escape_info();
|
|
||||||
this->globals_->add_function_declaration("delete", NULL, delete_type, loc);
|
this->globals_->add_function_declaration("delete", NULL, delete_type, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1889,74 +1833,6 @@ Gogo::add_label_reference(const std::string& label_name,
|
||||||
issue_goto_errors);
|
issue_goto_errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a function to the call graph.
|
|
||||||
|
|
||||||
Node*
|
|
||||||
Gogo::add_call_node(Named_object* function)
|
|
||||||
{
|
|
||||||
Node* call = this->lookup_call_node(function);
|
|
||||||
if (call == NULL)
|
|
||||||
{
|
|
||||||
call = Node::make_call(function);
|
|
||||||
this->call_graph_.insert(call);
|
|
||||||
this->named_call_nodes_[function] = call;
|
|
||||||
}
|
|
||||||
return call;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the call node that represents FUNCTION. Return NULL if it does not
|
|
||||||
// exist.
|
|
||||||
|
|
||||||
Node*
|
|
||||||
Gogo::lookup_call_node(Named_object* function) const
|
|
||||||
{
|
|
||||||
Named_escape_nodes::const_iterator p = this->named_call_nodes_.find(function);
|
|
||||||
if (p == this->named_call_nodes_.end())
|
|
||||||
return NULL;
|
|
||||||
return p->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a connection node for OBJECT.
|
|
||||||
|
|
||||||
Node*
|
|
||||||
Gogo::add_connection_node(Named_object* object)
|
|
||||||
{
|
|
||||||
Node* connection = this->lookup_connection_node(object);
|
|
||||||
if (connection == NULL)
|
|
||||||
{
|
|
||||||
connection = Node::make_connection(object, Node::ESCAPE_NONE);
|
|
||||||
|
|
||||||
// Each global variable is a part of the global connection graph.
|
|
||||||
if (object->is_variable()
|
|
||||||
&& object->var_value()->is_global())
|
|
||||||
{
|
|
||||||
connection->connection_node()->set_escape_state(Node::ESCAPE_GLOBAL);
|
|
||||||
this->global_connections_.insert(connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Each function declaration or definition is the root of its own
|
|
||||||
// connection graph. This means closures will have their own
|
|
||||||
// connection graph that objects in the enclosing function might
|
|
||||||
// refer to.
|
|
||||||
if (object->is_function() || object->is_function_declaration())
|
|
||||||
this->connection_roots_.insert(connection);
|
|
||||||
this->named_connection_nodes_[object] = connection;
|
|
||||||
}
|
|
||||||
return connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the connection node for OBJECT. Return NULL if it does not exist.
|
|
||||||
|
|
||||||
Node*
|
|
||||||
Gogo::lookup_connection_node(Named_object* object) const
|
|
||||||
{
|
|
||||||
Named_escape_nodes::const_iterator p =
|
|
||||||
this->named_connection_nodes_.find(object);
|
|
||||||
if (p == this->named_connection_nodes_.end())
|
|
||||||
return NULL;
|
|
||||||
return p->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the current binding state.
|
// Return the current binding state.
|
||||||
|
|
||||||
Bindings_snapshot*
|
Bindings_snapshot*
|
||||||
|
@ -4918,13 +4794,6 @@ Function::export_func_with_type(Export* exp, const std::string& name,
|
||||||
exp->write_c_string("(");
|
exp->write_c_string("(");
|
||||||
const Typed_identifier* receiver = fntype->receiver();
|
const Typed_identifier* receiver = fntype->receiver();
|
||||||
exp->write_name(receiver->name());
|
exp->write_name(receiver->name());
|
||||||
|
|
||||||
if (fntype->has_escape_info())
|
|
||||||
{
|
|
||||||
exp->write_c_string(" ");
|
|
||||||
exp->write_escape(fntype->receiver_escape_state());
|
|
||||||
}
|
|
||||||
|
|
||||||
exp->write_c_string(" ");
|
exp->write_c_string(" ");
|
||||||
exp->write_type(receiver->type());
|
exp->write_type(receiver->type());
|
||||||
exp->write_c_string(") ");
|
exp->write_c_string(") ");
|
||||||
|
@ -4948,13 +4817,6 @@ Function::export_func_with_type(Export* exp, const std::string& name,
|
||||||
else
|
else
|
||||||
exp->write_c_string(", ");
|
exp->write_c_string(", ");
|
||||||
exp->write_name(p->name());
|
exp->write_name(p->name());
|
||||||
|
|
||||||
if (fntype->has_escape_info())
|
|
||||||
{
|
|
||||||
exp->write_c_string(" ");
|
|
||||||
exp->write_escape(fntype->parameter_escape_states()->at(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
exp->write_c_string(" ");
|
exp->write_c_string(" ");
|
||||||
if (!is_varargs || p + 1 != parameters->end())
|
if (!is_varargs || p + 1 != parameters->end())
|
||||||
exp->write_type(p->type());
|
exp->write_type(p->type());
|
||||||
|
@ -5002,29 +4864,17 @@ Function::export_func_with_type(Export* exp, const std::string& name,
|
||||||
void
|
void
|
||||||
Function::import_func(Import* imp, std::string* pname,
|
Function::import_func(Import* imp, std::string* pname,
|
||||||
Typed_identifier** preceiver,
|
Typed_identifier** preceiver,
|
||||||
Node::Escapement_lattice* rcvr_escape,
|
|
||||||
Typed_identifier_list** pparameters,
|
Typed_identifier_list** pparameters,
|
||||||
Node::Escape_states** pparam_escapes,
|
|
||||||
Typed_identifier_list** presults,
|
Typed_identifier_list** presults,
|
||||||
bool* is_varargs, bool* has_escape_info)
|
bool* is_varargs)
|
||||||
{
|
{
|
||||||
*has_escape_info = false;
|
|
||||||
|
|
||||||
imp->require_c_string("func ");
|
imp->require_c_string("func ");
|
||||||
|
|
||||||
*preceiver = NULL;
|
*preceiver = NULL;
|
||||||
*rcvr_escape = Node::ESCAPE_NONE;
|
|
||||||
if (imp->peek_char() == '(')
|
if (imp->peek_char() == '(')
|
||||||
{
|
{
|
||||||
imp->require_c_string("(");
|
imp->require_c_string("(");
|
||||||
std::string name = imp->read_name();
|
std::string name = imp->read_name();
|
||||||
|
|
||||||
if (imp->match_c_string(" <escape")){
|
|
||||||
*has_escape_info = true;
|
|
||||||
imp->require_c_string(" ");
|
|
||||||
*rcvr_escape = imp->read_escape_info();
|
|
||||||
}
|
|
||||||
|
|
||||||
imp->require_c_string(" ");
|
imp->require_c_string(" ");
|
||||||
Type* rtype = imp->read_type();
|
Type* rtype = imp->read_type();
|
||||||
*preceiver = new Typed_identifier(name, rtype, imp->location());
|
*preceiver = new Typed_identifier(name, rtype, imp->location());
|
||||||
|
@ -5034,27 +4884,16 @@ Function::import_func(Import* imp, std::string* pname,
|
||||||
*pname = imp->read_identifier();
|
*pname = imp->read_identifier();
|
||||||
|
|
||||||
Typed_identifier_list* parameters;
|
Typed_identifier_list* parameters;
|
||||||
Node::Escape_states* param_escapes;
|
|
||||||
*is_varargs = false;
|
*is_varargs = false;
|
||||||
imp->require_c_string(" (");
|
imp->require_c_string(" (");
|
||||||
if (imp->peek_char() == ')')
|
if (imp->peek_char() == ')')
|
||||||
{
|
parameters = NULL;
|
||||||
parameters = NULL;
|
|
||||||
param_escapes = NULL;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
parameters = new Typed_identifier_list();
|
parameters = new Typed_identifier_list();
|
||||||
param_escapes = new Node::Escape_states();
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
std::string name = imp->read_name();
|
std::string name = imp->read_name();
|
||||||
if (imp->match_c_string(" <escape")){
|
|
||||||
*has_escape_info = true;
|
|
||||||
imp->require_c_string(" ");
|
|
||||||
param_escapes->push_back(imp->read_escape_info());
|
|
||||||
}
|
|
||||||
|
|
||||||
imp->require_c_string(" ");
|
imp->require_c_string(" ");
|
||||||
|
|
||||||
if (imp->match_c_string("..."))
|
if (imp->match_c_string("..."))
|
||||||
|
@ -5076,7 +4915,6 @@ Function::import_func(Import* imp, std::string* pname,
|
||||||
}
|
}
|
||||||
imp->require_c_string(")");
|
imp->require_c_string(")");
|
||||||
*pparameters = parameters;
|
*pparameters = parameters;
|
||||||
*pparam_escapes = param_escapes;
|
|
||||||
|
|
||||||
Typed_identifier_list* results;
|
Typed_identifier_list* results;
|
||||||
if (imp->peek_char() != ' ')
|
if (imp->peek_char() != ' ')
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#ifndef GO_GOGO_H
|
#ifndef GO_GOGO_H
|
||||||
#define GO_GOGO_H
|
#define GO_GOGO_H
|
||||||
|
|
||||||
#include "escape.h"
|
|
||||||
#include "go-linemap.h"
|
#include "go-linemap.h"
|
||||||
|
|
||||||
class Traverse;
|
class Traverse;
|
||||||
|
@ -126,21 +125,6 @@ class Gogo
|
||||||
linemap()
|
linemap()
|
||||||
{ return this->linemap_; }
|
{ return this->linemap_; }
|
||||||
|
|
||||||
// Get the Call Graph.
|
|
||||||
const std::set<Node*>&
|
|
||||||
call_graph() const
|
|
||||||
{ return this->call_graph_; }
|
|
||||||
|
|
||||||
// Get the roots of each connection graph.
|
|
||||||
const std::set<Node*>&
|
|
||||||
connection_roots() const
|
|
||||||
{ return this->connection_roots_; }
|
|
||||||
|
|
||||||
// Get the nodes that escape globally.
|
|
||||||
const std::set<Node*>&
|
|
||||||
global_connections() const
|
|
||||||
{ return this->global_connections_; }
|
|
||||||
|
|
||||||
// Get the package name.
|
// Get the package name.
|
||||||
const std::string&
|
const std::string&
|
||||||
package_name() const;
|
package_name() const;
|
||||||
|
@ -361,22 +345,6 @@ class Gogo
|
||||||
add_label_reference(const std::string&, Location,
|
add_label_reference(const std::string&, Location,
|
||||||
bool issue_goto_errors);
|
bool issue_goto_errors);
|
||||||
|
|
||||||
// Add a FUNCTION to the call graph.
|
|
||||||
Node*
|
|
||||||
add_call_node(Named_object* function);
|
|
||||||
|
|
||||||
// Lookup the call node for FUNCTION.
|
|
||||||
Node*
|
|
||||||
lookup_call_node(Named_object* function) const;
|
|
||||||
|
|
||||||
// Add a connection node for OBJECT.
|
|
||||||
Node*
|
|
||||||
add_connection_node(Named_object* object);
|
|
||||||
|
|
||||||
// Lookup the connection node for OBJECT.
|
|
||||||
Node*
|
|
||||||
lookup_connection_node(Named_object* object) const;
|
|
||||||
|
|
||||||
// Return a snapshot of the current binding state.
|
// Return a snapshot of the current binding state.
|
||||||
Bindings_snapshot*
|
Bindings_snapshot*
|
||||||
bindings_snapshot(Location);
|
bindings_snapshot(Location);
|
||||||
|
@ -576,26 +544,6 @@ class Gogo
|
||||||
void
|
void
|
||||||
check_return_statements();
|
check_return_statements();
|
||||||
|
|
||||||
// Build call graph.
|
|
||||||
void
|
|
||||||
build_call_graph();
|
|
||||||
|
|
||||||
// Build connection graphs.
|
|
||||||
void
|
|
||||||
build_connection_graphs();
|
|
||||||
|
|
||||||
// Analyze reachability in the connection graphs.
|
|
||||||
void
|
|
||||||
analyze_reachability();
|
|
||||||
|
|
||||||
// Record escape information in function signatures for export data.
|
|
||||||
void
|
|
||||||
mark_escaping_signatures();
|
|
||||||
|
|
||||||
// Optimize variable allocation.
|
|
||||||
void
|
|
||||||
optimize_allocations(const char** filenames);
|
|
||||||
|
|
||||||
// Do all exports.
|
// Do all exports.
|
||||||
void
|
void
|
||||||
do_exports();
|
do_exports();
|
||||||
|
@ -730,10 +678,6 @@ class Gogo
|
||||||
// where they were defined.
|
// where they were defined.
|
||||||
typedef Unordered_map(std::string, Location) File_block_names;
|
typedef Unordered_map(std::string, Location) File_block_names;
|
||||||
|
|
||||||
// Type used to map named objects that refer to objects to the
|
|
||||||
// node that represent them in the escape analysis graphs.
|
|
||||||
typedef Unordered_map(Named_object*, Node*) Named_escape_nodes;
|
|
||||||
|
|
||||||
// Type used to queue writing a type specific function.
|
// Type used to queue writing a type specific function.
|
||||||
struct Specific_type_function
|
struct Specific_type_function
|
||||||
{
|
{
|
||||||
|
@ -766,20 +710,6 @@ class Gogo
|
||||||
// The global binding contour. This includes the builtin functions
|
// The global binding contour. This includes the builtin functions
|
||||||
// and the package we are compiling.
|
// and the package we are compiling.
|
||||||
Bindings* globals_;
|
Bindings* globals_;
|
||||||
// The call graph for a program execution which represents the functions
|
|
||||||
// encountered and the caller-callee relationship between the functions.
|
|
||||||
std::set<Node*> call_graph_;
|
|
||||||
// The nodes that form the roots of the connection graphs for each called
|
|
||||||
// function and represent the connectivity relationship between all objects
|
|
||||||
// in the function.
|
|
||||||
std::set<Node*> connection_roots_;
|
|
||||||
// All connection nodes that have an escape state of ESCAPE_GLOBAL are a part
|
|
||||||
// of a special connection graph of only global variables.
|
|
||||||
std::set<Node*> global_connections_;
|
|
||||||
// Mapping from named objects to nodes in the call graph.
|
|
||||||
Named_escape_nodes named_call_nodes_;
|
|
||||||
// Mapping from named objects to nodes in a connection graph.
|
|
||||||
Named_escape_nodes named_connection_nodes_;
|
|
||||||
// The list of names we have seen in the file block.
|
// The list of names we have seen in the file block.
|
||||||
File_block_names file_block_names_;
|
File_block_names file_block_names_;
|
||||||
// Mapping from import file names to packages.
|
// Mapping from import file names to packages.
|
||||||
|
@ -1215,11 +1145,8 @@ class Function
|
||||||
// Import a function.
|
// Import a function.
|
||||||
static void
|
static void
|
||||||
import_func(Import*, std::string* pname, Typed_identifier** receiver,
|
import_func(Import*, std::string* pname, Typed_identifier** receiver,
|
||||||
Node::Escapement_lattice* rcvr_escape,
|
|
||||||
Typed_identifier_list** pparameters,
|
Typed_identifier_list** pparameters,
|
||||||
Node::Escape_states** pparam_escapes,
|
Typed_identifier_list** presults, bool* is_varargs);
|
||||||
Typed_identifier_list** presults, bool* is_varargs,
|
|
||||||
bool* has_escape_info);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Type for mapping from label names to Label objects.
|
// Type for mapping from label names to Label objects.
|
||||||
|
|
|
@ -502,28 +502,16 @@ Import::import_func(Package* package)
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
Typed_identifier* receiver;
|
Typed_identifier* receiver;
|
||||||
Node::Escapement_lattice rcvr_escape;
|
|
||||||
Typed_identifier_list* parameters;
|
Typed_identifier_list* parameters;
|
||||||
Node::Escape_states* param_escapes;
|
|
||||||
Typed_identifier_list* results;
|
Typed_identifier_list* results;
|
||||||
bool is_varargs;
|
bool is_varargs;
|
||||||
bool has_escape_info;
|
Function::import_func(this, &name, &receiver,
|
||||||
Function::import_func(this, &name, &receiver, &rcvr_escape, ¶meters,
|
¶meters, &results, &is_varargs);
|
||||||
¶m_escapes, &results, &is_varargs,
|
|
||||||
&has_escape_info);
|
|
||||||
Function_type *fntype = Type::make_function_type(receiver, parameters,
|
Function_type *fntype = Type::make_function_type(receiver, parameters,
|
||||||
results, this->location_);
|
results, this->location_);
|
||||||
if (is_varargs)
|
if (is_varargs)
|
||||||
fntype->set_is_varargs();
|
fntype->set_is_varargs();
|
||||||
|
|
||||||
if (has_escape_info)
|
|
||||||
{
|
|
||||||
if (fntype->is_method())
|
|
||||||
fntype->set_receiver_escape_state(rcvr_escape);
|
|
||||||
fntype->set_parameter_escape_states(param_escapes);
|
|
||||||
fntype->set_has_escape_info();
|
|
||||||
}
|
|
||||||
|
|
||||||
Location loc = this->location_;
|
Location loc = this->location_;
|
||||||
Named_object* no;
|
Named_object* no;
|
||||||
if (fntype->is_method())
|
if (fntype->is_method())
|
||||||
|
@ -774,19 +762,6 @@ Import::read_type()
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read escape info in the import stream.
|
|
||||||
|
|
||||||
Node::Escapement_lattice
|
|
||||||
Import::read_escape_info()
|
|
||||||
{
|
|
||||||
Stream* stream = this->stream_;
|
|
||||||
this->require_c_string("<escape ");
|
|
||||||
|
|
||||||
int escape_value = stream->get_char() - '0';
|
|
||||||
this->require_c_string(">");
|
|
||||||
return Node::Escapement_lattice(escape_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register the builtin types.
|
// Register the builtin types.
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#ifndef GO_IMPORT_H
|
#ifndef GO_IMPORT_H
|
||||||
#define GO_IMPORT_H
|
#define GO_IMPORT_H
|
||||||
|
|
||||||
#include "escape.h"
|
|
||||||
#include "export.h"
|
#include "export.h"
|
||||||
#include "go-linemap.h"
|
#include "go-linemap.h"
|
||||||
|
|
||||||
|
@ -198,10 +197,6 @@ class Import
|
||||||
Type*
|
Type*
|
||||||
read_type();
|
read_type();
|
||||||
|
|
||||||
// Read escape information.
|
|
||||||
Node::Escapement_lattice
|
|
||||||
read_escape_info();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Stream*
|
static Stream*
|
||||||
try_package_in_directory(const std::string&, Location);
|
try_package_in_directory(const std::string&, Location);
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
#include "backend.h"
|
#include "backend.h"
|
||||||
#include "statements.h"
|
#include "statements.h"
|
||||||
#include "ast-dump.h"
|
#include "ast-dump.h"
|
||||||
#include "dataflow.h"
|
|
||||||
|
|
||||||
// Class Statement.
|
// Class Statement.
|
||||||
|
|
||||||
|
@ -4821,22 +4820,6 @@ Select_clauses::Select_clause::check_types()
|
||||||
error_at(this->location(), "invalid receive on send-only channel");
|
error_at(this->location(), "invalid receive on send-only channel");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Analyze the dataflow across each case statement.
|
|
||||||
|
|
||||||
void
|
|
||||||
Select_clauses::Select_clause::analyze_dataflow(Dataflow* dataflow)
|
|
||||||
{
|
|
||||||
if (this->is_default_)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// For a CommClause, the dataflow analysis should record a definition of
|
|
||||||
// VAR and CLOSEDVAR
|
|
||||||
if (this->var_ != NULL && !this->var_->is_sink())
|
|
||||||
dataflow->add_def(this->var_, this->channel_, NULL, false);
|
|
||||||
if (this->closedvar_ != NULL && !this->closedvar_->is_sink())
|
|
||||||
dataflow->add_def(this->closedvar_, this->channel_, NULL, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Whether this clause may fall through to the statement which follows
|
// Whether this clause may fall through to the statement which follows
|
||||||
// the overall select statement.
|
// the overall select statement.
|
||||||
|
|
||||||
|
@ -4955,17 +4938,6 @@ Select_clauses::check_types()
|
||||||
p->check_types();
|
p->check_types();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Analyze the dataflow across each case statement.
|
|
||||||
|
|
||||||
void
|
|
||||||
Select_clauses::analyze_dataflow(Dataflow* dataflow)
|
|
||||||
{
|
|
||||||
for (Clauses::iterator p = this->clauses_.begin();
|
|
||||||
p != this->clauses_.end();
|
|
||||||
++p)
|
|
||||||
p->analyze_dataflow(dataflow);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return whether these select clauses fall through to the statement
|
// Return whether these select clauses fall through to the statement
|
||||||
// following the overall select statement.
|
// following the overall select statement.
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,6 @@ class Bexpression;
|
||||||
class Bstatement;
|
class Bstatement;
|
||||||
class Bvariable;
|
class Bvariable;
|
||||||
class Ast_dump_context;
|
class Ast_dump_context;
|
||||||
class Dataflow;
|
|
||||||
|
|
||||||
// This class is used to traverse assignments made by a statement
|
// This class is used to traverse assignments made by a statement
|
||||||
// which makes assignments.
|
// which makes assignments.
|
||||||
|
@ -860,10 +859,6 @@ class Select_clauses
|
||||||
void
|
void
|
||||||
check_types();
|
check_types();
|
||||||
|
|
||||||
// Analyze the dataflow across each case statement.
|
|
||||||
void
|
|
||||||
analyze_dataflow(Dataflow*);
|
|
||||||
|
|
||||||
// Whether the select clauses may fall through to the statement
|
// Whether the select clauses may fall through to the statement
|
||||||
// which follows the overall select statement.
|
// which follows the overall select statement.
|
||||||
bool
|
bool
|
||||||
|
@ -920,10 +915,6 @@ class Select_clauses
|
||||||
void
|
void
|
||||||
check_types();
|
check_types();
|
||||||
|
|
||||||
// Analyze the dataflow across each case statement.
|
|
||||||
void
|
|
||||||
analyze_dataflow(Dataflow*);
|
|
||||||
|
|
||||||
// Return true if this is the default clause.
|
// Return true if this is the default clause.
|
||||||
bool
|
bool
|
||||||
is_default() const
|
is_default() const
|
||||||
|
@ -1030,10 +1021,6 @@ class Select_statement : public Statement
|
||||||
Unnamed_label*
|
Unnamed_label*
|
||||||
break_label();
|
break_label();
|
||||||
|
|
||||||
void
|
|
||||||
analyze_dataflow(Dataflow* dataflow)
|
|
||||||
{ this->clauses_->analyze_dataflow(dataflow); }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int
|
int
|
||||||
do_traverse(Traverse* traverse)
|
do_traverse(Traverse* traverse)
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
#define GO_TYPES_H
|
#define GO_TYPES_H
|
||||||
|
|
||||||
#include "go-linemap.h"
|
#include "go-linemap.h"
|
||||||
#include "escape.h"
|
|
||||||
|
|
||||||
class Gogo;
|
class Gogo;
|
||||||
class Package;
|
class Package;
|
||||||
|
@ -1779,7 +1778,7 @@ class Function_type : public Type
|
||||||
: Type(TYPE_FUNCTION),
|
: Type(TYPE_FUNCTION),
|
||||||
receiver_(receiver), parameters_(parameters), results_(results),
|
receiver_(receiver), parameters_(parameters), results_(results),
|
||||||
location_(location), is_varargs_(false), is_builtin_(false),
|
location_(location), is_varargs_(false), is_builtin_(false),
|
||||||
has_escape_info_(false), fnbtype_(NULL), parameter_escape_states_(NULL)
|
fnbtype_(NULL)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
// Get the receiver.
|
// Get the receiver.
|
||||||
|
@ -1787,16 +1786,6 @@ class Function_type : public Type
|
||||||
receiver() const
|
receiver() const
|
||||||
{ return this->receiver_; }
|
{ return this->receiver_; }
|
||||||
|
|
||||||
// Get the escape state of the receiver.
|
|
||||||
const Node::Escapement_lattice&
|
|
||||||
receiver_escape_state() const
|
|
||||||
{ return this->receiver_escape_state_; }
|
|
||||||
|
|
||||||
// Set the escape state of the receiver.
|
|
||||||
void
|
|
||||||
set_receiver_escape_state(const Node::Escapement_lattice& e)
|
|
||||||
{ this->receiver_escape_state_ = e; }
|
|
||||||
|
|
||||||
// Get the return names and types.
|
// Get the return names and types.
|
||||||
const Typed_identifier_list*
|
const Typed_identifier_list*
|
||||||
results() const
|
results() const
|
||||||
|
@ -1807,16 +1796,6 @@ class Function_type : public Type
|
||||||
parameters() const
|
parameters() const
|
||||||
{ return this->parameters_; }
|
{ return this->parameters_; }
|
||||||
|
|
||||||
// Get the escape states associated with each parameter.
|
|
||||||
const Node::Escape_states*
|
|
||||||
parameter_escape_states() const
|
|
||||||
{ return this->parameter_escape_states_; }
|
|
||||||
|
|
||||||
// Set the escape states of the parameters.
|
|
||||||
void
|
|
||||||
set_parameter_escape_states(Node::Escape_states* states)
|
|
||||||
{ this->parameter_escape_states_ = states; }
|
|
||||||
|
|
||||||
// Whether this is a varargs function.
|
// Whether this is a varargs function.
|
||||||
bool
|
bool
|
||||||
is_varargs() const
|
is_varargs() const
|
||||||
|
@ -1827,11 +1806,6 @@ class Function_type : public Type
|
||||||
is_builtin() const
|
is_builtin() const
|
||||||
{ return this->is_builtin_; }
|
{ return this->is_builtin_; }
|
||||||
|
|
||||||
// Whether this contains escape information.
|
|
||||||
bool
|
|
||||||
has_escape_info() const
|
|
||||||
{ return this->has_escape_info_; }
|
|
||||||
|
|
||||||
// The location where this type was defined.
|
// The location where this type was defined.
|
||||||
Location
|
Location
|
||||||
location() const
|
location() const
|
||||||
|
@ -1862,11 +1836,6 @@ class Function_type : public Type
|
||||||
set_is_builtin()
|
set_is_builtin()
|
||||||
{ this->is_builtin_ = true; }
|
{ this->is_builtin_ = true; }
|
||||||
|
|
||||||
// Record that this has escape information.
|
|
||||||
void
|
|
||||||
set_has_escape_info()
|
|
||||||
{ this->has_escape_info_ = true; }
|
|
||||||
|
|
||||||
// Import a function type.
|
// Import a function type.
|
||||||
static Function_type*
|
static Function_type*
|
||||||
do_import(Import*);
|
do_import(Import*);
|
||||||
|
@ -1978,16 +1947,9 @@ class Function_type : public Type
|
||||||
// Whether this is a special builtin function which can not simply
|
// Whether this is a special builtin function which can not simply
|
||||||
// be called. This is used for len, cap, etc.
|
// be called. This is used for len, cap, etc.
|
||||||
bool is_builtin_;
|
bool is_builtin_;
|
||||||
// Whether escape information for the receiver and parameters has been
|
|
||||||
// recorded.
|
|
||||||
bool has_escape_info_;
|
|
||||||
// The backend representation of this type for backend function
|
// The backend representation of this type for backend function
|
||||||
// declarations and definitions.
|
// declarations and definitions.
|
||||||
Btype* fnbtype_;
|
Btype* fnbtype_;
|
||||||
// The escape state of the receiver.
|
|
||||||
Node::Escapement_lattice receiver_escape_state_;
|
|
||||||
// The escape states of each parameter.
|
|
||||||
Node::Escape_states* parameter_escape_states_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// The type of a function's backend representation.
|
// The type of a function's backend representation.
|
||||||
|
|
Loading…
Reference in New Issue