public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-2892] compiler: store pointers to go:notinheap types indirectly
@ 2021-08-12 23:33 Ian Lance Taylor
  0 siblings, 0 replies; only message in thread
From: Ian Lance Taylor @ 2021-08-12 23:33 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:1196b60f8fc5a169e01ac859712013a4d3d8de96

commit r12-2892-g1196b60f8fc5a169e01ac859712013a4d3d8de96
Author: Ian Lance Taylor <iant@golang.org>
Date:   Fri Aug 6 18:04:43 2021 -0700

    compiler: store pointers to go:notinheap types indirectly
    
    This is the gofrontend version of https://golang.org/cl/264480.
    
    For golang/go#42076
    
    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/340609

Diff:
---
 gcc/go/gofrontend/MERGE          |  2 +-
 gcc/go/gofrontend/expressions.cc | 30 ++++++++++++----
 gcc/go/gofrontend/types.cc       | 75 +++++++++++++++++++++++++++++++++++-----
 gcc/go/gofrontend/types.h        |  3 +-
 libgo/go/runtime/netpoll.go      |  4 +--
 5 files changed, 94 insertions(+), 20 deletions(-)

diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index be092de568b..539d886b08f 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-7e092d2cc5af7648036496485b639f2c9db2f2d8
+5edbb624b2595d644eb6842c952a292c41f7d6fa
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 67917dac95d..8d4d168f4e3 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -408,7 +408,14 @@ Expression::convert_type_to_interface(Type* lhs_type, Expression* rhs,
     {
       // We are assigning a non-pointer value to the interface; the
       // interface gets a copy of the value in the heap if it escapes.
-      if (rhs->is_constant())
+
+      // An exception is &global if global is notinheap, which is a
+      // pointer value but not a direct-iface type and we can't simply
+      // take its address.
+      bool is_address = (rhs->unary_expression() != NULL
+                         && rhs->unary_expression()->op() == OPERATOR_AND);
+
+      if (rhs->is_constant() && !is_address)
         obj = Expression::make_unary(OPERATOR_AND, rhs, location);
       else
         {
@@ -11331,6 +11338,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
       // We always pass a pointer when calling a method, except for
       // direct interface types when calling a value method.
       if (!first_arg->type()->is_error()
+          && first_arg->type()->points_to() == NULL
           && !first_arg->type()->is_direct_iface_type())
 	{
 	  first_arg = Expression::make_unary(OPERATOR_AND, first_arg, loc);
@@ -18630,12 +18638,20 @@ Interface_mtable_expression::do_get_backend(Translate_context* context)
       else
 	m = st->method_function(p->name(), &is_ambiguous);
       go_assert(m != NULL);
-      Named_object* no =
-        (this->is_pointer_
-         && this->type_->is_direct_iface_type()
-         && m->is_value_method()
-         ? m->iface_stub_object()
-         : m->named_object());
+
+      // See the comment in Type::method_constructor.
+      bool use_direct_iface_stub = false;
+      if (m->is_value_method()
+	  && this->is_pointer_
+	  && this->type_->is_direct_iface_type())
+	use_direct_iface_stub = true;
+      if (!m->is_value_method()
+	  && this->is_pointer_
+	  && !this->type_->in_heap())
+	use_direct_iface_stub = true;
+      Named_object* no = (use_direct_iface_stub
+			  ? m->iface_stub_object()
+			  : m->named_object());
 
       go_assert(no->is_function() || no->is_function_declaration());
 
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index 0c44186f507..e76600daab9 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -2464,8 +2464,16 @@ Type::is_direct_iface_type() const
 bool
 Type::is_direct_iface_type_helper(Unordered_set(const Type*)* visited) const
 {
-  if (this->points_to() != NULL
-      || this->channel_type() != NULL
+  if (this->points_to() != NULL)
+    {
+      // Pointers to notinheap types must be stored indirectly.  See
+      // https://golang.org/issue/42076.
+      if (!this->points_to()->in_heap())
+	return false;
+      return true;
+    }
+
+  if (this->channel_type() != NULL
       || this->function_type() != NULL
       || this->map_type() != NULL)
     return true;
@@ -3597,10 +3605,36 @@ Type::method_constructor(Gogo*, Type* method_type,
       vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
     }
 
-  bool use_direct_iface_stub =
-    this->points_to() != NULL
-    && this->points_to()->is_direct_iface_type()
-    && m->is_value_method();
+  // The direct_iface_stub dereferences the value stored in the
+  // interface when calling the method.
+  //
+  // We need this for a value method if this type is a pointer to a
+  // direct-iface type.  For example, if we have "type C chan int" and M
+  // is a value method on C, then since a channel is a direct-iface type
+  // M expects a value of type C.  We are generating the method table
+  // for *C, so the value stored in the interface is *C.  We have to
+  // call the direct-iface stub to dereference *C to get C to pass to M.
+  //
+  // We also need this for a pointer method if the pointer itself is not
+  // a direct-iface type, as arises for notinheap types.  In this case
+  // we have "type NIH ..." where NIH is go:notinheap.  Since NIH is
+  // notinheap, *NIH is a pointer type that is not a direct-iface type,
+  // so the value stored in the interface is actually **NIH.  The method
+  // expects *NIH, so we have to call the direct-iface stub to
+  // dereference **NIH to get *NIH to pass to M.  (This case doesn't
+  // arise for value methods because pointer types can't have methods,
+  // so there is no such thing as a value method for type *NIH.)
+
+  bool use_direct_iface_stub = false;
+  if (m->is_value_method()
+      && this->points_to() != NULL
+      && this->points_to()->is_direct_iface_type())
+    use_direct_iface_stub = true;
+  if (!m->is_value_method()
+      && this->points_to() != NULL
+      && !this->is_direct_iface_type())
+    use_direct_iface_stub = true;
+
   Named_object* no = (use_direct_iface_stub
                       ? m->iface_stub_object()
                       : (m->needs_stub_method()
@@ -10902,6 +10936,20 @@ Named_type::do_needs_key_update()
   return ret;
 }
 
+// Return whether this type is permitted in the heap.
+bool
+Named_type::do_in_heap() const
+{
+  if (!this->in_heap_)
+    return false;
+  if (this->seen_)
+    return true;
+  this->seen_ = true;
+  bool ret = this->type_->in_heap();
+  this->seen_ = false;
+  return ret;
+}
+
 // Return a hash code.  This is used for method lookup.  We simply
 // hash on the name itself.
 
@@ -11434,7 +11482,7 @@ Type::finalize_methods(Gogo* gogo, const Type* type, Location location,
       *all_methods = NULL;
     }
   Type::build_stub_methods(gogo, type, *all_methods, location);
-  if (type->is_direct_iface_type())
+  if (type->is_direct_iface_type() || !type->in_heap())
     Type::build_direct_iface_stub_methods(gogo, type, *all_methods, location);
 }
 
@@ -11814,12 +11862,23 @@ Type::build_direct_iface_stub_methods(Gogo* gogo, const Type* type,
   if (methods == NULL)
     return;
 
+  bool is_direct_iface = type->is_direct_iface_type();
+  bool in_heap = type->in_heap();
   for (Methods::const_iterator p = methods->begin();
        p != methods->end();
        ++p)
     {
       Method* m = p->second;
-      if (!m->is_value_method())
+
+      // We need a direct-iface stub for a value method for a
+      // direct-iface type, and for a pointer method for a not-in-heap
+      // type.
+      bool need_stub = false;
+      if (is_direct_iface && m->is_value_method())
+        need_stub = true;
+      if (!in_heap && !m->is_value_method())
+        need_stub = true;
+      if (!need_stub)
         continue;
 
       Type* receiver_type = const_cast<Type*>(type);
diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h
index f2880f9c5d8..ca1ab49c57e 100644
--- a/gcc/go/gofrontend/types.h
+++ b/gcc/go/gofrontend/types.h
@@ -3605,8 +3605,7 @@ class Named_type : public Type
   do_needs_key_update();
 
   bool
-  do_in_heap() const
-  { return this->in_heap_ && this->type_->in_heap(); }
+  do_in_heap() const;
 
   unsigned int
   do_hash_for_method(Gogo*, int) const;
diff --git a/libgo/go/runtime/netpoll.go b/libgo/go/runtime/netpoll.go
index da00b57c276..879112a728d 100644
--- a/libgo/go/runtime/netpoll.go
+++ b/libgo/go/runtime/netpoll.go
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
 // +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris windows
 
 package runtime
@@ -567,8 +568,7 @@ func (c *pollCache) alloc() *pollDesc {
 func (pd *pollDesc) makeArg() (i interface{}) {
 	x := (*eface)(unsafe.Pointer(&i))
 	x._type = pdType
-	// For gccgo, we still use pd.self here, not &pd.self.
-	x.data = unsafe.Pointer(pd.self)
+	x.data = unsafe.Pointer(&pd.self)
 	return
 }


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-08-12 23:33 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-12 23:33 [gcc r12-2892] compiler: store pointers to go:notinheap types indirectly Ian Lance Taylor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).