From 05a7d566782733230696a51ab8575261b8f9f162 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 3 Sep 2013 21:52:37 +0000 Subject: compiler, runtime: Use runtime functions to pass closure value. This changes the compiler and runtime to not pass a closure value as the last argument, but to instead pass it via __go_set_closure and retrieve it via __go_get_closure. This eliminates the need for function descriptor wrapper functions. It will make it possible to retrieve the closure value in a reflect.MakeFunc function. From-SVN: r202233 --- libgo/go/reflect/value.go | 7 ------- libgo/runtime/go-reflect-call.c | 17 +++++------------ libgo/runtime/mgc0.c | 7 +++---- libgo/runtime/proc.c | 20 ++++++++++++++++++++ libgo/runtime/runtime.h | 4 ++++ libgo/runtime/time.goc | 8 ++++---- 6 files changed, 36 insertions(+), 27 deletions(-) (limited to 'libgo') diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index 6bf66c8..45a0858 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -434,9 +434,6 @@ func (v Value) call(op string, in []Value) []Value { nin++ } firstPointer := len(in) > 0 && Kind(t.In(0).(*rtype).kind) != Ptr && v.flag&flagMethod == 0 && isMethod(v.typ) - if v.flag&flagMethod == 0 && !firstPointer { - nin++ - } params := make([]unsafe.Pointer, nin) off := 0 if v.flag&flagMethod != 0 { @@ -464,10 +461,6 @@ func (v Value) call(op string, in []Value) []Value { } off++ } - if v.flag&flagMethod == 0 && !firstPointer { - // Closure argument. - params[off] = unsafe.Pointer(&fn) - } ret := make([]Value, nout) results := make([]unsafe.Pointer, nout) diff --git a/libgo/runtime/go-reflect-call.c b/libgo/runtime/go-reflect-call.c index 83b9eba..5cf3707 100644 --- a/libgo/runtime/go-reflect-call.c +++ b/libgo/runtime/go-reflect-call.c @@ -302,9 +302,7 @@ 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) - + (!is_interface && !is_method ? 1 : 0)); + num_args = num_params + (is_interface ? 1 : 0); args = (ffi_type **) __go_alloc (num_args * sizeof (ffi_type *)); i = 0; off = 0; @@ -321,12 +319,6 @@ 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); @@ -511,9 +503,8 @@ go_set_results (const struct __go_func_type *func, unsigned char *call_result, 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. */ + function indirectly, and we must pass a closure pointer via + __go_set_closure. The pointer to pass is simply FUNC_VAL. */ void reflect_call (const struct __go_func_type *func_type, FuncVal *func_val, @@ -528,6 +519,8 @@ reflect_call (const struct __go_func_type *func_type, FuncVal *func_val, call_result = (unsigned char *) malloc (go_results_size (func_type)); + if (!is_interface && !is_method) + __go_set_closure (func_val); ffi_call (&cif, func_val->fn, call_result, params); /* Some day we may need to free result values if RESULTS is diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c index 36afd2b..c3b3211 100644 --- a/libgo/runtime/mgc0.c +++ b/libgo/runtime/mgc0.c @@ -2263,12 +2263,11 @@ runfinq(void* dummy __attribute__ ((unused))) for(; fb; fb=next) { next = fb->next; for(i=0; i<(uint32)fb->cnt; i++) { - void *params[2]; + void *param; f = &fb->fin[i]; - params[0] = &f->arg; - params[1] = f; - reflect_call(f->ft, f->fn, 0, 0, params, nil); + param = &f->arg; + reflect_call(f->ft, f->fn, 0, 0, ¶m, nil); f->fn = nil; f->arg = nil; } diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c index d42ff33..0e77a3e 100644 --- a/libgo/runtime/proc.c +++ b/libgo/runtime/proc.c @@ -2832,3 +2832,23 @@ runtime_proc_scan(void (*addroot)(Obj)) { addroot((Obj){(byte*)&runtime_sched, sizeof runtime_sched, 0}); } + +// When a function calls a closure, it passes the closure value to +// __go_set_closure immediately before the function call. When a +// function uses a closure, it calls __go_get_closure immediately on +// function entry. This is a hack, but it will work on any system. +// It would be better to use the static chain register when there is +// one. It is also worth considering expanding these functions +// directly in the compiler. + +void +__go_set_closure(void* v) +{ + g->closure = v; +} + +void * +__go_get_closure(void) +{ + return g->closure; +} diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h index 78fd388..d2e7d4c 100644 --- a/libgo/runtime/runtime.h +++ b/libgo/runtime/runtime.h @@ -190,6 +190,7 @@ struct Location struct G { + void* closure; // Closure value. Defer* defer; Panic* panic; void* exception; // current exception being thrown @@ -759,3 +760,6 @@ extern void runtime_main(void*); int32 getproccount(void); #define PREFETCH(p) __builtin_prefetch(p) + +void __go_set_closure(void*); +void* __go_get_closure(void); diff --git a/libgo/runtime/time.goc b/libgo/runtime/time.goc index e06b75c..8d12fe0 100644 --- a/libgo/runtime/time.goc +++ b/libgo/runtime/time.goc @@ -46,10 +46,9 @@ static void siftdown(int32); // Ready the goroutine e.data. static void -ready(int64 now, Eface e, void *closure) +ready(int64 now, Eface e) { USED(now); - USED(closure); runtime_ready(e.__object); } @@ -166,7 +165,7 @@ timerproc(void* dummy __attribute__ ((unused))) { int64 delta, now; Timer *t; - void (*f)(int64, Eface, void *); + void (*f)(int64, Eface); Eface arg; for(;;) { @@ -197,7 +196,8 @@ timerproc(void* dummy __attribute__ ((unused))) runtime_unlock(&timers); if(raceenabled) runtime_raceacquire(t); - f(now, arg, &t->fv); + __go_set_closure(t->fv); + f(now, arg); runtime_lock(&timers); } if(delta < 0) { -- cgit v1.1