Commit d4dc840d by Ian Lance Taylor

runtime: More efficient implementation of trampolines.

From-SVN: r187899
parent 40bb0243
...@@ -14,40 +14,100 @@ ...@@ -14,40 +14,100 @@
#include <sys/mman.h> #include <sys/mman.h>
#endif #endif
#include "go-alloc.h" #include "runtime.h"
#include "arch.h"
#include "malloc.h"
#include "go-assert.h" #include "go-assert.h"
/* In order to build a trampoline we need space which is both writable /* Trampolines need to run in memory that is both writable and
and executable. We currently just allocate a whole page. This executable. In order to implement them, we grab a page of memory
needs to be more system dependent. */ 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 * void *
__go_allocate_trampoline (uintptr_t size, void *closure) __go_allocate_trampoline (uintptr_t size, void *closure)
{ {
unsigned int page_size; uintptr_t ptr_size;
void *ret; uintptr_t full_size;
size_t off; unsigned char *ret;
page_size = getpagesize (); /* Because the garbage collector only looks at aligned addresses, we
__go_assert (page_size >= size); need to store the closure at an aligned address to ensure that it
ret = __go_alloc (2 * page_size - 1); sees it. */
ret = (void *) (((uintptr_t) ret + page_size - 1) ptr_size = sizeof (void *);
& ~ ((uintptr_t) page_size - 1)); 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 runtime_lock (&trampoline_lock);
address. */
off = ((size + sizeof (void *) - 1) / sizeof (void *)) * sizeof (void *); if (full_size < trampoline_page_size - trampoline_page_used)
__go_assert (size + off + sizeof (void *) <= page_size); trampoline_page = NULL;
__builtin_memcpy (ret + off, &closure, sizeof (void *));
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 #ifdef HAVE_SYS_MMAN_H
{ {
int i; int i;
i = mprotect (ret, size, PROT_READ | PROT_WRITE | PROT_EXEC);
__go_assert (i == 0); i = mprotect (page, page_size, PROT_READ | PROT_WRITE | PROT_EXEC);
} __go_assert (i == 0);
}
#endif #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);
} }
...@@ -703,6 +703,7 @@ mark(void (*scan)(byte*, int64)) ...@@ -703,6 +703,7 @@ mark(void (*scan)(byte*, int64))
scan((byte*)&runtime_allm, sizeof runtime_allm); scan((byte*)&runtime_allm, sizeof runtime_allm);
runtime_MProf_Mark(scan); runtime_MProf_Mark(scan);
runtime_time_scan(scan); runtime_time_scan(scan);
runtime_trampoline_scan(scan);
// mark stacks // mark stacks
for(gp=runtime_allg; gp!=nil; gp=gp->alllink) { for(gp=runtime_allg; gp!=nil; gp=gp->alllink) {
......
...@@ -490,6 +490,7 @@ uintptr runtime_memlimit(void); ...@@ -490,6 +490,7 @@ uintptr runtime_memlimit(void);
void runtime_setprof(bool); void runtime_setprof(bool);
void runtime_time_scan(void (*)(byte*, int64)); void runtime_time_scan(void (*)(byte*, int64));
void runtime_trampoline_scan(void (*)(byte *, int64));
void runtime_setsig(int32, bool, bool); void runtime_setsig(int32, bool, bool);
#define runtime_setitimer setitimer #define runtime_setitimer setitimer
......
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