]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgo/runtime/go-trampoline.c
libgo: Update to current sources.
[thirdparty/gcc.git] / libgo / runtime / go-trampoline.c
CommitLineData
7a938933
ILT
1/* go-trampoline.c -- allocate a trampoline for a nested function.
2
3 Copyright 2009 The Go Authors. All rights reserved.
4 Use of this source code is governed by a BSD-style
5 license that can be found in the LICENSE file. */
6
7#include "config.h"
8
9#include <stddef.h>
10#include <stdint.h>
11#include <unistd.h>
12
13#ifdef HAVE_SYS_MMAN_H
14#include <sys/mman.h>
15#endif
16
d4dc840d
ILT
17#include "runtime.h"
18#include "arch.h"
19#include "malloc.h"
7a938933
ILT
20#include "go-assert.h"
21
d4dc840d
ILT
22/* Trampolines need to run in memory that is both writable and
23 executable. In order to implement them, we grab a page of memory
24 and mprotect it. We fill in the page with trampolines as they are
25 required. When we run out of space, we drop the pointer to the
26 page and allocate a new one. The page will be freed by the garbage
27 collector when there are no more variables of type func pointing to
28 it. */
29
30/* A lock to control access to the page of closures. */
31
32static Lock trampoline_lock;
33
34/* The page of closures. */
35
36static unsigned char *trampoline_page;
37
38/* The size of trampoline_page. */
39
40static uintptr_t trampoline_page_size;
41
42/* The number of bytes we have used on trampoline_page. */
43
44static uintptr_t trampoline_page_used;
45
46/* Allocate a trampoline of SIZE bytes that will use the closure in
47 CLOSURE. */
7a938933
ILT
48
49void *
b39c10b8 50__go_allocate_trampoline (uintptr_t size, void *closure)
7a938933 51{
d4dc840d
ILT
52 uintptr_t ptr_size;
53 uintptr_t full_size;
54 unsigned char *ret;
55
56 /* Because the garbage collector only looks at aligned addresses, we
57 need to store the closure at an aligned address to ensure that it
58 sees it. */
59 ptr_size = sizeof (void *);
60 full_size = (((size + ptr_size - 1) / ptr_size) * ptr_size);
61 full_size += ptr_size;
62
63 runtime_lock (&trampoline_lock);
64
65 if (full_size < trampoline_page_size - trampoline_page_used)
66 trampoline_page = NULL;
67
68 if (trampoline_page == NULL)
69 {
70 uintptr_t page_size;
71 unsigned char *page;
72
73 page_size = getpagesize ();
74 __go_assert (page_size >= full_size);
75 page = (unsigned char *) runtime_mallocgc (2 * page_size - 1, 0, 0, 0);
76 page = (unsigned char *) (((uintptr_t) page + page_size - 1)
77 & ~ (page_size - 1));
7a938933
ILT
78
79#ifdef HAVE_SYS_MMAN_H
d4dc840d
ILT
80 {
81 int i;
82
83 i = mprotect (page, page_size, PROT_READ | PROT_WRITE | PROT_EXEC);
84 __go_assert (i == 0);
85 }
7a938933
ILT
86#endif
87
d4dc840d
ILT
88 trampoline_page = page;
89 trampoline_page_size = page_size;
90 trampoline_page_used = 0;
91 }
92
93 ret = trampoline_page + trampoline_page_used;
94 trampoline_page_used += full_size;
95
96 runtime_unlock (&trampoline_lock);
97
98 __builtin_memcpy (ret + full_size - ptr_size, &closure, ptr_size);
99
100 return (void *) ret;
101}
102
103/* Scan the trampoline page when running the garbage collector. This
104 just makes sure that the garbage collector sees the pointer in
105 trampoline_page, so that the page itself is not freed if there are
106 no other references to it. */
107
108void
4ccad563 109runtime_trampoline_scan (void (*addroot) (byte *, uintptr))
d4dc840d
ILT
110{
111 if (trampoline_page != NULL)
4ccad563 112 addroot ((byte *) &trampoline_page, sizeof trampoline_page);
7a938933 113}