From patchwork Fri May 25 21:51:47 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 161430 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 5990DB6EEC for ; Sat, 26 May 2012 07:52:11 +1000 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1338587532; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:Received:From:To:Subject:Date:Message-ID:User-Agent: MIME-Version:Content-Type:Mailing-List:Precedence:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:Sender: Delivered-To; bh=f6kwzN9IFzBV00xfEWdM8+59BNY=; b=hozpnKTv4FXNkgg ZF5DvXNEZJUEm2NOU8TszYMmQZcPzm0Paf915gVh2+7u4pZCpxACvmOvUaAklV2p /Sn93mxXItqOgGCsaz0uIRh+wiOCBCJ4ymkOa4XcmIkz8/80WEOySYqfwzqQiRtc a1sTJM/ByovxcwFpoFvpnkV5FqKo= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:X-Google-DKIM-Signature:Received:Received:Received:From:To:Subject:Date:Message-ID:User-Agent:MIME-Version:Content-Type:X-Gm-Message-State:X-IsSubscribed:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=slFw9a/d3uMUt8Vx/Xohb1gNO1KYvBV0XiC4UD3UIAc43l9SGyO+q6gLt1/Cqc Md45YFLEEacymfT045X/curdQaD4UC4vLZwRmUWDknHp2foAWrfUg//VhKSCldOQ uviTXj92DjjbYGg+jxjwB47DVkpX5oSGqbNxVZkFxZTsM=; Received: (qmail 16432 invoked by alias); 25 May 2012 21:52:06 -0000 Received: (qmail 16421 invoked by uid 22791); 25 May 2012 21:52:03 -0000 X-SWARE-Spam-Status: No, hits=-4.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, KHOP_RCVD_TRUST, RCVD_IN_DNSWL_LOW, RCVD_IN_HOSTKARMA_YE, T_RP_MATCHES_RCVD, T_TVD_MIME_NO_HEADERS X-Spam-Check-By: sourceware.org Received: from mail-pz0-f47.google.com (HELO mail-pz0-f47.google.com) (209.85.210.47) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 25 May 2012 21:51:49 +0000 Received: by dalh21 with SMTP id h21so1700136dal.20 for ; Fri, 25 May 2012 14:51:49 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:subject:date:message-id:user-agent:mime-version :content-type:x-gm-message-state; bh=O2UKgkNcaMrlTWJPc1J1LUNk4Yu3qsWSW5iBHf4VppI=; b=Vv5Iuzaw9FQKYwoBpXQPotF2EKFaiBqF3Mg+p1w0SJ8ReWxzGmAbGy+8mrpipEOxaa XzIw46xfDjQhp4C5RxjwcTETEPv9gjbkkOZM3bHOd6WaqpPVnCeOkpJpmtGU5e4IRT1Q d/tjaFEARkNacyrBVlQBfJMxR2ibalUrqCjvJnDnJBuu40FJS30HdhMe3oO96g1q0lJ1 GRLdFA3rXK04YoBnEVEKSmD1J2OqZg+nn4YMocykQRfb6Fs6yG0n5b9iPt86VyjNr2Tk ZkAdD0yZd0HSXypsw4F9rkI6HLE430cRgKRd9FI0I0HOPiNweGG6+fNUj/HVaEl6C9Zl DV5g== Received: by 10.68.202.99 with SMTP id kh3mr1094719pbc.157.1337982709251; Fri, 25 May 2012 14:51:49 -0700 (PDT) Received: by 10.68.202.99 with SMTP id kh3mr1094706pbc.157.1337982709132; Fri, 25 May 2012 14:51:49 -0700 (PDT) Received: from coign.google.com ([2620:0:1000:2301:f2de:f1ff:fe40:72a8]) by mx.google.com with ESMTPS id mt9sm10296399pbb.14.2012.05.25.14.51.48 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 25 May 2012 14:51:48 -0700 (PDT) From: Ian Lance Taylor To: gcc-patches@gcc.gnu.org, gofrontend-dev@googlegroups.com Subject: libgo patch committed: More efficient trampoline allocation Date: Fri, 25 May 2012 14:51:47 -0700 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) MIME-Version: 1.0 X-Gm-Message-State: ALoCoQk1zL1yXiTe0X3MTnEdH6NYLumGqkbGhduSl0s1vmNL6UygNf3HCPhscK3XYt9HxoE0J42oDpkHwsyFia6I6ZNF2x6yTfhAZ4GiUFDnTvWu9rwN9DUbrLIe3YgjdHf4bdFDtFpcKy2iu4OUUSM2oUxd/4Z0pQ== 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 to libgo makes the implementation of function trampolines, used for nested functions that refer to variables in an enclosing function scope, much more efficient. Previously we were allocating a separate page for each trampoline. This patch packs them on a single page as much as possible. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Commited to mainline and 4.7 branch. Ian diff -r 9dad4e6b17e9 libgo/runtime/go-trampoline.c --- a/libgo/runtime/go-trampoline.c Fri May 25 14:12:42 2012 -0700 +++ b/libgo/runtime/go-trampoline.c Fri May 25 14:45:55 2012 -0700 @@ -14,40 +14,100 @@ #include #endif -#include "go-alloc.h" +#include "runtime.h" +#include "arch.h" +#include "malloc.h" #include "go-assert.h" -/* In order to build a trampoline we need space which is both writable - and executable. We currently just allocate a whole page. This - needs to be more system dependent. */ +/* Trampolines need to run in memory that is both writable and + executable. In order to implement them, we grab a page of memory + and mprotect it. We fill in the page with trampolines as they are + required. When we run out of space, we drop the pointer to the + page and allocate a new one. The page will be freed by the garbage + collector when there are no more variables of type func pointing to + it. */ + +/* A lock to control access to the page of closures. */ + +static Lock trampoline_lock; + +/* The page of closures. */ + +static unsigned char *trampoline_page; + +/* The size of trampoline_page. */ + +static uintptr_t trampoline_page_size; + +/* The number of bytes we have used on trampoline_page. */ + +static uintptr_t trampoline_page_used; + +/* Allocate a trampoline of SIZE bytes that will use the closure in + CLOSURE. */ void * __go_allocate_trampoline (uintptr_t size, void *closure) { - unsigned int page_size; - void *ret; - size_t off; + uintptr_t ptr_size; + uintptr_t full_size; + unsigned char *ret; - page_size = getpagesize (); - __go_assert (page_size >= size); - ret = __go_alloc (2 * page_size - 1); - ret = (void *) (((uintptr_t) ret + page_size - 1) - & ~ ((uintptr_t) page_size - 1)); + /* Because the garbage collector only looks at aligned addresses, we + need to store the closure at an aligned address to ensure that it + sees it. */ + ptr_size = sizeof (void *); + full_size = (((size + ptr_size - 1) / ptr_size) * ptr_size); + full_size += ptr_size; - /* Because the garbage collector only looks at correct address - offsets, we need to ensure that it will see the closure - address. */ - off = ((size + sizeof (void *) - 1) / sizeof (void *)) * sizeof (void *); - __go_assert (size + off + sizeof (void *) <= page_size); - __builtin_memcpy (ret + off, &closure, sizeof (void *)); + runtime_lock (&trampoline_lock); + + if (full_size < trampoline_page_size - trampoline_page_used) + trampoline_page = NULL; + + if (trampoline_page == NULL) + { + uintptr_t page_size; + unsigned char *page; + + page_size = getpagesize (); + __go_assert (page_size >= full_size); + page = (unsigned char *) runtime_mallocgc (2 * page_size - 1, 0, 0, 0); + page = (unsigned char *) (((uintptr_t) page + page_size - 1) + & ~ (page_size - 1)); #ifdef HAVE_SYS_MMAN_H - { - int i; - i = mprotect (ret, size, PROT_READ | PROT_WRITE | PROT_EXEC); - __go_assert (i == 0); - } + { + int i; + + i = mprotect (page, page_size, PROT_READ | PROT_WRITE | PROT_EXEC); + __go_assert (i == 0); + } #endif - return ret; + trampoline_page = page; + trampoline_page_size = page_size; + trampoline_page_used = 0; + } + + ret = trampoline_page + trampoline_page_used; + trampoline_page_used += full_size; + + runtime_unlock (&trampoline_lock); + + __builtin_memcpy (ret + full_size - ptr_size, &closure, ptr_size); + + return (void *) ret; } + +/* Scan the trampoline page when running the garbage collector. This + just makes sure that the garbage collector sees the pointer in + trampoline_page, so that the page itself is not freed if there are + no other references to it. */ + +void +runtime_trampoline_scan (void (*scan) (byte *, int64)) +{ + if (trampoline_page != NULL) + scan ((byte *) &trampoline_page, sizeof trampoline_page); +} diff -r 9dad4e6b17e9 libgo/runtime/mgc0.c --- a/libgo/runtime/mgc0.c Fri May 25 14:12:42 2012 -0700 +++ b/libgo/runtime/mgc0.c Fri May 25 14:45:55 2012 -0700 @@ -703,6 +703,7 @@ scan((byte*)&runtime_allm, sizeof runtime_allm); runtime_MProf_Mark(scan); runtime_time_scan(scan); + runtime_trampoline_scan(scan); // mark stacks for(gp=runtime_allg; gp!=nil; gp=gp->alllink) { diff -r 9dad4e6b17e9 libgo/runtime/runtime.h --- a/libgo/runtime/runtime.h Fri May 25 14:12:42 2012 -0700 +++ b/libgo/runtime/runtime.h Fri May 25 14:45:55 2012 -0700 @@ -490,6 +490,7 @@ void runtime_setprof(bool); void runtime_time_scan(void (*)(byte*, int64)); +void runtime_trampoline_scan(void (*)(byte *, int64)); void runtime_setsig(int32, bool, bool); #define runtime_setitimer setitimer