aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2019-06-07 21:16:11 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2019-06-07 21:16:11 +0000
commit1afab7a878555956f4842dcbed19bfe3c1c28a6e (patch)
tree2eabbd83ae15107c9d8981d043ef0aa5411fd6de
parent7a649ef59f9c32dd164a8e62b6eddb778cd7cb12 (diff)
downloadgcc-1afab7a878555956f4842dcbed19bfe3c1c28a6e.zip
gcc-1afab7a878555956f4842dcbed19bfe3c1c28a6e.tar.gz
gcc-1afab7a878555956f4842dcbed19bfe3c1c28a6e.tar.bz2
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
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/expressions.h6
-rw-r--r--gcc/go/gofrontend/wb.cc115
3 files changed, 116 insertions, 7 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index e107d52..91b85c0 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -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.
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 6ba7fe1..22dd2fc 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -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.
diff --git a/gcc/go/gofrontend/wb.cc b/gcc/go/gofrontend/wb.cc
index 2eae08f..47cffee 100644
--- a/gcc/go/gofrontend/wb.cc
+++ b/gcc/go/gofrontend/wb.cc
@@ -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,