mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-09 21:31:30 +08:00
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
This commit is contained in:
parent
d0befed793
commit
1196b60f8f
@ -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.
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user