compiler: Only make function descriptors if needed.
From-SVN: r200273
This commit is contained in:
parent
07a6825b5f
commit
ed3cd9435c
5 changed files with 252 additions and 109 deletions
|
@ -1385,62 +1385,24 @@ Expression::make_func_reference(Named_object* function, Expression* closure,
|
|||
return new Func_expression(function, closure, location);
|
||||
}
|
||||
|
||||
// A function descriptor. A function descriptor is a struct with a
|
||||
// single field pointing to the function code. This is used for
|
||||
// functions without closures.
|
||||
// Class Func_descriptor_expression.
|
||||
|
||||
class Func_descriptor_expression : public Expression
|
||||
// Constructor.
|
||||
|
||||
Func_descriptor_expression::Func_descriptor_expression(Named_object* fn)
|
||||
: Expression(EXPRESSION_FUNC_DESCRIPTOR, fn->location()),
|
||||
fn_(fn), dfn_(NULL), dvar_(NULL)
|
||||
{
|
||||
public:
|
||||
Func_descriptor_expression(Named_object* fn, Named_object* dfn)
|
||||
: Expression(EXPRESSION_FUNC_DESCRIPTOR, fn->location()),
|
||||
fn_(fn), dfn_(dfn), dvar_(NULL)
|
||||
{
|
||||
go_assert(!fn->is_function() || !fn->func_value()->needs_closure());
|
||||
}
|
||||
go_assert(!fn->is_function() || !fn->func_value()->needs_closure());
|
||||
}
|
||||
|
||||
// Make the function descriptor type, so that it can be converted.
|
||||
static void
|
||||
make_func_descriptor_type();
|
||||
// Traversal.
|
||||
|
||||
protected:
|
||||
int
|
||||
do_traverse(Traverse*)
|
||||
{ return TRAVERSE_CONTINUE; }
|
||||
|
||||
Type*
|
||||
do_type();
|
||||
|
||||
void
|
||||
do_determine_type(const Type_context*)
|
||||
{ }
|
||||
|
||||
Expression*
|
||||
do_copy()
|
||||
{ return Expression::make_func_descriptor(this->fn_, this->dfn_); }
|
||||
|
||||
bool
|
||||
do_is_addressable() const
|
||||
{ return true; }
|
||||
|
||||
tree
|
||||
do_get_tree(Translate_context*);
|
||||
|
||||
void
|
||||
do_dump_expression(Ast_dump_context* context) const
|
||||
{ context->ostream() << "[descriptor " << this->fn_->name() << "]"; }
|
||||
|
||||
private:
|
||||
// The type of all function descriptors.
|
||||
static Type* descriptor_type;
|
||||
|
||||
// The function for which this is the descriptor.
|
||||
Named_object* fn_;
|
||||
// The descriptor function.
|
||||
Named_object* dfn_;
|
||||
// The descriptor variable.
|
||||
Bvariable* dvar_;
|
||||
};
|
||||
int
|
||||
Func_descriptor_expression::do_traverse(Traverse*)
|
||||
{
|
||||
return TRAVERSE_CONTINUE;
|
||||
}
|
||||
|
||||
// All function descriptors have the same type.
|
||||
|
||||
|
@ -1464,6 +1426,18 @@ Func_descriptor_expression::do_type()
|
|||
return Func_descriptor_expression::descriptor_type;
|
||||
}
|
||||
|
||||
// Copy a Func_descriptor_expression;
|
||||
|
||||
Expression*
|
||||
Func_descriptor_expression::do_copy()
|
||||
{
|
||||
Func_descriptor_expression* fde =
|
||||
Expression::make_func_descriptor(this->fn_);
|
||||
if (this->dfn_ != NULL)
|
||||
fde->set_descriptor_wrapper(this->dfn_);
|
||||
return fde;
|
||||
}
|
||||
|
||||
// The tree for a function descriptor.
|
||||
|
||||
tree
|
||||
|
@ -1519,12 +1493,20 @@ Func_descriptor_expression::do_get_tree(Translate_context* context)
|
|||
return var_to_tree(bvar);
|
||||
}
|
||||
|
||||
// Print a function descriptor expression.
|
||||
|
||||
void
|
||||
Func_descriptor_expression::do_dump_expression(Ast_dump_context* context) const
|
||||
{
|
||||
context->ostream() << "[descriptor " << this->fn_->name() << "]";
|
||||
}
|
||||
|
||||
// Make a function descriptor expression.
|
||||
|
||||
Expression*
|
||||
Expression::make_func_descriptor(Named_object* fn, Named_object* dfn)
|
||||
Func_descriptor_expression*
|
||||
Expression::make_func_descriptor(Named_object* fn)
|
||||
{
|
||||
return new Func_descriptor_expression(fn, dfn);
|
||||
return new Func_descriptor_expression(fn);
|
||||
}
|
||||
|
||||
// Make the function descriptor type, so that it can be converted.
|
||||
|
|
|
@ -32,6 +32,7 @@ class String_expression;
|
|||
class Binary_expression;
|
||||
class Call_expression;
|
||||
class Func_expression;
|
||||
class Func_descriptor_expression;
|
||||
class Unknown_expression;
|
||||
class Index_expression;
|
||||
class Map_index_expression;
|
||||
|
@ -161,10 +162,9 @@ class Expression
|
|||
// Make a function descriptor, an immutable struct with a single
|
||||
// field that points to the function code. This may only be used
|
||||
// with functions that do not have closures. FN is the function for
|
||||
// which we are making the descriptor. DFN is the descriptor
|
||||
// function wrapper.
|
||||
static Expression*
|
||||
make_func_descriptor(Named_object* fn, Named_object* dfn);
|
||||
// which we are making the descriptor.
|
||||
static Func_descriptor_expression*
|
||||
make_func_descriptor(Named_object* fn);
|
||||
|
||||
// Make a reference to the code of a function. This is used to set
|
||||
// descriptor and closure fields.
|
||||
|
@ -1562,6 +1562,63 @@ class Func_expression : public Expression
|
|||
Expression* closure_;
|
||||
};
|
||||
|
||||
// A function descriptor. A function descriptor is a struct with a
|
||||
// single field pointing to the function code. This is used for
|
||||
// functions without closures.
|
||||
|
||||
class Func_descriptor_expression : public Expression
|
||||
{
|
||||
public:
|
||||
Func_descriptor_expression(Named_object* fn);
|
||||
|
||||
// Set the descriptor wrapper.
|
||||
void
|
||||
set_descriptor_wrapper(Named_object* dfn)
|
||||
{
|
||||
go_assert(this->dfn_ == NULL);
|
||||
this->dfn_ = dfn;
|
||||
}
|
||||
|
||||
// Make the function descriptor type, so that it can be converted.
|
||||
static void
|
||||
make_func_descriptor_type();
|
||||
|
||||
protected:
|
||||
int
|
||||
do_traverse(Traverse*);
|
||||
|
||||
Type*
|
||||
do_type();
|
||||
|
||||
void
|
||||
do_determine_type(const Type_context*)
|
||||
{ }
|
||||
|
||||
Expression*
|
||||
do_copy();
|
||||
|
||||
bool
|
||||
do_is_addressable() const
|
||||
{ return true; }
|
||||
|
||||
tree
|
||||
do_get_tree(Translate_context*);
|
||||
|
||||
void
|
||||
do_dump_expression(Ast_dump_context* context) const;
|
||||
|
||||
private:
|
||||
// The type of all function descriptors.
|
||||
static Type* descriptor_type;
|
||||
|
||||
// The function for which this is the descriptor.
|
||||
Named_object* fn_;
|
||||
// The descriptor function.
|
||||
Named_object* dfn_;
|
||||
// The descriptor variable.
|
||||
Bvariable* dvar_;
|
||||
};
|
||||
|
||||
// A reference to an unknown name.
|
||||
|
||||
class Unknown_expression : public Parser_expression
|
||||
|
|
|
@ -91,6 +91,9 @@ go_parse_input_files(const char** filenames, unsigned int filename_count,
|
|||
// form which is easier to use.
|
||||
::gogo->lower_parse_tree();
|
||||
|
||||
// Create function descriptors as needed.
|
||||
::gogo->create_function_descriptors();
|
||||
|
||||
// Write out queued up functions for hash and comparison of types.
|
||||
::gogo->write_specific_type_functions();
|
||||
|
||||
|
|
|
@ -1608,14 +1608,6 @@ Lower_parse_tree::function(Named_object* no)
|
|||
{
|
||||
no->func_value()->set_closure_type();
|
||||
|
||||
// Make sure that every externally visible function has a
|
||||
// descriptor, so that packages that import this one can refer to
|
||||
// it.
|
||||
if (!Gogo::is_hidden_name(no->name())
|
||||
&& !no->func_value()->is_method()
|
||||
&& !no->func_value()->is_descriptor_wrapper())
|
||||
no->func_value()->descriptor(this->gogo_, no);
|
||||
|
||||
go_assert(this->function_ == NULL);
|
||||
this->function_ = no;
|
||||
int t = no->func_value()->traverse(this);
|
||||
|
@ -1703,28 +1695,6 @@ Lower_parse_tree::expression(Expression** pexpr)
|
|||
void
|
||||
Gogo::lower_parse_tree()
|
||||
{
|
||||
// Create a function descriptor for any function that is declared in
|
||||
// this package. This is so that we have a descriptor for functions
|
||||
// written in assembly. Gather the descriptors first so that we
|
||||
// don't add declarations while looping over them.
|
||||
std::vector<Named_object*> fndecls;
|
||||
Bindings* b = this->package_->bindings();
|
||||
for (Bindings::const_declarations_iterator p = b->begin_declarations();
|
||||
p != b->end_declarations();
|
||||
++p)
|
||||
{
|
||||
Named_object* no = p->second;
|
||||
if (no->is_function_declaration()
|
||||
&& !no->func_declaration_value()->type()->is_method()
|
||||
&& !Linemap::is_predeclared_location(no->location()))
|
||||
fndecls.push_back(no);
|
||||
}
|
||||
for (std::vector<Named_object*>::const_iterator p = fndecls.begin();
|
||||
p != fndecls.end();
|
||||
++p)
|
||||
(*p)->func_declaration_value()->descriptor(this, *p);
|
||||
fndecls.clear();
|
||||
|
||||
Lower_parse_tree lower_parse_tree(this, NULL);
|
||||
this->traverse(&lower_parse_tree);
|
||||
}
|
||||
|
@ -1763,6 +1733,121 @@ Gogo::lower_constant(Named_object* no)
|
|||
lower.constant(no, false);
|
||||
}
|
||||
|
||||
// Traverse the tree to create function descriptors as needed.
|
||||
|
||||
class Create_function_descriptors : public Traverse
|
||||
{
|
||||
public:
|
||||
Create_function_descriptors(Gogo* gogo)
|
||||
: Traverse(traverse_functions | traverse_expressions),
|
||||
gogo_(gogo)
|
||||
{ }
|
||||
|
||||
int
|
||||
function(Named_object*);
|
||||
|
||||
int
|
||||
expression(Expression**);
|
||||
|
||||
private:
|
||||
Gogo* gogo_;
|
||||
};
|
||||
|
||||
// Create a descriptor for every top-level exported function.
|
||||
|
||||
int
|
||||
Create_function_descriptors::function(Named_object* no)
|
||||
{
|
||||
if (no->is_function()
|
||||
&& no->func_value()->enclosing() == NULL
|
||||
&& !no->func_value()->is_method()
|
||||
&& !no->func_value()->is_descriptor_wrapper()
|
||||
&& !Gogo::is_hidden_name(no->name()))
|
||||
no->func_value()->descriptor(this->gogo_, no);
|
||||
|
||||
return TRAVERSE_CONTINUE;
|
||||
}
|
||||
|
||||
// If we see a function referenced in any way other than calling it,
|
||||
// create a descriptor for it.
|
||||
|
||||
int
|
||||
Create_function_descriptors::expression(Expression** pexpr)
|
||||
{
|
||||
Expression* expr = *pexpr;
|
||||
|
||||
Func_expression* fe = expr->func_expression();
|
||||
if (fe != NULL)
|
||||
{
|
||||
// We would not get here for a call to this function, so this is
|
||||
// a reference to a function other than calling it. We need a
|
||||
// descriptor.
|
||||
if (fe->closure() != NULL)
|
||||
return TRAVERSE_CONTINUE;
|
||||
Named_object* no = fe->named_object();
|
||||
if (no->is_function() && !no->func_value()->is_method())
|
||||
no->func_value()->descriptor(this->gogo_, no);
|
||||
else if (no->is_function_declaration()
|
||||
&& !no->func_declaration_value()->type()->is_method()
|
||||
&& !Linemap::is_predeclared_location(no->location()))
|
||||
no->func_declaration_value()->descriptor(this->gogo_, no);
|
||||
return TRAVERSE_CONTINUE;
|
||||
}
|
||||
|
||||
Call_expression* ce = expr->call_expression();
|
||||
if (ce != NULL)
|
||||
{
|
||||
Expression* fn = ce->fn();
|
||||
if (fn->func_expression() != NULL)
|
||||
{
|
||||
// Traverse the arguments but not the function.
|
||||
Expression_list* args = ce->args();
|
||||
if (args != NULL)
|
||||
{
|
||||
if (args->traverse(this) == TRAVERSE_EXIT)
|
||||
return TRAVERSE_EXIT;
|
||||
}
|
||||
return TRAVERSE_SKIP_COMPONENTS;
|
||||
}
|
||||
}
|
||||
|
||||
return TRAVERSE_CONTINUE;
|
||||
}
|
||||
|
||||
// Create function descriptors as needed. We need a function
|
||||
// descriptor for all exported functions and for all functions that
|
||||
// are referenced without being called.
|
||||
|
||||
void
|
||||
Gogo::create_function_descriptors()
|
||||
{
|
||||
// Create a function descriptor for any exported function that is
|
||||
// declared in this package. This is so that we have a descriptor
|
||||
// for functions written in assembly. Gather the descriptors first
|
||||
// so that we don't add declarations while looping over them.
|
||||
std::vector<Named_object*> fndecls;
|
||||
Bindings* b = this->package_->bindings();
|
||||
for (Bindings::const_declarations_iterator p = b->begin_declarations();
|
||||
p != b->end_declarations();
|
||||
++p)
|
||||
{
|
||||
Named_object* no = p->second;
|
||||
if (no->is_function_declaration()
|
||||
&& !no->func_declaration_value()->type()->is_method()
|
||||
&& !Linemap::is_predeclared_location(no->location())
|
||||
&& !Gogo::is_hidden_name(no->name()))
|
||||
fndecls.push_back(no);
|
||||
}
|
||||
for (std::vector<Named_object*>::const_iterator p = fndecls.begin();
|
||||
p != fndecls.end();
|
||||
++p)
|
||||
(*p)->func_declaration_value()->descriptor(this, *p);
|
||||
fndecls.clear();
|
||||
|
||||
Create_function_descriptors cfd(this);
|
||||
this->traverse(&cfd);
|
||||
}
|
||||
|
||||
// Look for interface types to finalize methods of inherited
|
||||
// interfaces.
|
||||
|
||||
|
@ -3559,7 +3644,9 @@ Function::make_descriptor_wrapper(Gogo* gogo, Named_object* no,
|
|||
}
|
||||
|
||||
gogo->add_statement(s);
|
||||
gogo->add_block(gogo->finish_block(loc), loc);
|
||||
Block* b = gogo->finish_block(loc);
|
||||
gogo->add_block(b, loc);
|
||||
gogo->lower_block(dno, b);
|
||||
gogo->finish_function(loc);
|
||||
|
||||
return dno;
|
||||
|
@ -3576,13 +3663,18 @@ Function::descriptor(Gogo* gogo, Named_object* no)
|
|||
go_assert(!this->is_descriptor_wrapper_);
|
||||
if (this->descriptor_ == NULL)
|
||||
{
|
||||
Named_object* dno;
|
||||
if (no->package() != NULL
|
||||
|| Linemap::is_predeclared_location(no->location()))
|
||||
dno = NULL;
|
||||
else
|
||||
dno = Function::make_descriptor_wrapper(gogo, no, this->type_);
|
||||
this->descriptor_ = Expression::make_func_descriptor(no, dno);
|
||||
// Make and record the descriptor first, so that when we lower
|
||||
// the descriptor wrapper we don't try to make it again.
|
||||
Func_descriptor_expression* descriptor =
|
||||
Expression::make_func_descriptor(no);
|
||||
this->descriptor_ = descriptor;
|
||||
if (no->package() == NULL
|
||||
&& !Linemap::is_predeclared_location(no->location()))
|
||||
{
|
||||
Named_object* dno = Function::make_descriptor_wrapper(gogo, no,
|
||||
this->type_);
|
||||
descriptor->set_descriptor_wrapper(dno);
|
||||
}
|
||||
}
|
||||
return this->descriptor_;
|
||||
}
|
||||
|
@ -4127,13 +4219,18 @@ Function_declaration::descriptor(Gogo* gogo, Named_object* no)
|
|||
go_assert(!this->fntype_->is_method());
|
||||
if (this->descriptor_ == NULL)
|
||||
{
|
||||
Named_object* dno;
|
||||
if (no->package() != NULL
|
||||
|| Linemap::is_predeclared_location(no->location()))
|
||||
dno = NULL;
|
||||
else
|
||||
dno = Function::make_descriptor_wrapper(gogo, no, this->fntype_);
|
||||
this->descriptor_ = Expression::make_func_descriptor(no, dno);
|
||||
// Make and record the descriptor first, so that when we lower
|
||||
// the descriptor wrapper we don't try to make it again.
|
||||
Func_descriptor_expression* descriptor =
|
||||
Expression::make_func_descriptor(no);
|
||||
this->descriptor_ = descriptor;
|
||||
if (no->package() == NULL
|
||||
&& !Linemap::is_predeclared_location(no->location()))
|
||||
{
|
||||
Named_object* dno = Function::make_descriptor_wrapper(gogo, no,
|
||||
this->fntype_);
|
||||
descriptor->set_descriptor_wrapper(dno);
|
||||
}
|
||||
}
|
||||
return this->descriptor_;
|
||||
}
|
||||
|
|
|
@ -476,6 +476,10 @@ class Gogo
|
|||
void
|
||||
lower_constant(Named_object*);
|
||||
|
||||
// Create all necessary function descriptors.
|
||||
void
|
||||
create_function_descriptors();
|
||||
|
||||
// Finalize the method lists and build stub methods for named types.
|
||||
void
|
||||
finalize_methods();
|
||||
|
@ -1164,15 +1168,15 @@ class Function
|
|||
// is NULL unless we actually need a defer stack.
|
||||
Temporary_statement* defer_stack_;
|
||||
// True if the result variables are named.
|
||||
bool results_are_named_;
|
||||
bool results_are_named_ : 1;
|
||||
// True if this method should not be included in the type descriptor.
|
||||
bool nointerface_;
|
||||
bool nointerface_ : 1;
|
||||
// True if this function calls the predeclared recover function.
|
||||
bool calls_recover_;
|
||||
bool calls_recover_ : 1;
|
||||
// True if this a thunk built for a function which calls recover.
|
||||
bool is_recover_thunk_;
|
||||
bool is_recover_thunk_ : 1;
|
||||
// True if this function already has a recover thunk.
|
||||
bool has_recover_thunk_;
|
||||
bool has_recover_thunk_ : 1;
|
||||
// True if this function should be put in a unique section. This is
|
||||
// turned on for field tracking.
|
||||
bool in_unique_section_ : 1;
|
||||
|
|
Loading…
Add table
Reference in a new issue