compiler: make single Btype for methods table of identical interface type
authorIan Lance Taylor <ian@gcc.gnu.org>
Wed, 7 Feb 2018 01:52:48 +0000 (01:52 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Wed, 7 Feb 2018 01:52:48 +0000 (01:52 +0000)
    Normally we ensure to build a single Btype for identical types.
    We did not do this for methods table of identical interface
    types, however. If there are two identical interface type I, I2,
    they have the same Btype BI, but different Btypes for their
    methods tables, BM and BM2. From the backend's point of view
    only one of them is linked to BI. This can cause inconsitency
    in the backend's type system, like unresolved placeholder. This
    CL ensures we create a single Btype for methods table of
    identical interface type.

    Reviewed-on: https://go-review.googlesource.com/92436

From-SVN: r257436

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/types.cc
gcc/go/gofrontend/types.h

index 8c49b2b12da37b23d2934adce35ef1ccf315267b..81e11d1946f311c9ff1afd0249f756092697a5d2 100644 (file)
@@ -1,4 +1,4 @@
-02f11a2d5cf0db2c2675c13d92bb69529f2175dd
+5fe998e4a18cc1dbbd4869be5c8202bda55adb33
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index 34edf7628352eb7a8cd1359e76fa3c612439427f..eb04fe1e2293bb52984527ec67a82e71e9a5b2a3 100644 (file)
@@ -9096,6 +9096,8 @@ Interface_type::get_backend_empty_interface_type(Gogo* gogo)
   return empty_interface_type;
 }
 
+Interface_type::Bmethods_map Interface_type::bmethods_map;
+
 // Return a pointer to the backend representation of the method table.
 
 Btype*
@@ -9104,6 +9106,21 @@ Interface_type::get_backend_methods(Gogo* gogo)
   if (this->bmethods_ != NULL && !this->bmethods_is_placeholder_)
     return this->bmethods_;
 
+  std::pair<Interface_type*, Bmethods_map_entry> val;
+  val.first = this;
+  val.second.btype = NULL;
+  val.second.is_placeholder = false;
+  std::pair<Bmethods_map::iterator, bool> ins =
+    Interface_type::bmethods_map.insert(val);
+  if (!ins.second
+      && ins.first->second.btype != NULL
+      && !ins.first->second.is_placeholder)
+    {
+      this->bmethods_ = ins.first->second.btype;
+      this->bmethods_is_placeholder_ = false;
+      return this->bmethods_;
+    }
+
   Location loc = this->location();
 
   std::vector<Backend::Btyped_identifier>
@@ -9160,10 +9177,14 @@ Interface_type::get_backend_methods(Gogo* gogo)
   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);
+  if (ins.first->second.btype != NULL
+      && ins.first->second.is_placeholder)
+    gogo->backend()->set_placeholder_pointer_type(ins.first->second.btype,
+                                                  ret);
   this->bmethods_ = ret;
+  ins.first->second.btype = ret;
   this->bmethods_is_placeholder_ = false;
+  ins.first->second.is_placeholder = false;
   return ret;
 }
 
@@ -9174,10 +9195,25 @@ Interface_type::get_backend_methods_placeholder(Gogo* gogo)
 {
   if (this->bmethods_ == NULL)
     {
+      std::pair<Interface_type*, Bmethods_map_entry> val;
+      val.first = this;
+      val.second.btype = NULL;
+      val.second.is_placeholder = false;
+      std::pair<Bmethods_map::iterator, bool> ins =
+        Interface_type::bmethods_map.insert(val);
+      if (!ins.second && ins.first->second.btype != NULL)
+        {
+          this->bmethods_ = ins.first->second.btype;
+          this->bmethods_is_placeholder_ = ins.first->second.is_placeholder;
+          return this->bmethods_;
+        }
+
       Location loc = this->location();
-      this->bmethods_ = gogo->backend()->placeholder_pointer_type("", loc,
-                                                                 false);
+      Btype* bt = gogo->backend()->placeholder_pointer_type("", loc, false);
+      this->bmethods_ = bt;
+      ins.first->second.btype = bt;
       this->bmethods_is_placeholder_ = true;
+      ins.first->second.is_placeholder = true;
     }
   return this->bmethods_;
 }
index 648773131ca6f43da3a6a466f763fde05bfd17cb..234e0a6abbda0389f1d571f42bbb8e4d58c2ae48 100644 (file)
@@ -3185,6 +3185,20 @@ class Interface_type : public Type
   bool
   assume_identical(const Interface_type*, const Interface_type*) const;
 
+  struct Bmethods_map_entry
+  {
+    Btype *btype;
+    bool is_placeholder;
+  };
+
+  // A mapping from Interface_type to the backend type of its bmethods_,
+  // used to ensure that the backend representation of identical types
+  // is identical.
+  typedef Unordered_map_hash(const Interface_type*, Bmethods_map_entry,
+                             Type_hash_identical, Type_identical) Bmethods_map;
+
+  static Bmethods_map bmethods_map;
+
   // The list of methods associated with the interface from the
   // parser.  This will be NULL for the empty interface.  This may
   // include unnamed interface types.