compiler: improve write barrier generation
For string, slice, interface values, do assignments field by field instead of using typedmemmove. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/181297 From-SVN: r272055
This commit is contained in:
parent
7a649ef59f
commit
1afab7a878
3 changed files with 116 additions and 7 deletions
|
@ -1,4 +1,4 @@
|
|||
9df825b5f142ac2b6f48a8dac94fcff740acd411
|
||||
b79e9e79fddc9040ab58c7c518eb08454f308def
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the gofrontend repository.
|
||||
|
|
|
@ -237,7 +237,7 @@ class Expression
|
|||
|
||||
// Make an expression that evaluates to some characteristic of an string.
|
||||
// For simplicity, the enum values must match the field indexes in the
|
||||
// underlying struct.
|
||||
// underlying struct. This returns an lvalue.
|
||||
enum String_info
|
||||
{
|
||||
// The underlying data in the string.
|
||||
|
@ -448,7 +448,7 @@ class Expression
|
|||
|
||||
// Make an expression that evaluates to some characteristic of a
|
||||
// slice. For simplicity, the enum values must match the field indexes
|
||||
// in the underlying struct.
|
||||
// in the underlying struct. This returns an lvalue.
|
||||
enum Slice_info
|
||||
{
|
||||
// The underlying data of the slice.
|
||||
|
@ -469,7 +469,7 @@ class Expression
|
|||
|
||||
// Make an expression that evaluates to some characteristic of an
|
||||
// interface. For simplicity, the enum values must match the field indexes
|
||||
// in the underlying struct.
|
||||
// in the underlying struct. This returns an lvalue.
|
||||
enum Interface_info
|
||||
{
|
||||
// The type descriptor of an empty interface.
|
||||
|
|
|
@ -822,6 +822,7 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing,
|
|||
Type* unsafe_ptr_type = Type::make_pointer_type(Type::make_void_type());
|
||||
lhs = Expression::make_unsafe_cast(unsafe_ptr_type, lhs, loc);
|
||||
|
||||
Type* uintptr_type = Type::lookup_integer_type("uintptr");
|
||||
Expression* call;
|
||||
switch (type->base()->classification())
|
||||
{
|
||||
|
@ -837,17 +838,125 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing,
|
|||
case Type::TYPE_CHANNEL:
|
||||
{
|
||||
// These types are all represented by a single pointer.
|
||||
Type* uintptr_type = Type::lookup_integer_type("uintptr");
|
||||
rhs = Expression::make_unsafe_cast(uintptr_type, rhs, loc);
|
||||
call = Runtime::make_call(Runtime::GCWRITEBARRIER, loc, 2, lhs, rhs);
|
||||
}
|
||||
break;
|
||||
|
||||
case Type::TYPE_STRING:
|
||||
case Type::TYPE_STRUCT:
|
||||
case Type::TYPE_ARRAY:
|
||||
{
|
||||
// Assign the length field directly.
|
||||
Expression* llen =
|
||||
Expression::make_string_info(indir->copy(),
|
||||
Expression::STRING_INFO_LENGTH,
|
||||
loc);
|
||||
Expression* rlen =
|
||||
Expression::make_string_info(rhs,
|
||||
Expression::STRING_INFO_LENGTH,
|
||||
loc);
|
||||
Statement* as = Statement::make_assignment(llen, rlen, loc);
|
||||
inserter->insert(as);
|
||||
|
||||
// Assign the data field with a write barrier.
|
||||
lhs =
|
||||
Expression::make_string_info(indir->copy(),
|
||||
Expression::STRING_INFO_DATA,
|
||||
loc);
|
||||
rhs =
|
||||
Expression::make_string_info(rhs,
|
||||
Expression::STRING_INFO_DATA,
|
||||
loc);
|
||||
assign = Statement::make_assignment(lhs, rhs, loc);
|
||||
lhs = Expression::make_unary(OPERATOR_AND, lhs, loc);
|
||||
rhs = Expression::make_unsafe_cast(uintptr_type, rhs, loc);
|
||||
call = Runtime::make_call(Runtime::GCWRITEBARRIER, loc, 2, lhs, rhs);
|
||||
}
|
||||
break;
|
||||
|
||||
case Type::TYPE_INTERFACE:
|
||||
{
|
||||
// Assign the first field directly.
|
||||
// The first field is either a type descriptor or a method table.
|
||||
// Type descriptors are either statically created, or created by
|
||||
// the reflect package. For the latter the reflect package keeps
|
||||
// all references.
|
||||
// Method tables are either statically created or persistently
|
||||
// allocated.
|
||||
// In all cases they don't need a write barrier.
|
||||
Expression* ltab =
|
||||
Expression::make_interface_info(indir->copy(),
|
||||
Expression::INTERFACE_INFO_METHODS,
|
||||
loc);
|
||||
Expression* rtab =
|
||||
Expression::make_interface_info(rhs,
|
||||
Expression::INTERFACE_INFO_METHODS,
|
||||
loc);
|
||||
Statement* as = Statement::make_assignment(ltab, rtab, loc);
|
||||
inserter->insert(as);
|
||||
|
||||
// Assign the data field with a write barrier.
|
||||
lhs =
|
||||
Expression::make_interface_info(indir->copy(),
|
||||
Expression::INTERFACE_INFO_OBJECT,
|
||||
loc);
|
||||
rhs =
|
||||
Expression::make_interface_info(rhs,
|
||||
Expression::INTERFACE_INFO_OBJECT,
|
||||
loc);
|
||||
assign = Statement::make_assignment(lhs, rhs, loc);
|
||||
lhs = Expression::make_unary(OPERATOR_AND, lhs, loc);
|
||||
rhs = Expression::make_unsafe_cast(uintptr_type, rhs, loc);
|
||||
call = Runtime::make_call(Runtime::GCWRITEBARRIER, loc, 2, lhs, rhs);
|
||||
}
|
||||
break;
|
||||
|
||||
case Type::TYPE_ARRAY:
|
||||
if (type->is_slice_type())
|
||||
{
|
||||
// Assign the lenth fields directly.
|
||||
Expression* llen =
|
||||
Expression::make_slice_info(indir->copy(),
|
||||
Expression::SLICE_INFO_LENGTH,
|
||||
loc);
|
||||
Expression* rlen =
|
||||
Expression::make_slice_info(rhs,
|
||||
Expression::SLICE_INFO_LENGTH,
|
||||
loc);
|
||||
Statement* as = Statement::make_assignment(llen, rlen, loc);
|
||||
inserter->insert(as);
|
||||
|
||||
// Assign the capacity fields directly.
|
||||
Expression* lcap =
|
||||
Expression::make_slice_info(indir->copy(),
|
||||
Expression::SLICE_INFO_CAPACITY,
|
||||
loc);
|
||||
Expression* rcap =
|
||||
Expression::make_slice_info(rhs,
|
||||
Expression::SLICE_INFO_CAPACITY,
|
||||
loc);
|
||||
as = Statement::make_assignment(lcap, rcap, loc);
|
||||
inserter->insert(as);
|
||||
|
||||
// Assign the data field with a write barrier.
|
||||
lhs =
|
||||
Expression::make_slice_info(indir->copy(),
|
||||
Expression::SLICE_INFO_VALUE_POINTER,
|
||||
loc);
|
||||
rhs =
|
||||
Expression::make_slice_info(rhs,
|
||||
Expression::SLICE_INFO_VALUE_POINTER,
|
||||
loc);
|
||||
assign = Statement::make_assignment(lhs, rhs, loc);
|
||||
lhs = Expression::make_unary(OPERATOR_AND, lhs, loc);
|
||||
rhs = Expression::make_unsafe_cast(uintptr_type, rhs, loc);
|
||||
call = Runtime::make_call(Runtime::GCWRITEBARRIER, loc, 2, lhs, rhs);
|
||||
break;
|
||||
}
|
||||
// fallthrough
|
||||
|
||||
case Type::TYPE_STRUCT:
|
||||
{
|
||||
// TODO: split assignments for small struct/array?
|
||||
rhs = Expression::make_unary(OPERATOR_AND, rhs, loc);
|
||||
rhs->unary_expression()->set_does_not_escape();
|
||||
call = Runtime::make_call(Runtime::TYPEDMEMMOVE, loc, 3,
|
||||
|
|
Loading…
Add table
Reference in a new issue