compiler: check for notinheap struct at each struct field

When generating write barriers, we were only checking for a notinheap
    struct at the outermost struct.  That mishandled the case of setting a
    pointer to a notinheap struct as a field of another struct that is not
    notinheap.  This caused an invalid write barrier error when building
    the 1.13 version of the runtime.
    
    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/192279

From-SVN: r275240
This commit is contained in:
Ian Lance Taylor 2019-08-31 03:07:48 +00:00
parent c70ff9f9be
commit 3ba155dd19
2 changed files with 26 additions and 26 deletions

View File

@ -1,4 +1,4 @@
289d94b9e6303ec74649d1f08d418300f2b4d0fd
3b8a505824abb2a69f4c04c555a4ba29ab8b102b
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.

View File

@ -733,6 +733,31 @@ Gogo::assign_needs_write_barrier(
&& !lhs->type()->points_to()->in_heap())
return false;
// For a struct assignment, we don't need a write barrier if all
// the field types can not be in the heap.
Struct_type* st = lhs->type()->struct_type();
if (st != NULL)
{
bool in_heap = false;
const Struct_field_list* fields = st->fields();
for (Struct_field_list::const_iterator p = fields->begin();
p != fields->end();
p++)
{
Type* ft = p->type();
if (!ft->has_pointer())
continue;
if (!ft->in_heap())
continue;
if (ft->points_to() != NULL && !ft->points_to()->in_heap())
continue;
in_heap = true;
break;
}
if (!in_heap)
return false;
}
Field_reference_expression* fre = lhs->field_reference_expression();
if (fre != NULL)
{
@ -788,31 +813,6 @@ Gogo::assign_needs_write_barrier(
&& this->is_nonwb_pointer(ue->operand(), nonwb_pointers))
return false;
// For a struct assignment, we don't need a write barrier if all the
// pointer types can not be in the heap.
Struct_type* st = lhs->type()->struct_type();
if (st != NULL)
{
bool in_heap = false;
const Struct_field_list* fields = st->fields();
for (Struct_field_list::const_iterator p = fields->begin();
p != fields->end();
p++)
{
Type* ft = p->type();
if (!ft->has_pointer())
continue;
if (!ft->in_heap())
continue;
if (ft->points_to() != NULL && !ft->points_to()->in_heap())
continue;
in_heap = true;
break;
}
if (!in_heap)
return false;
}
// Write barrier needed in other cases.
return true;
}