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:
Chris Manghane 2016-04-29 17:33:01 +00:00 committed by Ian Lance Taylor
parent 52d11a4bbf
commit e49aacaf30
17 changed files with 11 additions and 2742 deletions

View File

@ -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.

View File

@ -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 \

View File

@ -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.

View File

@ -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;
}

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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&);

View File

@ -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();

View File

@ -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() != ' ')

View File

@ -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.

View File

@ -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, &parameters, &parameters, &results, &is_varargs);
&param_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

View File

@ -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);

View File

@ -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.

View File

@ -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)

View File

@ -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.