aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2021-08-06 18:04:43 -0700
committerIan Lance Taylor <iant@golang.org>2021-08-12 16:33:10 -0700
commit1196b60f8fc5a169e01ac859712013a4d3d8de96 (patch)
tree431a9cea9e59f3dda3f12a613802b04f094f5712 /gcc
parentd0befed793b94f3f407be44e6f69f81a02f5f073 (diff)
downloadgcc-1196b60f8fc5a169e01ac859712013a4d3d8de96.zip
gcc-1196b60f8fc5a169e01ac859712013a4d3d8de96.tar.gz
gcc-1196b60f8fc5a169e01ac859712013a4d3d8de96.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/expressions.cc30
-rw-r--r--gcc/go/gofrontend/types.cc75
-rw-r--r--gcc/go/gofrontend/types.h3
4 files changed, 92 insertions, 18 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index be092de..539d886 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 67917da..8d4d168 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 0c44186..e76600d 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 f2880f9..ca1ab49 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;