From c683798925b93552510392fe72148c6ac4282b57 Mon Sep 17 00:00:00 2001 From: ian Date: Fri, 21 Jun 2013 00:11:53 +0000 Subject: [PATCH] compiler: Only make function descriptors if needed. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@200273 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/go/gofrontend/expressions.cc | 92 ++++++++----------- gcc/go/gofrontend/expressions.h | 65 +++++++++++++- gcc/go/gofrontend/go.cc | 3 + gcc/go/gofrontend/gogo.cc | 187 +++++++++++++++++++++++++++++---------- gcc/go/gofrontend/gogo.h | 14 +-- 5 files changed, 252 insertions(+), 109 deletions(-) diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index adadfbb..240e455 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 3f4db91..133b237 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 c0b3fef..55b4dca 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 e4c21be..d005fb8 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 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::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 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::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 ec43ef6..4a84075 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; -- 2.7.4