Commit 1afab7a8 by Ian Lance Taylor

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
parent 7a649ef5
9df825b5f142ac2b6f48a8dac94fcff740acd411 b79e9e79fddc9040ab58c7c518eb08454f308def
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -237,7 +237,7 @@ class Expression ...@@ -237,7 +237,7 @@ class Expression
// Make an expression that evaluates to some characteristic of an string. // Make an expression that evaluates to some characteristic of an string.
// For simplicity, the enum values must match the field indexes in the // For simplicity, the enum values must match the field indexes in the
// underlying struct. // underlying struct. This returns an lvalue.
enum String_info enum String_info
{ {
// The underlying data in the string. // The underlying data in the string.
...@@ -448,7 +448,7 @@ class Expression ...@@ -448,7 +448,7 @@ class Expression
// Make an expression that evaluates to some characteristic of a // Make an expression that evaluates to some characteristic of a
// slice. For simplicity, the enum values must match the field indexes // 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 enum Slice_info
{ {
// The underlying data of the slice. // The underlying data of the slice.
...@@ -469,7 +469,7 @@ class Expression ...@@ -469,7 +469,7 @@ class Expression
// Make an expression that evaluates to some characteristic of an // Make an expression that evaluates to some characteristic of an
// interface. For simplicity, the enum values must match the field indexes // 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 enum Interface_info
{ {
// The type descriptor of an empty interface. // The type descriptor of an empty interface.
......
...@@ -822,6 +822,7 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing, ...@@ -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()); Type* unsafe_ptr_type = Type::make_pointer_type(Type::make_void_type());
lhs = Expression::make_unsafe_cast(unsafe_ptr_type, lhs, loc); lhs = Expression::make_unsafe_cast(unsafe_ptr_type, lhs, loc);
Type* uintptr_type = Type::lookup_integer_type("uintptr");
Expression* call; Expression* call;
switch (type->base()->classification()) switch (type->base()->classification())
{ {
...@@ -837,17 +838,125 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing, ...@@ -837,17 +838,125 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing,
case Type::TYPE_CHANNEL: case Type::TYPE_CHANNEL:
{ {
// These types are all represented by a single pointer. // 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); rhs = Expression::make_unsafe_cast(uintptr_type, rhs, loc);
call = Runtime::make_call(Runtime::GCWRITEBARRIER, loc, 2, lhs, rhs); call = Runtime::make_call(Runtime::GCWRITEBARRIER, loc, 2, lhs, rhs);
} }
break; break;
case Type::TYPE_STRING: 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: 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 = Expression::make_unary(OPERATOR_AND, rhs, loc);
rhs->unary_expression()->set_does_not_escape(); rhs->unary_expression()->set_does_not_escape();
call = Runtime::make_call(Runtime::TYPEDMEMMOVE, loc, 3, call = Runtime::make_call(Runtime::TYPEDMEMMOVE, loc, 3,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment