]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
compiler: Fix backend representation of calls to interface methods.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 23 Nov 2013 19:01:57 +0000 (19:01 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 23 Nov 2013 19:01:57 +0000 (19:01 +0000)
Also unify all identical result parameter sets into a single
struct type, and fix the use of backend function pointers.

* go-gcc.cc (Gcc_backend::function_type): Add result_struct
parameter.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@205316 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/go/ChangeLog
gcc/go/go-gcc.cc
gcc/go/gofrontend/backend.h
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/types.cc
gcc/go/gofrontend/types.h

index d2e35737cbcaeba73da6c50e22b8b76ebfa6a9b0..a7dafac8e7465be0c9846a166ad606bfb904aab4 100644 (file)
@@ -1,3 +1,8 @@
+2013-11-23  Ian Lance Taylor  <iant@google.com>
+
+       * go-gcc.cc (Gcc_backend::function_type): Add result_struct
+       parameter.
+
 2013-11-22  Andrew MacLeod  <amacleod@redhat.com>
 
        * go-gcc.cc: Add required include files from gimple.h.
index 50e31fff91f34281521ba3704d811efdd01a7eb1..939be20c3494e742242a8bf2cec5be72a95ce83e 100644 (file)
@@ -158,6 +158,7 @@ class Gcc_backend : public Backend
   function_type(const Btyped_identifier&,
                const std::vector<Btyped_identifier>&,
                const std::vector<Btyped_identifier>&,
+               Btype*,
                const Location);
 
   Btype*
@@ -493,7 +494,8 @@ Btype*
 Gcc_backend::function_type(const Btyped_identifier& receiver,
                           const std::vector<Btyped_identifier>& parameters,
                           const std::vector<Btyped_identifier>& results,
-                          Location location)
+                          Btype* result_struct,
+                          Location)
 {
   tree args = NULL_TREE;
   tree* pp = &args;
@@ -528,29 +530,8 @@ Gcc_backend::function_type(const Btyped_identifier& receiver,
     result = results.front().btype->get_tree();
   else
     {
-      result = make_node(RECORD_TYPE);
-      tree field_trees = NULL_TREE;
-      pp = &field_trees;
-      for (std::vector<Btyped_identifier>::const_iterator p = results.begin();
-          p != results.end();
-          ++p)
-       {
-         const std::string name = (p->name.empty()
-                                   ? "UNNAMED"
-                                   : p->name);
-         tree name_tree = get_identifier_from_string(name);
-         tree field_type_tree = p->btype->get_tree();
-         if (field_type_tree == error_mark_node)
-           return this->error_type();
-         gcc_assert(TYPE_SIZE(field_type_tree) != NULL_TREE);
-         tree field = build_decl(location.gcc_location(), FIELD_DECL,
-                                  name_tree, field_type_tree);
-         DECL_CONTEXT(field) = result;
-         *pp = field;
-         pp = &DECL_CHAIN(field);
-       }
-      TYPE_FIELDS(result) = field_trees;
-      layout_type(result);
+      gcc_assert(result_struct != NULL);
+      result = result_struct->get_tree();
     }
   if (result == error_mark_node)
     return this->error_type();
index 6f2c321e09e50d087989a35af5628df70d63301a..8344da40120d5706b34fc51dde7b728a19c6e3fa 100644 (file)
@@ -101,11 +101,15 @@ class Backend
   // is provided so that the names are available.  This should return
   // not the type of a Go function (which is a pointer to a struct)
   // but the type of a C function pointer (which will be used as the
-  // type of the first field of the struct).
+  // type of the first field of the struct).  If there is more than
+  // one result, RESULT_STRUCT is a struct type to hold the results,
+  // and RESULTS may be ignored; if there are zero or one results,
+  // RESULT_STRUCT is NULL.
   virtual Btype*
   function_type(const Btyped_identifier& receiver,
                const std::vector<Btyped_identifier>& parameters,
                const std::vector<Btyped_identifier>& results,
+               Btype* result_struct,
                Location location) = 0;
 
   // Get a struct type.
@@ -121,10 +125,11 @@ class Backend
   // NAME is the name of the type, and the location is where the named
   // type is defined.  This function is also used for unnamed function
   // types with multiple results, in which case the type has no name
-  // and NAME will be empty.  FOR_FUNCTION is true if this is for a Go
-  // function type, which corresponds to a C/C++ pointer to function
-  // type.  The return value will later be passed as the first
-  // parameter to set_placeholder_pointer_type or
+  // and NAME will be empty.  FOR_FUNCTION is true if this is for a C
+  // pointer to function type.  A Go func type is represented as a
+  // pointer to a struct, and the first field of the struct is a C
+  // pointer to function.  The return value will later be passed as
+  // the first parameter to set_placeholder_pointer_type or
   // set_placeholder_function_type.
   virtual Btype*
   placeholder_pointer_type(const std::string& name, Location,
index dd2bee429faae4e8a0093869f88f4700928d1360..4f9368ed255105316b5f835f7cada10cc6f3290d 100644 (file)
@@ -9863,8 +9863,11 @@ Call_expression::do_get_tree(Translate_context* context)
     fndecl = TREE_OPERAND(fndecl, 0);
 
   // Add a type cast in case the type of the function is a recursive
-  // type which refers to itself.
-  if (!DECL_P(fndecl) || !DECL_IS_BUILTIN(fndecl))
+  // type which refers to itself.  We don't do this for an interface
+  // method because 1) an interface method never refers to itself, so
+  // we always have a function type here; 2) we pass an extra first
+  // argument to an interface method, so fnfield_type is not correct.
+  if ((!DECL_P(fndecl) || !DECL_IS_BUILTIN(fndecl)) && !is_interface_method)
     fn = fold_convert_loc(location.gcc_location(), fnfield_type, fn);
 
   // This is to support builtin math functions when using 80387 math.
index 4f2bd0b38604feb7f1d79dab33bdb04e70da30d8..28a5b3201a21ce8b0897a0ba7c67f0d12be73b3d 100644 (file)
@@ -1059,8 +1059,9 @@ Type::get_backend_placeholder(Gogo* gogo)
     {
     case TYPE_FUNCTION:
       {
+       // A Go function type is a pointer to a struct type.
        Location loc = this->function_type()->location();
-       bt = gogo->backend()->placeholder_pointer_type("", loc, true);
+       bt = gogo->backend()->placeholder_pointer_type("", loc, false);
       }
       break;
 
@@ -1153,7 +1154,7 @@ Type::finish_backend(Gogo* gogo, Btype *placeholder)
     case TYPE_FUNCTION:
       {
        Btype* bt = this->do_get_backend(gogo);
-       if (!gogo->backend()->set_placeholder_function_type(placeholder, bt))
+       if (!gogo->backend()->set_placeholder_pointer_type(placeholder, bt))
          go_assert(saw_errors());
       }
       break;
@@ -3378,6 +3379,48 @@ Function_type::do_hash_for_method(Gogo* gogo) const
   return ret;
 }
 
+// Hash result parameters.
+
+unsigned int
+Function_type::Results_hash::operator()(const Typed_identifier_list* t) const
+{
+  unsigned int hash = 0;
+  for (Typed_identifier_list::const_iterator p = t->begin();
+       p != t->end();
+       ++p)
+    {
+      hash <<= 2;
+      hash = Type::hash_string(p->name(), hash);
+      hash += p->type()->hash_for_method(NULL);
+    }
+  return hash;
+}
+
+// Compare result parameters so that can map identical result
+// parameters to a single struct type.
+
+bool
+Function_type::Results_equal::operator()(const Typed_identifier_list* a,
+                                        const Typed_identifier_list* b) const
+{
+  if (a->size() != b->size())
+    return false;
+  Typed_identifier_list::const_iterator pa = a->begin();
+  for (Typed_identifier_list::const_iterator pb = b->begin();
+       pb != b->end();
+       ++pa, ++pb)
+    {
+      if (pa->name() != pb->name()
+         || !Type::are_identical(pa->type(), pb->type(), true, NULL))
+       return false;
+    }
+  return true;
+}
+
+// Hash from results to a backend struct type.
+
+Function_type::Results_structs Function_type::results_structs;
+
 // Get the backend representation for a function type.
 
 Btype*
@@ -3416,12 +3459,14 @@ Function_type::get_backend_fntype(Gogo* gogo)
         }
 
       std::vector<Backend::Btyped_identifier> bresults;
+      Btype* bresult_struct = NULL;
       if (this->results_ != NULL)
         {
           bresults.resize(this->results_->size());
           size_t i = 0;
           for (Typed_identifier_list::const_iterator p =
-                   this->results_->begin(); p != this->results_->end();
+                   this->results_->begin();
+              p != this->results_->end();
                ++p, ++i)
            {
               bresults[i].name = Gogo::unpack_hidden_name(p->name());
@@ -3429,10 +3474,42 @@ Function_type::get_backend_fntype(Gogo* gogo)
               bresults[i].location = p->location();
             }
           go_assert(i == bresults.size());
+
+         if (this->results_->size() > 1)
+           {
+             // Use the same results struct for all functions that
+             // return the same set of results.  This is useful to
+             // unify calls to interface methods with other calls.
+             std::pair<Typed_identifier_list*, Btype*> val;
+             val.first = this->results_;
+             val.second = NULL;
+             std::pair<Results_structs::iterator, bool> ins =
+               Function_type::results_structs.insert(val);
+             if (ins.second)
+               {
+                 // Build a new struct type.
+                 Struct_field_list* sfl = new Struct_field_list;
+                 for (Typed_identifier_list::const_iterator p =
+                        this->results_->begin();
+                      p != this->results_->end();
+                      ++p)
+                   {
+                     Typed_identifier tid = *p;
+                     if (tid.name().empty())
+                       tid = Typed_identifier("UNNAMED", tid.type(),
+                                              tid.location());
+                     sfl->push_back(Struct_field(tid));
+                   }
+                 Struct_type* st = Type::make_struct_type(sfl,
+                                                          this->location());
+                 ins.first->second = st->get_backend(gogo);
+               }
+             bresult_struct = ins.first->second;
+           }
         }
 
       this->fnbtype_ = gogo->backend()->function_type(breceiver, bparameters,
-                                                      bresults,
+                                                      bresults, bresult_struct,
                                                       this->location());
 
     }
@@ -7134,18 +7211,18 @@ Interface_type::get_backend_empty_interface_type(Gogo* gogo)
   return empty_interface_type;
 }
 
-// Return the fields of a non-empty interface type.  This is not
-// declared in types.h so that types.h doesn't have to #include
-// backend.h.
+// Return a pointer to the backend representation of the method table.
 
-static void
-get_backend_interface_fields(Gogo* gogo, Interface_type* type,
-                            bool use_placeholder,
-                            std::vector<Backend::Btyped_identifier>* bfields)
+Btype*
+Interface_type::get_backend_methods(Gogo* gogo)
 {
-  Location loc = type->location();
+  if (this->bmethods_ != NULL && !this->bmethods_is_placeholder_)
+    return this->bmethods_;
 
-  std::vector<Backend::Btyped_identifier> mfields(type->methods()->size() + 1);
+  Location loc = this->location();
+
+  std::vector<Backend::Btyped_identifier>
+    mfields(this->all_methods_->size() + 1);
 
   Type* pdt = Type::make_type_descriptor_ptr_type();
   mfields[0].name = "__type_descriptor";
@@ -7154,8 +7231,8 @@ get_backend_interface_fields(Gogo* gogo, Interface_type* type,
 
   std::string last_name = "";
   size_t i = 1;
-  for (Typed_identifier_list::const_iterator p = type->methods()->begin();
-       p != type->methods()->end();
+  for (Typed_identifier_list::const_iterator p = this->all_methods_->begin();
+       p != this->all_methods_->end();
        ++p, ++i)
     {
       // The type of the method in Go only includes the parameters.
@@ -7186,21 +7263,56 @@ get_backend_interface_fields(Gogo* gogo, Interface_type* type,
                                                    ft->location());
 
       mfields[i].name = Gogo::unpack_hidden_name(p->name());
-      mfields[i].btype = (use_placeholder
-                         ? mft->get_backend_placeholder(gogo)
-                         : mft->get_backend(gogo));
+      mfields[i].btype = mft->get_backend_fntype(gogo);
       mfields[i].location = loc;
+
       // Sanity check: the names should be sorted.
       go_assert(p->name() > last_name);
       last_name = p->name();
     }
 
-  Btype* methods = gogo->backend()->struct_type(mfields);
+  Btype* st = gogo->backend()->struct_type(mfields);
+  Btype* ret = gogo->backend()->pointer_type(st);
+
+  if (this->bmethods_ != NULL && this->bmethods_is_placeholder_)
+    gogo->backend()->set_placeholder_pointer_type(this->bmethods_, ret);
+  this->bmethods_ = ret;
+  this->bmethods_is_placeholder_ = false;
+  return ret;
+}
+
+// Return a placeholder for the pointer to the backend methods table.
+
+Btype*
+Interface_type::get_backend_methods_placeholder(Gogo* gogo)
+{
+  if (this->bmethods_ == NULL)
+    {
+      Location loc = this->location();
+      this->bmethods_ = gogo->backend()->placeholder_pointer_type("", loc,
+                                                                 false);
+      this->bmethods_is_placeholder_ = true;
+    }
+  return this->bmethods_;
+}
+
+// Return the fields of a non-empty interface type.  This is not
+// declared in types.h so that types.h doesn't have to #include
+// backend.h.
+
+static void
+get_backend_interface_fields(Gogo* gogo, Interface_type* type,
+                            bool use_placeholder,
+                            std::vector<Backend::Btyped_identifier>* bfields)
+{
+  Location loc = type->location();
 
   bfields->resize(2);
 
   (*bfields)[0].name = "__methods";
-  (*bfields)[0].btype = gogo->backend()->pointer_type(methods);
+  (*bfields)[0].btype = (use_placeholder
+                        ? type->get_backend_methods_placeholder(gogo)
+                        : type->get_backend_methods(gogo));
   (*bfields)[0].location = loc;
 
   Type* vt = Type::make_pointer_type(Type::make_void_type());
@@ -7241,7 +7353,7 @@ Interface_type::do_get_backend(Gogo* gogo)
 void
 Interface_type::finish_backend_methods(Gogo* gogo)
 {
-  if (!this->interface_type()->is_empty())
+  if (!this->is_empty())
     {
       const Typed_identifier_list* methods = this->methods();
       if (methods != NULL)
@@ -7251,6 +7363,10 @@ Interface_type::finish_backend_methods(Gogo* gogo)
               ++p)
            p->type()->get_backend(gogo);
        }
+
+      // Getting the backend methods now will set the placeholder
+      // pointer.
+      this->get_backend_methods(gogo);
     }
 }
 
@@ -8542,14 +8658,14 @@ Named_type::do_get_backend(Gogo* gogo)
       if (this->seen_in_get_backend_)
        {
          this->is_circular_ = true;
-         return gogo->backend()->circular_pointer_type(bt, true);
+         return gogo->backend()->circular_pointer_type(bt, false);
        }
       this->seen_in_get_backend_ = true;
       bt1 = Type::get_named_base_btype(gogo, base);
       this->seen_in_get_backend_ = false;
       if (this->is_circular_)
-       bt1 = gogo->backend()->circular_pointer_type(bt, true);
-      if (!gogo->backend()->set_placeholder_function_type(bt, bt1))
+       bt1 = gogo->backend()->circular_pointer_type(bt, false);
+      if (!gogo->backend()->set_placeholder_pointer_type(bt, bt1))
        bt = gogo->backend()->error_type();
       return bt;
 
index 12a7c8579b26a47834e8b43f7274b706b6536ccf..d1a739af354643c9f7a7bd4953943a025ba97aed 100644 (file)
@@ -1840,6 +1840,27 @@ class Function_type : public Type
   type_descriptor_params(Type*, const Typed_identifier*,
                         const Typed_identifier_list*);
 
+  // A mapping from a list of result types to a backend struct type.
+  class Results_hash
+  {
+  public:
+    unsigned int
+    operator()(const Typed_identifier_list*) const;
+  };
+
+  class Results_equal
+  {
+  public:
+    bool
+    operator()(const Typed_identifier_list*,
+              const Typed_identifier_list*) const;
+  };
+
+  typedef Unordered_map_hash(Typed_identifier_list*, Btype*,
+                            Results_hash, Results_equal) Results_structs;
+
+  static Results_structs results_structs;
+
   // The receiver name and type.  This will be NULL for a normal
   // function, non-NULL for a method.
   Typed_identifier* receiver_;
@@ -2552,8 +2573,9 @@ class Interface_type : public Type
   Interface_type(Typed_identifier_list* methods, Location location)
     : Type(TYPE_INTERFACE),
       parse_methods_(methods), all_methods_(NULL), location_(location),
-      interface_btype_(NULL), assume_identical_(NULL),
-      methods_are_finalized_(false), seen_(false)
+      interface_btype_(NULL), bmethods_(NULL), assume_identical_(NULL),
+      methods_are_finalized_(false), bmethods_is_placeholder_(false),
+      seen_(false)
   { go_assert(methods == NULL || !methods->empty()); }
 
   // The location where the interface type was defined.
@@ -2620,6 +2642,15 @@ class Interface_type : public Type
   static Btype*
   get_backend_empty_interface_type(Gogo*);
 
+  // Get a pointer to the backend representation of the method table.
+  Btype*
+  get_backend_methods(Gogo*);
+
+  // Return a placeholder for the backend representation of the
+  // pointer to the method table.
+  Btype*
+  get_backend_methods_placeholder(Gogo*);
+
   // Finish the backend representation of the method types.
   void
   finish_backend_methods(Gogo*);
@@ -2686,11 +2717,15 @@ class Interface_type : public Type
   Location location_;
   // The backend representation of this type during backend conversion.
   Btype* interface_btype_;
+  // The backend representation of the pointer to the method table.
+  Btype* bmethods_;
   // A list of interface types assumed to be identical during
   // interface comparison.
   mutable Assume_identical* assume_identical_;
   // Whether the methods have been finalized.
   bool methods_are_finalized_;
+  // Whether the bmethods_ field is a placeholder.
+  bool bmethods_is_placeholder_;
   // Used to avoid endless recursion in do_mangled_name.
   mutable bool seen_;
 };