summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2013-06-21 00:11:53 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2013-06-21 00:11:53 +0000
commitc683798925b93552510392fe72148c6ac4282b57 (patch)
tree8ba3b0e226b435f1bd100cda1a3a66dbefeab8c1
parenta9c99fc43e8eaf78b35595f7ca1f8baf6e203c74 (diff)
downloadgcc-c683798925b93552510392fe72148c6ac4282b57.tar.gz
compiler: Only make function descriptors if needed.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@200273 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/go/gofrontend/expressions.cc92
-rw-r--r--gcc/go/gofrontend/expressions.h65
-rw-r--r--gcc/go/gofrontend/go.cc3
-rw-r--r--gcc/go/gofrontend/gogo.cc187
-rw-r--r--gcc/go/gofrontend/gogo.h14
5 files changed, 252 insertions, 109 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index adadfbbebb8..240e4558d9d 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -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
-{
- 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());
- }
-
- // Make the function descriptor type, so that it can be converted.
- static void
- make_func_descriptor_type();
-
- 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; }
+// Constructor.
- tree
- do_get_tree(Translate_context*);
+Func_descriptor_expression::Func_descriptor_expression(Named_object* fn)
+ : Expression(EXPRESSION_FUNC_DESCRIPTOR, fn->location()),
+ fn_(fn), dfn_(NULL), dvar_(NULL)
+{
+ go_assert(!fn->is_function() || !fn->func_value()->needs_closure());
+}
- void
- do_dump_expression(Ast_dump_context* context) const
- { context->ostream() << "[descriptor " << this->fn_->name() << "]"; }
+// Traversal.
- 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.
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 3f4db91ebf6..133b23789b5 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -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
diff --git a/gcc/go/gofrontend/go.cc b/gcc/go/gofrontend/go.cc
index c0b3fef7239..55b4dca8579 100644
--- a/gcc/go/gofrontend/go.cc
+++ b/gcc/go/gofrontend/go.cc
@@ -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();
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index e4c21be2dda..d005fb86156 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -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_;
}
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index ec43ef67f08..4a840758cac 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -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;