Skip to content

Commit 1196b60

Browse files
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
1 parent d0befed commit 1196b60

File tree

5 files changed

+94
-20
lines changed

5 files changed

+94
-20
lines changed

gcc/go/gofrontend/MERGE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
7e092d2cc5af7648036496485b639f2c9db2f2d8
1+
5edbb624b2595d644eb6842c952a292c41f7d6fa
22

33
The first line of this file holds the git revision number of the last
44
merge done from the gofrontend repository.

gcc/go/gofrontend/expressions.cc

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,14 @@ Expression::convert_type_to_interface(Type* lhs_type, Expression* rhs,
408408
{
409409
// We are assigning a non-pointer value to the interface; the
410410
// interface gets a copy of the value in the heap if it escapes.
411-
if (rhs->is_constant())
411+
412+
// An exception is &global if global is notinheap, which is a
413+
// pointer value but not a direct-iface type and we can't simply
414+
// take its address.
415+
bool is_address = (rhs->unary_expression() != NULL
416+
&& rhs->unary_expression()->op() == OPERATOR_AND);
417+
418+
if (rhs->is_constant() && !is_address)
412419
obj = Expression::make_unary(OPERATOR_AND, rhs, location);
413420
else
414421
{
@@ -11331,6 +11338,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
1133111338
// We always pass a pointer when calling a method, except for
1133211339
// direct interface types when calling a value method.
1133311340
if (!first_arg->type()->is_error()
11341+
&& first_arg->type()->points_to() == NULL
1133411342
&& !first_arg->type()->is_direct_iface_type())
1133511343
{
1133611344
first_arg = Expression::make_unary(OPERATOR_AND, first_arg, loc);
@@ -18630,12 +18638,20 @@ Interface_mtable_expression::do_get_backend(Translate_context* context)
1863018638
else
1863118639
m = st->method_function(p->name(), &is_ambiguous);
1863218640
go_assert(m != NULL);
18633-
Named_object* no =
18634-
(this->is_pointer_
18635-
&& this->type_->is_direct_iface_type()
18636-
&& m->is_value_method()
18637-
? m->iface_stub_object()
18638-
: m->named_object());
18641+
18642+
// See the comment in Type::method_constructor.
18643+
bool use_direct_iface_stub = false;
18644+
if (m->is_value_method()
18645+
&& this->is_pointer_
18646+
&& this->type_->is_direct_iface_type())
18647+
use_direct_iface_stub = true;
18648+
if (!m->is_value_method()
18649+
&& this->is_pointer_
18650+
&& !this->type_->in_heap())
18651+
use_direct_iface_stub = true;
18652+
Named_object* no = (use_direct_iface_stub
18653+
? m->iface_stub_object()
18654+
: m->named_object());
1863918655

1864018656
go_assert(no->is_function() || no->is_function_declaration());
1864118657

gcc/go/gofrontend/types.cc

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2464,8 +2464,16 @@ Type::is_direct_iface_type() const
24642464
bool
24652465
Type::is_direct_iface_type_helper(Unordered_set(const Type*)* visited) const
24662466
{
2467-
if (this->points_to() != NULL
2468-
|| this->channel_type() != NULL
2467+
if (this->points_to() != NULL)
2468+
{
2469+
// Pointers to notinheap types must be stored indirectly. See
2470+
// https://golang.org/issue/42076.
2471+
if (!this->points_to()->in_heap())
2472+
return false;
2473+
return true;
2474+
}
2475+
2476+
if (this->channel_type() != NULL
24692477
|| this->function_type() != NULL
24702478
|| this->map_type() != NULL)
24712479
return true;
@@ -3597,10 +3605,36 @@ Type::method_constructor(Gogo*, Type* method_type,
35973605
vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
35983606
}
35993607

3600-
bool use_direct_iface_stub =
3601-
this->points_to() != NULL
3602-
&& this->points_to()->is_direct_iface_type()
3603-
&& m->is_value_method();
3608+
// The direct_iface_stub dereferences the value stored in the
3609+
// interface when calling the method.
3610+
//
3611+
// We need this for a value method if this type is a pointer to a
3612+
// direct-iface type. For example, if we have "type C chan int" and M
3613+
// is a value method on C, then since a channel is a direct-iface type
3614+
// M expects a value of type C. We are generating the method table
3615+
// for *C, so the value stored in the interface is *C. We have to
3616+
// call the direct-iface stub to dereference *C to get C to pass to M.
3617+
//
3618+
// We also need this for a pointer method if the pointer itself is not
3619+
// a direct-iface type, as arises for notinheap types. In this case
3620+
// we have "type NIH ..." where NIH is go:notinheap. Since NIH is
3621+
// notinheap, *NIH is a pointer type that is not a direct-iface type,
3622+
// so the value stored in the interface is actually **NIH. The method
3623+
// expects *NIH, so we have to call the direct-iface stub to
3624+
// dereference **NIH to get *NIH to pass to M. (This case doesn't
3625+
// arise for value methods because pointer types can't have methods,
3626+
// so there is no such thing as a value method for type *NIH.)
3627+
3628+
bool use_direct_iface_stub = false;
3629+
if (m->is_value_method()
3630+
&& this->points_to() != NULL
3631+
&& this->points_to()->is_direct_iface_type())
3632+
use_direct_iface_stub = true;
3633+
if (!m->is_value_method()
3634+
&& this->points_to() != NULL
3635+
&& !this->is_direct_iface_type())
3636+
use_direct_iface_stub = true;
3637+
36043638
Named_object* no = (use_direct_iface_stub
36053639
? m->iface_stub_object()
36063640
: (m->needs_stub_method()
@@ -10902,6 +10936,20 @@ Named_type::do_needs_key_update()
1090210936
return ret;
1090310937
}
1090410938

10939+
// Return whether this type is permitted in the heap.
10940+
bool
10941+
Named_type::do_in_heap() const
10942+
{
10943+
if (!this->in_heap_)
10944+
return false;
10945+
if (this->seen_)
10946+
return true;
10947+
this->seen_ = true;
10948+
bool ret = this->type_->in_heap();
10949+
this->seen_ = false;
10950+
return ret;
10951+
}
10952+
1090510953
// Return a hash code. This is used for method lookup. We simply
1090610954
// hash on the name itself.
1090710955

@@ -11434,7 +11482,7 @@ Type::finalize_methods(Gogo* gogo, const Type* type, Location location,
1143411482
*all_methods = NULL;
1143511483
}
1143611484
Type::build_stub_methods(gogo, type, *all_methods, location);
11437-
if (type->is_direct_iface_type())
11485+
if (type->is_direct_iface_type() || !type->in_heap())
1143811486
Type::build_direct_iface_stub_methods(gogo, type, *all_methods, location);
1143911487
}
1144011488

@@ -11814,12 +11862,23 @@ Type::build_direct_iface_stub_methods(Gogo* gogo, const Type* type,
1181411862
if (methods == NULL)
1181511863
return;
1181611864

11865+
bool is_direct_iface = type->is_direct_iface_type();
11866+
bool in_heap = type->in_heap();
1181711867
for (Methods::const_iterator p = methods->begin();
1181811868
p != methods->end();
1181911869
++p)
1182011870
{
1182111871
Method* m = p->second;
11822-
if (!m->is_value_method())
11872+
11873+
// We need a direct-iface stub for a value method for a
11874+
// direct-iface type, and for a pointer method for a not-in-heap
11875+
// type.
11876+
bool need_stub = false;
11877+
if (is_direct_iface && m->is_value_method())
11878+
need_stub = true;
11879+
if (!in_heap && !m->is_value_method())
11880+
need_stub = true;
11881+
if (!need_stub)
1182311882
continue;
1182411883

1182511884
Type* receiver_type = const_cast<Type*>(type);

gcc/go/gofrontend/types.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3605,8 +3605,7 @@ class Named_type : public Type
36053605
do_needs_key_update();
36063606

36073607
bool
3608-
do_in_heap() const
3609-
{ return this->in_heap_ && this->type_->in_heap(); }
3608+
do_in_heap() const;
36103609

36113610
unsigned int
36123611
do_hash_for_method(Gogo*, int) const;

libgo/go/runtime/netpoll.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5+
//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
56
// +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris windows
67

78
package runtime
@@ -567,8 +568,7 @@ func (c *pollCache) alloc() *pollDesc {
567568
func (pd *pollDesc) makeArg() (i interface{}) {
568569
x := (*eface)(unsafe.Pointer(&i))
569570
x._type = pdType
570-
// For gccgo, we still use pd.self here, not &pd.self.
571-
x.data = unsafe.Pointer(pd.self)
571+
x.data = unsafe.Pointer(&pd.self)
572572
return
573573
}
574574

0 commit comments

Comments
 (0)