From patchwork Fri Jul 23 16:45:15 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 59820 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 78E7A1007D1 for ; Sat, 24 Jul 2010 02:45:36 +1000 (EST) Received: (qmail 11750 invoked by alias); 23 Jul 2010 16:45:33 -0000 Received: (qmail 11738 invoked by uid 22791); 23 Jul 2010 16:45:31 -0000 X-SWARE-Spam-Status: No, hits=-2.0 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, SPF_HELO_PASS, TW_CC, T_RP_MATCHES_RCVD, T_TVD_MIME_NO_HEADERS X-Spam-Check-By: sourceware.org Received: from smtp-out.google.com (HELO smtp-out.google.com) (74.125.121.35) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 23 Jul 2010 16:45:24 +0000 Received: from hpaq2.eem.corp.google.com (hpaq2.eem.corp.google.com [172.25.149.2]) by smtp-out.google.com with ESMTP id o6NGjLYm030965 for ; Fri, 23 Jul 2010 09:45:21 -0700 Received: from eyz10 (eyz10.prod.google.com [10.208.26.10]) by hpaq2.eem.corp.google.com with ESMTP id o6NGjKCY020570 for ; Fri, 23 Jul 2010 09:45:20 -0700 Received: by eyz10 with SMTP id 10so129914eyz.11 for ; Fri, 23 Jul 2010 09:45:20 -0700 (PDT) Received: by 10.213.56.17 with SMTP id w17mr956651ebg.76.1279903520218; Fri, 23 Jul 2010 09:45:20 -0700 (PDT) Received: from coign.google.com (81-233-149-58-no82.tbcn.telia.com [81.233.149.58]) by mx.google.com with ESMTPS id a48sm656546eei.7.2010.07.23.09.45.17 (version=TLSv1/SSLv3 cipher=RC4-MD5); Fri, 23 Jul 2010 09:45:18 -0700 (PDT) From: Ian Lance Taylor To: gcc-patches@gcc.gnu.org, gofrontend-dev@googlegroups.com Subject: [gccgo] Mark memory which can not contain pointers Date: Fri, 23 Jul 2010 09:45:15 -0700 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) MIME-Version: 1.0 X-System-Of-Record: true X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org This patch uses a different allocation routine for memory which can not contain pointers (e.g., []byte). The marking already exists in the memory allocator, this just changes the compiler to use it. This is in preparation for garbage collection. Committed to gccgo branch. Ian diff -r 640e5a4f513f go/expressions.cc --- a/go/expressions.cc Fri Jul 23 03:59:55 2010 -0700 +++ b/go/expressions.cc Fri Jul 23 09:36:21 2010 -0700 @@ -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 -r 640e5a4f513f go/gogo-tree.cc --- a/go/gogo-tree.cc Fri Jul 23 03:59:55 2010 -0700 +++ b/go/gogo-tree.cc Fri Jul 23 09:36:21 2010 -0700 @@ -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 -r 640e5a4f513f go/gogo.cc --- a/go/gogo.cc Fri Jul 23 03:59:55 2010 -0700 +++ b/go/gogo.cc Fri Jul 23 09:36:21 2010 -0700 @@ -27,6 +27,7 @@ functions_(), globals_(new Bindings(NULL)), imports_(), + imported_unsafe_(false), packages_(), map_descriptors_(NULL), type_descriptor_decls_(NULL), diff -r 640e5a4f513f go/gogo.h --- a/go/gogo.h Fri Jul 23 03:59:55 2010 -0700 +++ b/go/gogo.h Fri Jul 23 09:36:21 2010 -0700 @@ -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 -r 640e5a4f513f go/statements.cc --- a/go/statements.cc Fri Jul 23 03:59:55 2010 -0700 +++ b/go/statements.cc Fri Jul 23 09:36:21 2010 -0700 @@ -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 -r 640e5a4f513f go/types.cc --- a/go/types.cc Fri Jul 23 03:59:55 2010 -0700 +++ b/go/types.cc Fri Jul 23 09:36:21 2010 -0700 @@ -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 -r 640e5a4f513f go/types.h --- a/go/types.h Fri Jul 23 03:59:55 2010 -0700 +++ b/go/types.h Fri Jul 23 09:36:21 2010 -0700 @@ -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 -r 640e5a4f513f go/unsafe.cc --- a/go/unsafe.cc Fri Jul 23 03:59:55 2010 -0700 +++ b/go/unsafe.cc Fri Jul 23 09:36:21 2010 -0700 @@ -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; } diff -r 640e5a4f513f libgo/runtime/go-new.c --- a/libgo/runtime/go-new.c Fri Jul 23 03:59:55 2010 -0700 +++ b/libgo/runtime/go-new.c Fri Jul 23 09:36:21 2010 -0700 @@ -5,13 +5,17 @@ license that can be found in the LICENSE file. */ #include "go-alloc.h" +#include "runtime.h" +#include "malloc.h" void * __go_new (size_t size) { - void *ret; + return __go_alloc (size); +} - ret = __go_alloc (size); - __builtin_memset (ret, 0, size); - return ret; +void * +__go_new_nopointers (size_t size) +{ + return mallocgc (size, RefNoPointers, 1, 1); }