summaryrefslogtreecommitdiff
path: root/libgo/runtime
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2013-06-18 23:49:49 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2013-06-18 23:49:49 +0000
commit8381eda7ff1e5a2874d708573654e64a4efcfb4f (patch)
tree1a7d38cd8be5484451189338ed6f4b76d8521f31 /libgo/runtime
parent2851d736ebf1e8cceebb9106cab69d2c3fdc7624 (diff)
downloadgcc-8381eda7ff1e5a2874d708573654e64a4efcfb4f.tar.gz
compiler, runtime: Use function descriptors.
This changes the representation of a Go value of function type from being a pointer to function code (like a C function pointer) to being a pointer to a struct. The first field of the struct points to the function code. The remaining fields, if any, are the addresses of variables referenced in enclosing functions. For each call to a function, the address of the function descriptor is passed as the last argument. This lets us avoid generating trampolines, and removes the use of writable/executable sections of the heap. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@200181 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/runtime')
-rw-r--r--libgo/runtime/go-reflect-call.c33
-rw-r--r--libgo/runtime/malloc.h3
-rw-r--r--libgo/runtime/mfinal.c8
-rw-r--r--libgo/runtime/mgc0.c10
-rw-r--r--libgo/runtime/parfor.c2
-rw-r--r--libgo/runtime/runtime.h12
-rw-r--r--libgo/runtime/time.goc13
7 files changed, 55 insertions, 26 deletions
diff --git a/libgo/runtime/go-reflect-call.c b/libgo/runtime/go-reflect-call.c
index a66f92868f8..83b9eba0436 100644
--- a/libgo/runtime/go-reflect-call.c
+++ b/libgo/runtime/go-reflect-call.c
@@ -302,7 +302,9 @@ go_func_to_cif (const struct __go_func_type *func, _Bool is_interface,
in_types = ((const struct __go_type_descriptor **)
func->__in.__values);
- num_args = num_params + (is_interface ? 1 : 0);
+ num_args = (num_params
+ + (is_interface ? 1 : 0)
+ + (!is_interface && !is_method ? 1 : 0));
args = (ffi_type **) __go_alloc (num_args * sizeof (ffi_type *));
i = 0;
off = 0;
@@ -319,6 +321,12 @@ go_func_to_cif (const struct __go_func_type *func, _Bool is_interface,
for (; i < num_params; ++i)
args[i + off] = go_type_to_ffi (in_types[i]);
+ if (!is_interface && !is_method)
+ {
+ // There is a closure argument, a pointer.
+ args[i + off] = &ffi_type_pointer;
+ }
+
rettype = go_func_return_ffi (func);
status = ffi_prep_cif (cif, FFI_DEFAULT_ABI, num_args, rettype, args);
@@ -491,11 +499,24 @@ go_set_results (const struct __go_func_type *func, unsigned char *call_result,
}
/* Call a function. The type of the function is FUNC_TYPE, and the
- address is FUNC_ADDR. PARAMS is an array of parameter addresses.
- RESULTS is an array of result addresses. */
+ closure is FUNC_VAL. PARAMS is an array of parameter addresses.
+ RESULTS is an array of result addresses.
+
+ If IS_INTERFACE is true this is a call to an interface method and
+ the first argument is the receiver, which is always a pointer.
+ This argument, the receiver, is not described in FUNC_TYPE.
+
+ If IS_METHOD is true this is a call to a method expression. The
+ first argument is the receiver. It is described in FUNC_TYPE, but
+ regardless of FUNC_TYPE, it is passed as a pointer.
+
+ If neither IS_INTERFACE nor IS_METHOD is true then we are calling a
+ function indirectly, and the caller is responsible for passing a
+ trailing closure argument, a pointer, which is not described in
+ FUNC_TYPE. */
void
-reflect_call (const struct __go_func_type *func_type, const void *func_addr,
+reflect_call (const struct __go_func_type *func_type, FuncVal *func_val,
_Bool is_interface, _Bool is_method, void **params,
void **results)
{
@@ -507,7 +528,7 @@ reflect_call (const struct __go_func_type *func_type, const void *func_addr,
call_result = (unsigned char *) malloc (go_results_size (func_type));
- ffi_call (&cif, func_addr, call_result, params);
+ ffi_call (&cif, func_val->fn, call_result, params);
/* Some day we may need to free result values if RESULTS is
NULL. */
@@ -521,7 +542,7 @@ reflect_call (const struct __go_func_type *func_type, const void *func_addr,
void
reflect_call (const struct __go_func_type *func_type __attribute__ ((unused)),
- const void *func_addr __attribute__ ((unused)),
+ FuncVal *func_val __attribute__ ((unused)),
_Bool is_interface __attribute__ ((unused)),
_Bool is_method __attribute__ ((unused)),
void **params __attribute__ ((unused)),
diff --git a/libgo/runtime/malloc.h b/libgo/runtime/malloc.h
index a8207742031..7ebb762450e 100644
--- a/libgo/runtime/malloc.h
+++ b/libgo/runtime/malloc.h
@@ -485,7 +485,7 @@ void runtime_helpgc(int32 nproc);
void runtime_gchelper(void);
struct __go_func_type;
-bool runtime_getfinalizer(void *p, bool del, void (**fn)(void*), const struct __go_func_type **ft);
+bool runtime_getfinalizer(void *p, bool del, FuncVal **fn, const struct __go_func_type **ft);
void runtime_walkfintab(void (*fn)(void*), void (*scan)(Obj));
enum
@@ -505,4 +505,3 @@ void runtime_gc_itab_ptr(Eface*);
void runtime_memorydump(void);
void runtime_time_scan(void (*)(Obj));
-void runtime_trampoline_scan(void (*)(Obj));
diff --git a/libgo/runtime/mfinal.c b/libgo/runtime/mfinal.c
index 7c906daf347..407092bf392 100644
--- a/libgo/runtime/mfinal.c
+++ b/libgo/runtime/mfinal.c
@@ -11,7 +11,7 @@ enum { debug = 0 };
typedef struct Fin Fin;
struct Fin
{
- void (*fn)(void*);
+ FuncVal *fn;
const struct __go_func_type *ft;
};
@@ -42,7 +42,7 @@ static struct {
} fintab[TABSZ];
static void
-addfintab(Fintab *t, void *k, void (*fn)(void*), const struct __go_func_type *ft)
+addfintab(Fintab *t, void *k, FuncVal *fn, const struct __go_func_type *ft)
{
int32 i, j;
@@ -137,7 +137,7 @@ resizefintab(Fintab *tab)
}
bool
-runtime_addfinalizer(void *p, void (*f)(void*), const struct __go_func_type *ft)
+runtime_addfinalizer(void *p, FuncVal *f, const struct __go_func_type *ft)
{
Fintab *tab;
byte *base;
@@ -175,7 +175,7 @@ runtime_addfinalizer(void *p, void (*f)(void*), const struct __go_func_type *ft)
// get finalizer; if del, delete finalizer.
// caller is responsible for updating RefHasFinalizer (special) bit.
bool
-runtime_getfinalizer(void *p, bool del, void (**fn)(void*), const struct __go_func_type **ft)
+runtime_getfinalizer(void *p, bool del, FuncVal **fn, const struct __go_func_type **ft)
{
Fintab *tab;
bool res;
diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c
index ffbe2cefb2d..88283ccab2b 100644
--- a/libgo/runtime/mgc0.c
+++ b/libgo/runtime/mgc0.c
@@ -120,7 +120,7 @@ struct Workbuf
typedef struct Finalizer Finalizer;
struct Finalizer
{
- void (*fn)(void*);
+ FuncVal *fn;
void *arg;
const struct __go_func_type *ft;
};
@@ -1130,7 +1130,6 @@ addroots(void)
addroot((Obj){(byte*)&runtime_allm, sizeof runtime_allm, 0});
runtime_MProf_Mark(addroot);
runtime_time_scan(addroot);
- runtime_trampoline_scan(addroot);
// MSpan.types
allspans = runtime_mheap.allspans;
@@ -1182,7 +1181,7 @@ addroots(void)
static bool
handlespecial(byte *p, uintptr size)
{
- void (*fn)(void*);
+ FuncVal *fn;
const struct __go_func_type *ft;
FinBlock *block;
Finalizer *f;
@@ -1731,11 +1730,12 @@ runfinq(void* dummy __attribute__ ((unused)))
for(; fb; fb=next) {
next = fb->next;
for(i=0; i<(uint32)fb->cnt; i++) {
- void *params[1];
+ void *params[2];
f = &fb->fin[i];
params[0] = &f->arg;
- reflect_call(f->ft, (void*)f->fn, 0, 0, params, nil);
+ params[1] = f;
+ reflect_call(f->ft, f->fn, 0, 0, params, nil);
f->fn = nil;
f->arg = nil;
}
diff --git a/libgo/runtime/parfor.c b/libgo/runtime/parfor.c
index 591b968c039..65ca586eadb 100644
--- a/libgo/runtime/parfor.c
+++ b/libgo/runtime/parfor.c
@@ -83,7 +83,7 @@ void runtime_parforsetup2(ParFor *, uint32, uint32, void *, bool, void *)
void
runtime_parforsetup2(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void *body)
{
- runtime_parforsetup(desc, nthr, n, ctx, wait, (void(*)(ParFor*, uint32))body);
+ runtime_parforsetup(desc, nthr, n, ctx, wait, *(void(**)(ParFor*, uint32))body);
}
void
diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h
index 9392df162bf..959220d734c 100644
--- a/libgo/runtime/runtime.h
+++ b/libgo/runtime/runtime.h
@@ -57,6 +57,7 @@ typedef struct G G;
typedef union Lock Lock;
typedef struct M M;
typedef union Note Note;
+typedef struct FuncVal FuncVal;
typedef struct SigTab SigTab;
typedef struct MCache MCache;
typedef struct FixAlloc FixAlloc;
@@ -147,6 +148,11 @@ struct String
const byte* str;
intgo len;
};
+struct FuncVal
+{
+ void (*fn)(void);
+ // variable-size, fn-specific data here
+};
struct GCStats
{
// the struct must consist of only uint64's,
@@ -313,7 +319,7 @@ struct Timer
// a well-behaved function and not block.
int64 when;
int64 period;
- void (*f)(int64, Eface);
+ FuncVal *fv;
Eface arg;
};
@@ -540,7 +546,7 @@ void runtime_printslice(Slice);
void runtime_printcomplex(__complex double);
struct __go_func_type;
-void reflect_call(const struct __go_func_type *, const void *, _Bool, _Bool,
+void reflect_call(const struct __go_func_type *, FuncVal *, _Bool, _Bool,
void **, void **)
__asm__ (GOSYM_PREFIX "reflect.call");
@@ -570,7 +576,7 @@ void free(void *v);
#define PREFETCH(p) __builtin_prefetch(p)
struct __go_func_type;
-bool runtime_addfinalizer(void*, void(*fn)(void*), const struct __go_func_type *);
+bool runtime_addfinalizer(void*, FuncVal *fn, const struct __go_func_type *);
#define runtime_getcallersp(p) __builtin_frame_address(1)
int32 runtime_mcount(void);
int32 runtime_gcount(void);
diff --git a/libgo/runtime/time.goc b/libgo/runtime/time.goc
index 9a5cbdfed3b..e9f087ac884 100644
--- a/libgo/runtime/time.goc
+++ b/libgo/runtime/time.goc
@@ -49,13 +49,16 @@ static void siftdown(int32);
// Ready the goroutine e.data.
static void
-ready(int64 now, Eface e)
+ready(int64 now, Eface e, void *closure)
{
USED(now);
+ USED(closure);
runtime_ready(e.__object);
}
+static FuncVal readyv = {(void(*)(void))ready};
+
// Put the current goroutine to sleep for ns nanoseconds.
void
runtime_tsleep(int64 ns, const char *reason)
@@ -70,7 +73,7 @@ runtime_tsleep(int64 ns, const char *reason)
t.when = runtime_nanotime() + ns;
t.period = 0;
- t.f = ready;
+ t.fv = &readyv;
t.arg.__object = g;
runtime_lock(&timers);
addtimer(&t);
@@ -158,7 +161,7 @@ timerproc(void* dummy __attribute__ ((unused)))
{
int64 delta, now;
Timer *t;
- void (*f)(int64, Eface);
+ void (*f)(int64, Eface, void *);
Eface arg;
for(;;) {
@@ -184,12 +187,12 @@ timerproc(void* dummy __attribute__ ((unused)))
siftdown(0);
t->i = -1; // mark as removed
}
- f = t->f;
+ f = (void*)t->fv->fn;
arg = t->arg;
runtime_unlock(&timers);
if(raceenabled)
runtime_raceacquire(t);
- f(now, arg);
+ f(now, arg, &t->fv);
runtime_lock(&timers);
}
if(delta < 0) {