Use different allocation when memory can not contain pointers. R=iant https://golang.org/cl/1849044
diff --git a/go/expressions.cc b/go/expressions.cc index baf8537..19a6120 100644 --- a/go/expressions.cc +++ b/go/expressions.cc
@@ -10252,8 +10252,9 @@ { tree type_tree = this->type_->get_tree(context->gogo()); tree size_tree = TYPE_SIZE_UNIT(type_tree); - tree space = context->gogo()->allocate_memory(size_tree, this->location()); - return fold_convert(build_pointer_type (type_tree), space); + tree space = context->gogo()->allocate_memory(this->type_, size_tree, + this->location()); + return fold_convert(build_pointer_type(type_tree), space); } // Make an allocation expression. @@ -11122,7 +11123,8 @@ else { tree memsize = TYPE_SIZE_UNIT(TREE_TYPE(values)); - space = context->gogo()->allocate_memory(memsize, this->location()); + space = context->gogo()->allocate_memory(element_type, memsize, + this->location()); space = save_expr(space); tree s = fold_convert(build_pointer_type(TREE_TYPE(values)), space); @@ -12106,7 +12108,8 @@ return error_mark_node; tree expr_size = TYPE_SIZE_UNIT(TREE_TYPE(expr_tree)); gcc_assert(TREE_CODE(expr_size) == INTEGER_CST); - tree space = context->gogo()->allocate_memory(expr_size, this->location()); + tree space = context->gogo()->allocate_memory(this->expr_->type(), + expr_size, this->location()); space = fold_convert(build_pointer_type(TREE_TYPE(expr_tree)), space); space = save_expr(space); tree ret = build2(COMPOUND_EXPR, TREE_TYPE(space),
diff --git a/go/gogo-tree.cc b/go/gogo-tree.cc index 127ae25..b4aa530 100644 --- a/go/gogo-tree.cc +++ b/go/gogo-tree.cc
@@ -666,6 +666,12 @@ // Pass everything back to the middle-end. + if (this->imported_unsafe_) + { + // Importing the "unsafe" package automatically disables TBAA. + flag_strict_aliasing = false; + } + wrapup_global_declarations(vec, count); cgraph_finalize_compilation_unit(); @@ -918,7 +924,8 @@ init = type->get_init_tree(gogo, false); else { - tree space = gogo->allocate_memory(TYPE_SIZE_UNIT(result_type), + tree space = gogo->allocate_memory(type, + TYPE_SIZE_UNIT(result_type), loc); result_type = build_pointer_type(result_type); tree subinit = type->get_init_tree(gogo, true); @@ -1265,7 +1272,8 @@ if (is_in_heap) { tree size = TYPE_SIZE_UNIT(val_type); - tree space = gogo->allocate_memory(size, DECL_SOURCE_LOCATION(var_decl)); + tree space = gogo->allocate_memory(no->var_value()->type(), size, + no->location()); space = save_expr(space); space = fold_convert(build_pointer_type(val_type), space); init = build2(COMPOUND_EXPR, TREE_TYPE(space), @@ -1285,7 +1293,7 @@ // indirection. tree -Function::copy_parm_to_heap(Gogo* gogo, tree ref) +Function::copy_parm_to_heap(Gogo* gogo, Named_object* no, tree ref) { gcc_assert(TREE_CODE(ref) == INDIRECT_REF); @@ -1306,7 +1314,7 @@ DECL_ARG_TYPE(parm_decl) = type; tree size = TYPE_SIZE_UNIT(type); - tree space = gogo->allocate_memory(size, loc); + tree space = gogo->allocate_memory(no->var_value()->type(), size, loc); space = save_expr(space); space = fold_convert(TREE_TYPE(var_decl), space); tree init = build2(COMPOUND_EXPR, TREE_TYPE(space), @@ -1359,7 +1367,7 @@ { // If we take the address of a parameter, then we need // to copy it into the heap. - tree parm_decl = this->copy_parm_to_heap(gogo, *pp); + tree parm_decl = this->copy_parm_to_heap(gogo, *p, *pp); gcc_assert(TREE_CODE(*pp) == INDIRECT_REF); tree var_decl = TREE_OPERAND(*pp, 0); gcc_assert(TREE_CODE(var_decl) == VAR_DECL); @@ -1927,19 +1935,36 @@ return NULL_TREE; } -// Return a tree which allocates SIZE bytes. +// Return a tree which allocates SIZE bytes which will holds value of +// type TYPE. tree -Gogo::allocate_memory(tree size, source_location location) +Gogo::allocate_memory(Type* type, tree size, source_location location) { - static tree new_fndecl; - return Gogo::call_builtin(&new_fndecl, - location, - "__go_new", - 1, - ptr_type_node, - sizetype, - size); + // If the package imports unsafe, then it may play games with + // pointers that look like integers. + if (this->imported_unsafe_ || type->has_pointer()) + { + static tree new_fndecl; + return Gogo::call_builtin(&new_fndecl, + location, + "__go_new", + 1, + ptr_type_node, + sizetype, + size); + } + else + { + static tree new_nopointers_fndecl; + return Gogo::call_builtin(&new_nopointers_fndecl, + location, + "__go_new_nopointers", + 1, + ptr_type_node, + sizetype, + size); + } } // Build a builtin struct with a list of fields. The name is
diff --git a/go/gogo.cc b/go/gogo.cc index 84b4cfa..3e8baf9 100644 --- a/go/gogo.cc +++ b/go/gogo.cc
@@ -27,6 +27,7 @@ functions_(), globals_(new Bindings(NULL)), imports_(), + imported_unsafe_(false), packages_(), map_descriptors_(NULL), type_descriptor_decls_(NULL),
diff --git a/go/gogo.h b/go/gogo.h index 14b2314..4f8c3c0 100644 --- a/go/gogo.h +++ b/go/gogo.h
@@ -520,9 +520,10 @@ tree interface_method_table_for_type(const Interface_type*, const Named_type*); - // Return a tree which allocates SIZE bytes. + // Return a tree which allocate SIZE bytes to hold values of type + // TYPE. tree - allocate_memory(tree size, source_location); + allocate_memory(Type *type, tree size, source_location); // Return a type to use for pointer to const char. static tree @@ -761,6 +762,8 @@ Bindings* globals_; // Mapping from import file names to packages. Imports imports_; + // Whether the magic unsafe package was imported. + bool imported_unsafe_; // Mapping from package names we have seen to packages. This does // not include the package we are compiling. Packages packages_; @@ -1084,7 +1087,7 @@ make_receiver_parm_decl(Gogo*, Named_object*, tree); tree - copy_parm_to_heap(Gogo*, tree); + copy_parm_to_heap(Gogo*, Named_object*, tree); void build_defer_wrapper(Gogo*, Named_object*, tree, tree*, tree*);
diff --git a/go/statements.cc b/go/statements.cc index 002c5b6..af28c74 100644 --- a/go/statements.cc +++ b/go/statements.cc
@@ -267,7 +267,8 @@ tree type = TREE_TYPE(decl); gcc_assert(POINTER_TYPE_P(type)); tree size = TYPE_SIZE_UNIT(TREE_TYPE(type)); - tree space = context->gogo()->allocate_memory(size, this->location()); + tree space = context->gogo()->allocate_memory(variable->type(), size, + this->location()); space = fold_convert(TREE_TYPE(decl), space); DECL_INITIAL(decl) = space; return build2(COMPOUND_EXPR, void_type_node,
diff --git a/go/types.cc b/go/types.cc index d2f96b6..1e3e832 100644 --- a/go/types.cc +++ b/go/types.cc
@@ -2492,6 +2492,10 @@ { } protected: + bool + do_has_pointer() const + { gcc_unreachable(); } + tree do_get_tree(Gogo*); @@ -2649,6 +2653,24 @@ return true; } +// Whether this contains a pointer. + +bool +Struct_type::do_has_pointer() const +{ + const Struct_field_list* fields = this->fields(); + if (fields == NULL) + return false; + for (Struct_field_list::const_iterator p = fields->begin(); + p != fields->end(); + ++p) + { + if (p->type()->has_pointer()) + return true; + } + return false; +} + // Whether this contains a reference counted component. bool @@ -3621,7 +3643,8 @@ tree size_tree = fold_build2_loc(location, MULT_EXPR, TREE_TYPE(count_field), element_size_tree, capacity_tree); - tree space = context->gogo()->allocate_memory(size_tree, location); + tree space = context->gogo()->allocate_memory(this->element_type_, + size_tree, location); if (value != NULL_TREE) space = save_expr(space);
diff --git a/go/types.h b/go/types.h index 577a877..d5ee0f9 100644 --- a/go/types.h +++ b/go/types.h
@@ -583,6 +583,13 @@ Type* make_non_abstract_type(); + // Return true if this type is or contains a pointer. This + // determines whether the garbage collector needs to look at a value + // of this type. + bool + has_pointer() const + { return this->do_has_pointer(); } + // Return true if this type requires reference counting: if copying // or destroying a value of this type requires adjusting a reference // count. @@ -888,6 +895,10 @@ { return true; } virtual bool + do_has_pointer() const + { return false; } + + virtual bool do_is_refcounted() const { return false; } @@ -1488,6 +1499,10 @@ protected: bool + do_has_pointer() const + { return true; } + + bool do_is_refcounted() const { return true; } @@ -1600,6 +1615,11 @@ int do_traverse(Traverse*); + // A trampoline function has a pointer which matters for GC. + bool + do_has_pointer() const + { return true; } + // Function types are really pointers, and they are reference // counted in case that pointer points to a trampoline. bool @@ -1670,6 +1690,10 @@ do_traverse(Traverse*); bool + do_has_pointer() const + { return true; } + + bool do_is_refcounted() const { return !this->is_unsafe_pointer_type(); } @@ -1922,6 +1946,9 @@ do_verify(); bool + do_has_pointer() const; + + bool do_has_refcounted_component() const; void @@ -2015,6 +2042,12 @@ do_traverse(Traverse* traverse); bool + do_has_pointer() const + { + return this->length_ == NULL || this->element_type_->has_pointer(); + } + + bool do_is_refcounted() const { return (this->length_ == NULL @@ -2108,6 +2141,10 @@ do_verify(); bool + do_has_pointer() const + { return true; } + + bool do_is_refcounted() const { return true; } @@ -2189,6 +2226,10 @@ { return Type::traverse(this->element_type_, traverse); } bool + do_has_pointer() const + { return true; } + + bool do_is_refcounted() const { return true; } @@ -2293,6 +2334,10 @@ do_traverse(Traverse*); bool + do_has_pointer() const + { return true; } + + bool do_is_refcounted() const { return true; } @@ -2493,6 +2538,10 @@ do_verify(); bool + do_has_pointer() const + { return this->type_->has_pointer(); } + + bool do_is_refcounted() const { return this->type_->is_refcounted(); } @@ -2626,6 +2675,10 @@ do_traverse(Traverse* traverse); bool + do_has_pointer() const + { return this->base()->has_pointer(); } + + bool do_is_refcounted() const { return this->base()->is_refcounted(); }
diff --git a/go/unsafe.cc b/go/unsafe.cc index 437829f..51d812b 100644 --- a/go/unsafe.cc +++ b/go/unsafe.cc
@@ -18,9 +18,6 @@ { location_t bloc = BUILTINS_LOCATION; - // Importing the "unsafe" package automatically disables TBAA. - flag_strict_aliasing = false; - bool add_to_globals; Package* package = this->add_imported_package("unsafe", local_name, is_local_name_exported, @@ -132,4 +129,6 @@ no = bindings->add_function_declaration("NewArray", package, fntype, bloc); if (add_to_globals) this->add_named_object(no); + + this->imported_unsafe_ = true; }