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
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,
......
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