From 38bf819a5f995ae4621496df2324d68b9e24900f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 16 Jan 2015 14:58:53 -0800 Subject: [PATCH] compiler, reflect, runtime: Use static chain for closures. Change from using __go_set_closure to passing the closure value in the static chain field. Uses new backend support for setting the closure chain in a call from C via __builtin_call_with_static_chain. Uses new support in libffi for Go closures. The old architecture specific support for reflect.MakeFunc is removed, replaced by the libffi support. All work done by Richard Henderson. * go-gcc.cc (Gcc_backend::call_expression): Add chain_expr argument. (Gcc_backend::static_chain_variable): New method. From-SVN: r219776 --- gcc/go/ChangeLog | 5 + gcc/go/go-gcc.cc | 44 ++- gcc/go/gofrontend/backend.h | 7 +- gcc/go/gofrontend/expressions.cc | 21 +- gcc/go/gofrontend/gogo.cc | 29 +- gcc/go/gofrontend/gogo.h | 14 + gcc/go/gofrontend/runtime.def | 6 - libgo/Makefile.am | 38 -- libgo/Makefile.in | 44 +-- libgo/go/reflect/makefunc.go | 61 +--- libgo/go/reflect/makefunc_386.S | 230 ------------- libgo/go/reflect/makefunc_amd64.S | 177 ---------- libgo/go/reflect/makefunc_dummy.c | 15 - libgo/go/reflect/makefunc_ffi.go | 67 ++-- libgo/go/reflect/makefunc_ffi_c.c | 68 +--- libgo/go/reflect/makefunc_s390.c | 86 ----- libgo/go/reflect/makefuncgo_386.go | 139 -------- libgo/go/reflect/makefuncgo_amd64.go | 496 --------------------------- libgo/go/reflect/makefuncgo_s390.go | 454 ------------------------ libgo/go/reflect/makefuncgo_s390x.go | 436 ----------------------- libgo/go/reflect/value.go | 24 -- libgo/runtime/go-ffi.c | 39 ++- libgo/runtime/go-reflect-call.c | 15 +- libgo/runtime/malloc.goc | 8 - libgo/runtime/mgc0.c | 4 +- libgo/runtime/proc.c | 20 -- libgo/runtime/runtime.h | 4 - libgo/runtime/time.goc | 3 +- 28 files changed, 174 insertions(+), 2380 deletions(-) delete mode 100644 libgo/go/reflect/makefunc_386.S delete mode 100644 libgo/go/reflect/makefunc_amd64.S delete mode 100644 libgo/go/reflect/makefunc_dummy.c delete mode 100644 libgo/go/reflect/makefunc_s390.c delete mode 100644 libgo/go/reflect/makefuncgo_386.go delete mode 100644 libgo/go/reflect/makefuncgo_amd64.go delete mode 100644 libgo/go/reflect/makefuncgo_s390.go delete mode 100644 libgo/go/reflect/makefuncgo_s390x.go diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 907a011ab79..a2d236c1833 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,8 @@ +2015-01-16 Richard Henderson + + * go-gcc.cc (Gcc_backend::call_expression): Add chain_expr argument. + (Gcc_backend::static_chain_variable): New method. + 2015-01-09 Ian Lance Taylor * config-lang.in (lang_dirs): Define. diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index d8b80b6d208..1ce1ff2f79b 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -322,7 +322,7 @@ class Gcc_backend : public Backend Bexpression* call_expression(Bexpression* fn, const std::vector& args, - Location); + Bexpression* static_chain, Location); // Statements. @@ -402,6 +402,9 @@ class Gcc_backend : public Backend parameter_variable(Bfunction*, const std::string&, Btype*, bool, Location); + Bvariable* + static_chain_variable(Bfunction*, const std::string&, Btype*, Location); + Bvariable* temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression*, bool, Location, Bstatement**); @@ -1808,7 +1811,7 @@ Gcc_backend::array_index_expression(Bexpression* array, Bexpression* index, Bexpression* Gcc_backend::call_expression(Bexpression* fn_expr, const std::vector& fn_args, - Location location) + Bexpression* chain_expr, Location location) { tree fn = fn_expr->get_tree(); if (fn == error_mark_node || TREE_TYPE(fn) == error_mark_node) @@ -1868,6 +1871,9 @@ Gcc_backend::call_expression(Bexpression* fn_expr, excess_type != NULL_TREE ? excess_type : rettype, fn, nargs, args); + if (chain_expr) + CALL_EXPR_STATIC_CHAIN (ret) = chain_expr->get_tree(); + if (excess_type != NULL_TREE) { // Calling convert here can undo our excess precision change. @@ -2489,6 +2495,40 @@ Gcc_backend::parameter_variable(Bfunction* function, const std::string& name, return new Bvariable(decl); } +// Make a static chain variable. + +Bvariable* +Gcc_backend::static_chain_variable(Bfunction* function, const std::string& name, + Btype* btype, Location location) +{ + tree type_tree = btype->get_tree(); + if (type_tree == error_mark_node) + return this->error_variable(); + tree decl = build_decl(location.gcc_location(), PARM_DECL, + get_identifier_from_string(name), type_tree); + tree fndecl = function->get_tree(); + DECL_CONTEXT(decl) = fndecl; + DECL_ARG_TYPE(decl) = type_tree; + TREE_USED(decl) = 1; + DECL_ARTIFICIAL(decl) = 1; + DECL_IGNORED_P(decl) = 1; + TREE_READONLY(decl) = 1; + + struct function *f = DECL_STRUCT_FUNCTION(fndecl); + if (f == NULL) + { + push_struct_function(fndecl); + pop_cfun(); + f = DECL_STRUCT_FUNCTION(fndecl); + } + gcc_assert(f->static_chain_decl == NULL); + f->static_chain_decl = decl; + DECL_STATIC_CHAIN(fndecl) = 1; + + go_preserve_from_gc(decl); + return new Bvariable(decl); +} + // Make a temporary variable. Bvariable* diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h index 46b2a6d6906..31ed8dff0a6 100644 --- a/gcc/go/gofrontend/backend.h +++ b/gcc/go/gofrontend/backend.h @@ -375,7 +375,7 @@ class Backend // Create an expression for a call to FN with ARGS. virtual Bexpression* call_expression(Bexpression* fn, const std::vector& args, - Location) = 0; + Bexpression* static_chain, Location) = 0; // Statements. @@ -529,6 +529,11 @@ class Backend Btype* type, bool is_address_taken, Location location) = 0; + // Create a static chain parameter. This is the closure parameter. + virtual Bvariable* + static_chain_variable(Bfunction* function, const std::string& name, + Btype* type, Location location) = 0; + // Create a temporary variable. A temporary variable has no name, // just a type. We pass in FUNCTION and BLOCK in case they are // needed. If INIT is not NULL, the variable should be initialized diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 564c5b72ad7..ee8af849f50 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -6321,6 +6321,7 @@ Bound_method_expression::create_thunk(Gogo* gogo, const Method* method, Variable* cvar = new Variable(closure_type, NULL, false, false, false, loc); cvar->set_is_used(); + cvar->set_is_closure(); Named_object* cp = Named_object::make_variable("$closure", NULL, cvar); new_no->func_value()->set_closure_var(cp); @@ -9328,19 +9329,11 @@ Call_expression::do_get_backend(Translate_context* context) fn_args[0] = first_arg->get_backend(context); } - if (!has_closure_arg) - go_assert(closure == NULL); + Bexpression* bclosure = NULL; + if (has_closure_arg) + bclosure = closure->get_backend(context); else - { - // Pass the closure argument by calling the function function - // __go_set_closure. In the order_evaluations pass we have - // ensured that if any parameters contain call expressions, they - // will have been moved out to temporary variables. - go_assert(closure != NULL); - Expression* set_closure = - Runtime::make_call(Runtime::SET_CLOSURE, location, 1, closure); - fn = Expression::make_compound(set_closure, fn, location); - } + go_assert(closure == NULL); Bexpression* bfn = fn->get_backend(context); @@ -9356,7 +9349,8 @@ Call_expression::do_get_backend(Translate_context* context) bfn = gogo->backend()->convert_expression(bft, bfn, location); } - Bexpression* call = gogo->backend()->call_expression(bfn, fn_args, location); + Bexpression* call = gogo->backend()->call_expression(bfn, fn_args, + bclosure, location); if (this->results_ != NULL) { @@ -11132,6 +11126,7 @@ Interface_field_reference_expression::create_thunk(Gogo* gogo, Variable* cvar = new Variable(closure_type, NULL, false, false, false, loc); cvar->set_is_used(); + cvar->set_is_closure(); Named_object* cp = Named_object::make_variable("$closure", NULL, cvar); new_no->func_value()->set_closure_var(cp); diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 49be6af61f2..7bc54fcd658 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -698,7 +698,8 @@ Gogo::init_imports(std::vector& init_stmts) Bexpression* pfunc_code = this->backend()->function_code_expression(pfunc, unknown_loc); Bexpression* pfunc_call = - this->backend()->call_expression(pfunc_code, empty_args, unknown_loc); + this->backend()->call_expression(pfunc_code, empty_args, + NULL, unknown_loc); init_stmts.push_back(this->backend()->expression_statement(pfunc_call)); } } @@ -1413,7 +1414,7 @@ Gogo::write_globals() this->backend()->function_code_expression(initfn, func_loc); Bexpression* call = this->backend()->call_expression(func_code, empty_args, - func_loc); + NULL, func_loc); init_stmts.push_back(this->backend()->expression_statement(call)); } @@ -3915,6 +3916,7 @@ Build_recover_thunks::function(Named_object* orig_no) Variable* orig_closure_var = orig_closure_no->var_value(); Variable* new_var = new Variable(orig_closure_var->type(), NULL, false, false, false, location); + new_var->set_is_closure(); snprintf(buf, sizeof buf, "closure.%u", count); ++count; Named_object* new_closure_no = Named_object::make_variable(buf, NULL, @@ -4518,6 +4520,7 @@ Function::closure_var() Variable* var = new Variable(Type::make_pointer_type(struct_type), NULL, false, false, false, loc); var->set_is_used(); + var->set_is_closure(); this->closure_var_ = Named_object::make_variable("$closure", NULL, var); // Note that the new variable is not in any binding contour. } @@ -5188,18 +5191,12 @@ Function::build(Gogo* gogo, Named_object* named_function) return; } - // If we need a closure variable, fetch it by calling a runtime - // function. The caller will have called __go_set_closure before - // the function call. + // If we need a closure variable, make sure to create it. + // It gets installed in the function as a side effect of creation. if (this->closure_var_ != NULL) { - Bvariable* closure_bvar = - this->closure_var_->get_backend_variable(gogo, named_function); - vars.push_back(closure_bvar); - - Expression* closure = - Runtime::make_call(Runtime::GET_CLOSURE, this->location_, 0); - var_inits.push_back(closure->get_backend(&context)); + go_assert(this->closure_var_->var_value()->is_closure()); + this->closure_var_->get_backend_variable(gogo, named_function); } if (this->block_ != NULL) @@ -5733,7 +5730,8 @@ Variable::Variable(Type* type, Expression* init, bool is_global, Location location) : type_(type), init_(init), preinit_(NULL), location_(location), backend_(NULL), is_global_(is_global), is_parameter_(is_parameter), - is_receiver_(is_receiver), is_varargs_parameter_(false), is_used_(false), + is_closure_(false), is_receiver_(is_receiver), + is_varargs_parameter_(false), is_used_(false), is_address_taken_(false), is_non_escaping_address_taken_(false), seen_(false), init_is_lowered_(false), init_is_flattened_(false), type_from_init_tuple_(false), type_from_range_index_(false), @@ -6287,7 +6285,10 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function, Bfunction* bfunction = function->func_value()->get_decl(); bool is_address_taken = (this->is_non_escaping_address_taken_ && !this->is_in_heap()); - if (is_parameter) + if (this->is_closure()) + bvar = backend->static_chain_variable(bfunction, n, btype, + this->location_); + else if (is_parameter) bvar = backend->parameter_variable(bfunction, n, btype, is_address_taken, this->location_); diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index a75ae4b9542..8a1663703aa 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -1364,6 +1364,18 @@ class Variable is_parameter() const { return this->is_parameter_; } + // Return whether this is a closure (static chain) parameter. + bool + is_closure() const + { return this->is_closure_; } + + // Change this parameter to be a closure. + void + set_is_closure() + { + this->is_closure_ = true; + } + // Return whether this is the receiver parameter of a method. bool is_receiver() const @@ -1585,6 +1597,8 @@ class Variable bool is_global_ : 1; // Whether this is a function parameter. bool is_parameter_ : 1; + // Whether this is a closure parameter. + bool is_closure_ : 1; // Whether this is the receiver parameter of a method. bool is_receiver_ : 1; // Whether this is the varargs parameter of a function. diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def index bec1cfc09ea..43025dd7b61 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -230,12 +230,6 @@ DEF_GO_RUNTIME(NEW_NOPOINTERS, "__go_new_nopointers", P2(TYPE, UINTPTR), R1(POIN // Start a new goroutine. DEF_GO_RUNTIME(GO, "__go_go", P2(FUNC_PTR, POINTER), R0()) -// Get the function closure. -DEF_GO_RUNTIME(GET_CLOSURE, "__go_get_closure", P0(), R1(POINTER)) - -// Set the function closure. -DEF_GO_RUNTIME(SET_CLOSURE, "__go_set_closure", P1(POINTER), R0()) - // Defer a function. DEF_GO_RUNTIME(DEFER, "__go_defer", P3(BOOLPTR, FUNC_PTR, POINTER), R0()) diff --git a/libgo/Makefile.am b/libgo/Makefile.am index 419598183ed..727662d5f1d 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -938,44 +938,10 @@ go_path_files = \ go/path/match.go \ go/path/path.go -if LIBGO_IS_X86_64 -go_reflect_makefunc_file = \ - go/reflect/makefuncgo_amd64.go -go_reflect_makefunc_s_file = \ - go/reflect/makefunc_amd64.S -else -if LIBGO_IS_386 -go_reflect_makefunc_file = \ - go/reflect/makefuncgo_386.go -go_reflect_makefunc_s_file = \ - go/reflect/makefunc_386.S -else -if LIBGO_IS_S390 -go_reflect_makefunc_file = \ - go/reflect/makefuncgo_s390.go -go_reflect_makefunc_s_file = \ - go/reflect/makefunc_s390.c -else -if LIBGO_IS_S390X -go_reflect_makefunc_file = \ - go/reflect/makefuncgo_s390x.go \ - go/reflect/makefuncgo_s390.go -go_reflect_makefunc_s_file = \ - go/reflect/makefunc_s390.c -else -go_reflect_makefunc_file = -go_reflect_makefunc_s_file = \ - go/reflect/makefunc_dummy.c -endif -endif -endif -endif - go_reflect_files = \ go/reflect/deepequal.go \ go/reflect/makefunc.go \ go/reflect/makefunc_ffi.go \ - $(go_reflect_makefunc_file) \ go/reflect/type.go \ go/reflect/value.go go_reflect_makefunc_c_file = \ @@ -1897,7 +1863,6 @@ libgo_go_objs = \ os.lo \ path.lo \ reflect-go.lo \ - reflect/makefunc.lo \ reflect/makefunc_ffi_c.lo \ regexp.lo \ runtime-go.lo \ @@ -2316,9 +2281,6 @@ reflect-go.lo: $(go_reflect_files) $(BUILDPACKAGE) reflect/check: $(CHECK_DEPS) @$(CHECK) -reflect/makefunc.lo: $(go_reflect_makefunc_s_file) - @$(MKDIR_P) reflect - $(LTCOMPILE) -c -o $@ $< reflect/makefunc_ffi_c.lo: $(go_reflect_makefunc_c_file) @$(MKDIR_P) reflect $(LTCOMPILE) -c -o $@ $< diff --git a/libgo/Makefile.in b/libgo/Makefile.in index af8566f6837..7c8fc320d93 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -141,11 +141,11 @@ am__DEPENDENCIES_1 = am__DEPENDENCIES_2 = bufio.lo bytes.lo bytes/index.lo crypto.lo \ encoding.lo errors.lo expvar.lo flag.lo fmt.lo hash.lo html.lo \ image.lo io.lo log.lo math.lo mime.lo net.lo os.lo path.lo \ - reflect-go.lo reflect/makefunc.lo reflect/makefunc_ffi_c.lo \ - regexp.lo runtime-go.lo sort.lo strconv.lo strings.lo \ - strings/index.lo sync.lo syscall.lo syscall/errno.lo \ - syscall/signame.lo syscall/wait.lo testing.lo time-go.lo \ - unicode.lo archive/tar.lo archive/zip.lo compress/bzip2.lo \ + reflect-go.lo reflect/makefunc_ffi_c.lo regexp.lo \ + runtime-go.lo sort.lo strconv.lo strings.lo strings/index.lo \ + sync.lo syscall.lo syscall/errno.lo syscall/signame.lo \ + syscall/wait.lo testing.lo time-go.lo unicode.lo \ + archive/tar.lo archive/zip.lo compress/bzip2.lo \ compress/flate.lo compress/gzip.lo compress/lzw.lo \ compress/zlib.lo container/heap.lo container/list.lo \ container/ring.lo crypto/aes.lo crypto/cipher.lo crypto/des.lo \ @@ -1125,40 +1125,10 @@ go_path_files = \ go/path/match.go \ go/path/path.go -@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_FALSE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file = -@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_TRUE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file = \ -@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_TRUE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@ go/reflect/makefuncgo_s390x.go \ -@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_TRUE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@ go/reflect/makefuncgo_s390.go - -@LIBGO_IS_386_FALSE@@LIBGO_IS_S390_TRUE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file = \ -@LIBGO_IS_386_FALSE@@LIBGO_IS_S390_TRUE@@LIBGO_IS_X86_64_FALSE@ go/reflect/makefuncgo_s390.go - -@LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file = \ -@LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@ go/reflect/makefuncgo_386.go - -@LIBGO_IS_X86_64_TRUE@go_reflect_makefunc_file = \ -@LIBGO_IS_X86_64_TRUE@ go/reflect/makefuncgo_amd64.go - -@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_FALSE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \ -@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_FALSE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@ go/reflect/makefunc_dummy.c - -@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_TRUE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \ -@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_TRUE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@ go/reflect/makefunc_s390.c - -@LIBGO_IS_386_FALSE@@LIBGO_IS_S390_TRUE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \ -@LIBGO_IS_386_FALSE@@LIBGO_IS_S390_TRUE@@LIBGO_IS_X86_64_FALSE@ go/reflect/makefunc_s390.c - -@LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \ -@LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@ go/reflect/makefunc_386.S - -@LIBGO_IS_X86_64_TRUE@go_reflect_makefunc_s_file = \ -@LIBGO_IS_X86_64_TRUE@ go/reflect/makefunc_amd64.S - go_reflect_files = \ go/reflect/deepequal.go \ go/reflect/makefunc.go \ go/reflect/makefunc_ffi.go \ - $(go_reflect_makefunc_file) \ go/reflect/type.go \ go/reflect/value.go @@ -1963,7 +1933,6 @@ libgo_go_objs = \ os.lo \ path.lo \ reflect-go.lo \ - reflect/makefunc.lo \ reflect/makefunc_ffi_c.lo \ regexp.lo \ runtime-go.lo \ @@ -4657,9 +4626,6 @@ reflect-go.lo: $(go_reflect_files) $(BUILDPACKAGE) reflect/check: $(CHECK_DEPS) @$(CHECK) -reflect/makefunc.lo: $(go_reflect_makefunc_s_file) - @$(MKDIR_P) reflect - $(LTCOMPILE) -c -o $@ $< reflect/makefunc_ffi_c.lo: $(go_reflect_makefunc_c_file) @$(MKDIR_P) reflect $(LTCOMPILE) -c -o $@ $< diff --git a/libgo/go/reflect/makefunc.go b/libgo/go/reflect/makefunc.go index 276be26108f..71aadfbceec 100644 --- a/libgo/go/reflect/makefunc.go +++ b/libgo/go/reflect/makefunc.go @@ -7,25 +7,24 @@ package reflect import ( - "runtime" "unsafe" ) // makeFuncImpl is the closure value implementing the function // returned by MakeFunc. type makeFuncImpl struct { - code uintptr - typ *funcType - fn func([]Value) []Value + // These first three words are layed out like ffi_go_closure. + code uintptr + ffi_cif unsafe.Pointer + ffi_fun func(unsafe.Pointer, unsafe.Pointer) + + typ *funcType + fn func([]Value) []Value // For gccgo we use the same entry point for functions and for // method values. method int rcvr Value - - // When using FFI, hold onto the FFI closure for the garbage - // collector. - ffi *ffiData } // MakeFunc returns a new function of the given Type @@ -58,37 +57,17 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value { t := typ.common() ftyp := (*funcType)(unsafe.Pointer(t)) - var code uintptr - var ffi *ffiData - switch runtime.GOARCH { - case "amd64", "386", "s390", "s390x": - // Indirect Go func value (dummy) to obtain actual - // code address. (A Go func value is a pointer to a C - // function pointer. http://golang.org/s/go11func.) - dummy := makeFuncStub - code = **(**uintptr)(unsafe.Pointer(&dummy)) - default: - code, ffi = makeFuncFFI(ftyp, fn) - } - impl := &makeFuncImpl{ - code: code, typ: ftyp, fn: fn, method: -1, - ffi: ffi, } + makeFuncFFI(ftyp, impl) + return Value{t, unsafe.Pointer(&impl), flag(Func) | flagIndir} } -// makeFuncStub is an assembly function that is the code half of -// the function returned from MakeFunc. It expects a *callReflectFunc -// as its context register, and its job is to invoke callReflect(ctxt, frame) -// where ctxt is the context register and frame is a pointer to the first -// word in the passed-in argument frame. -func makeFuncStub() - // makeMethodValue converts v from the rcvr+method index representation // of a method value to an actual method func value, which is // basically the receiver value with a special bit set, into a true @@ -123,16 +102,7 @@ func makeMethodValue(op string, v Value) Value { rcvr: rcvr, } - switch runtime.GOARCH { - case "amd64", "386": - // Indirect Go func value (dummy) to obtain actual - // code address. (A Go func value is a pointer to a C - // function pointer. http://golang.org/s/go11func.) - dummy := makeFuncStub - fv.code = **(**uintptr)(unsafe.Pointer(&dummy)) - default: - fv.code, fv.ffi = makeFuncFFI(ftyp, fv.call) - } + makeFuncFFI(ftyp, fv) return Value{ft, unsafe.Pointer(&fv), v.flag&flagRO | flag(Func) | flagIndir} } @@ -158,16 +128,7 @@ func makeValueMethod(v Value) Value { rcvr: v, } - switch runtime.GOARCH { - case "amd64", "386", "s390", "s390x": - // Indirect Go func value (dummy) to obtain actual - // code address. (A Go func value is a pointer to a C - // function pointer. http://golang.org/s/go11func.) - dummy := makeFuncStub - impl.code = **(**uintptr)(unsafe.Pointer(&dummy)) - default: - impl.code, impl.ffi = makeFuncFFI(ftyp, impl.call) - } + makeFuncFFI(ftyp, impl) return Value{t, unsafe.Pointer(&impl), v.flag&flagRO | flag(Func) | flagIndir} } diff --git a/libgo/go/reflect/makefunc_386.S b/libgo/go/reflect/makefunc_386.S deleted file mode 100644 index 0e2e7646532..00000000000 --- a/libgo/go/reflect/makefunc_386.S +++ /dev/null @@ -1,230 +0,0 @@ -/* Copyright 2013 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. - - MakeFunc 386 assembly code. */ - -#include "config.h" - - .globl reflect.makeFuncStub - -#ifdef __ELF__ - .type reflect.makeFuncStub,@function -#endif - -reflect.makeFuncStub: -.LFB1: - - /* Go does not provide any equivalent to the regparm function - attribute, so on Go we do not need to worry about passing - parameters in registers. We just pass a pointer to the - arguments on the stack. - - We do need to pick up the return values, though, so we pass - a pointer to a struct that looks like this. - struct { - esp uint32 // 0x0 - eax uint32 // 0x4 - st0 float64 // 0x8 - sr bool // 0x10 - sf bool // 0x11 - } - The sr field is set by the function to a non-zero value if - the function takes a struct hidden pointer that must be - popped off the stack. */ - - pushl %ebp -.LCFI0: - movl %esp, %ebp -.LCFI1: - pushl %ebx /* In case this is PIC. */ - subl $36, %esp /* Enough for args and to align stack. */ -.LCFI2: - -#ifdef __PIC__ - call __x86.get_pc_thunk.bx - addl $_GLOBAL_OFFSET_TABLE_, %ebx -#endif - - leal 8(%ebp), %eax /* Set esp field in struct. */ - movl %eax, -24(%ebp) - - /* For MakeFunc functions that call recover. */ - movl 4(%ebp), %eax - movl %eax, (%esp) -#ifdef __PIC__ - call __go_makefunc_can_recover@PLT -#else - call __go_makefunc_can_recover -#endif - -#ifdef __PIC__ - call __go_get_closure@PLT -#else - call __go_get_closure -#endif - - movl %eax, 4(%esp) - - leal -24(%ebp), %eax - movl %eax, (%esp) - -#ifdef __PIC__ - call reflect.MakeFuncStubGo@PLT -#else - call reflect.MakeFuncStubGo -#endif - - /* MakeFunc functions can no longer call recover. */ -#ifdef __PIC__ - call __go_makefunc_returning@PLT -#else - call __go_makefunc_returning -#endif - - /* Set return registers. */ - - movl -20(%ebp), %eax - - cmpb $0, -7(%ebp) - je 2f - - fldl -16(%ebp) - -#ifdef __SSE2__ - /* In case we are compiling with -msseregparm. This won't work - correctly if only SSE1 is supported, but that seems unlikely. */ - movsd -16(%ebp), %xmm0 -#endif - -2: - movb -8(%ebp), %dl - - addl $36, %esp - popl %ebx -.LCFI3: - popl %ebp -.LCFI4: - - testb %dl,%dl - jne 1f - ret -1: - ret $4 -.LFE1: -#ifdef __ELF__ - .size reflect.makeFuncStub, . - reflect.makeFuncStub -#endif - -#ifdef __PIC__ -#ifdef HAVE_AS_COMDAT_GAS - .section .text.__x86.get_pc_thunk.bx,"axG",@progbits,__x86.get_pc_thunk.bx,comdat -#else - /* Sun as needs a different syntax. */ - .section .text.__x86.get_pc_thunk.bx%__x86.get_pc_thunk.bx,"ax",@progbits - .group __x86.get_pc_thunk.bx,.text.__x86.get_pc_thunk.bx%__x86.get_pc_thunk.bx,#comdat -#endif - .globl __x86.get_pc_thunk.bx - .hidden __x86.get_pc_thunk.bx -#ifdef __ELF__ - .type __x86.get_pc_thunk.bx, @function -#endif -__x86.get_pc_thunk.bx: -.LFB2: - movl (%esp), %ebx - ret -.LFE2: -#ifdef __ELF__ - .size __x86.get_pc_thunk.bx, . - __x86.get_pc_thunk.bx -#endif -#endif - -#ifdef __ELF__ -#if defined __PIC__ -# if defined __sun__ && defined __svr4__ -/* 32-bit Solaris 2/x86 uses datarel encoding for PIC. GNU ld before 2.22 - doesn't correctly sort .eh_frame_hdr with mixed encodings, so match this. */ -# define FDE_ENCODING 0x30 /* datarel */ -# define FDE_ENCODE(X) X@GOTOFF -# else -# define FDE_ENCODING 0x1b /* pcrel sdata4 */ -# if defined HAVE_AS_X86_PCREL -# define FDE_ENCODE(X) X-. -# else -# define FDE_ENCODE(X) X@rel -# endif -# endif -#else -# define FDE_ENCODING 0 /* absolute */ -# define FDE_ENCODE(X) X -#endif - - .section .eh_frame,EH_FRAME_FLAGS,@progbits -.Lframe1: - .long .LECIE1-.LSCIE1 /* Length of Common Information Entry */ -.LSCIE1: - .long 0x0 /* CIE Identifier Tag */ - .byte 0x1 /* CIE Version */ - .ascii "zR\0" /* CIE Augmentation */ - .byte 0x1 /* .uleb128 0x1; CIE Code Alignment Factor */ - .byte 0x7c /* .sleb128 -4; CIE Data Alignment Factor */ - .byte 0x8 /* CIE RA Column */ - .byte 0x1 /* .uleb128 0x1; Augmentation size */ - .byte FDE_ENCODING - .byte 0xc /* DW_CFA_def_cfa */ - .byte 0x4 /* .uleb128 0x4 */ - .byte 0x4 /* .uleb128 0x4 */ - .byte 0x88 /* DW_CFA_offset, column 0x8 */ - .byte 0x1 /* .uleb128 0x1 */ - .align 4 -.LECIE1: -.LSFDE1: - .long .LEFDE1-.LASFDE1 /* FDE Length */ -.LASFDE1: - .long .LASFDE1-.Lframe1 /* FDE CIE offset */ - .long FDE_ENCODE(.LFB1) /* FDE initial location */ - .long .LFE1-.LFB1 /* FDE address range */ - .byte 0x0 /* .uleb128 0x0; Augmentation size */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI0-.LFB1 - .byte 0xe /* DW_CFA_def_cfa_offset */ - .byte 0x8 /* .uleb128 0x8 */ - .byte 0x85 /* DW_CFA_offset, column 0x5 */ - .byte 0x2 /* .uleb128 0x2 */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI1-.LCFI0 - .byte 0xd /* DW_CFA_def_cfa_register */ - .byte 0x5 /* .uleb128 0x5 */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI2-.LCFI1 - .byte 0x83 /* .DW_CFA_offset, column 0x3 */ - .byte 0x3 /* .uleb128 0x3 */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI3-.LCFI2 - .byte 0xc3 /* DW_CFA_restore, column 0x3 */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI4-.LCFI3 - .byte 0xc5 /* DW_CFA_restore, column 0x5 */ - .byte 0xc /* DW_CFA_def_cfa */ - .byte 0x4 /* .uleb128 0x4 */ - .byte 0x4 /* .uleb128 0x4 */ - .align 4 -.LEFDE1: -#ifdef __PIC__ -.LSFDE2: - .long .LEFDE2-.LASFDE2 /* FDE Length */ -.LASFDE2: - .long .LASFDE2-.Lframe1 /* FDE CIE offset */ - .long FDE_ENCODE(.LFB2) /* FDE initial location */ - .long .LFE2-.LFB2 /* FDE address range */ - .byte 0x0 /* .uleb128 0x0; Augmentation size */ - .align 4 -.LEFDE2: -#endif /* __PIC__ */ -#endif /* __ELF__ */ - -#if defined(__ELF__) && defined(__linux__) - .section .note.GNU-stack,"",@progbits - .section .note.GNU-split-stack,"",@progbits - .section .note.GNU-no-split-stack,"",@progbits -#endif diff --git a/libgo/go/reflect/makefunc_amd64.S b/libgo/go/reflect/makefunc_amd64.S deleted file mode 100644 index 88302eee1b2..00000000000 --- a/libgo/go/reflect/makefunc_amd64.S +++ /dev/null @@ -1,177 +0,0 @@ -# Copyright 2013 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# MakeFunc amd64 assembly code. - -#include "config.h" - - .global reflect.makeFuncStub - -#ifdef __ELF__ - .type reflect.makeFuncStub,@function -#endif - -reflect.makeFuncStub: -.LFB1: - - # Store all the parameter registers in a struct that looks - # like: - # struct { - # rax uint64 // 0x0 - # rdi uint64 // 0x8 - # rsi uint64 // 0x10 - # rdx uint64 // 0x18 - # rcx uint64 // 0x20 - # r8 uint64 // 0x28 - # r9 uint64 // 0x30 - # rsp uint64 // 0x38 Pointer to arguments on stack. - # xmm0 [2]uint64 // 0x40 - # xmm1 [2]uint64 // 0x50 - # xmm2 [2]uint64 // 0x60 - # xmm3 [2]uint64 // 0x70 - # xmm4 [2]uint64 // 0x80 - # xmm5 [2]uint64 // 0x90 - # xmm6 [2]uint64 // 0xa0 - # xmm7 [2]uint64 // 0xb0 - # }; - - pushq %rbp -.LCFI0: - movq %rsp, %rbp -.LCFI1: - - subq $0xc0, %rsp # Space for struct on stack. - - movq %rax, 0x0(%rsp) - movq %rdi, 0x8(%rsp) - movq %rsi, 0x10(%rsp) - movq %rdx, 0x18(%rsp) - movq %rcx, 0x20(%rsp) - movq %r8, 0x28(%rsp) - movq %r9, 0x30(%rsp) - leaq 16(%rbp), %rax - movq %rax, 0x38(%rsp) - movdqa %xmm0, 0x40(%rsp) - movdqa %xmm1, 0x50(%rsp) - movdqa %xmm2, 0x60(%rsp) - movdqa %xmm3, 0x70(%rsp) - movdqa %xmm4, 0x80(%rsp) - movdqa %xmm5, 0x90(%rsp) - movdqa %xmm6, 0xa0(%rsp) - movdqa %xmm7, 0xb0(%rsp) - - /* For MakeFunc functions that call recover. */ - movq 8(%rbp), %rdi -#ifdef __PIC__ - call __go_makefunc_can_recover@PLT -#else - call __go_makefunc_can_recover -#endif - - # Get function type. -#ifdef __PIC__ - call __go_get_closure@PLT -#else - call __go_get_closure -#endif - movq %rax, %rsi - - movq %rsp, %rdi - -#ifdef __PIC__ - call reflect.MakeFuncStubGo@PLT -#else - call reflect.MakeFuncStubGo -#endif - - /* MakeFunc functions can no longer call recover. */ -#ifdef __PIC__ - call __go_makefunc_returning@PLT -#else - call __go_makefunc_returning -#endif - - # The structure will be updated with any return values. Load - # all possible return registers before returning to the caller. - - movq 0x0(%rsp), %rax - movq 0x18(%rsp), %rdx - movq 0x8(%rsp), %rdi - movq 0x10(%rsp), %rsi - movdqa 0x40(%rsp), %xmm0 - movdqa 0x50(%rsp), %xmm1 - - # long double values are returned on the floating point stack, - # but we don't worry about that since Go doesn't have a long - # double type. - - leave -.LCFI2: - - ret -.LFE1: - -#ifdef __ELF__ - .size reflect.makeFuncStub, . - reflect.makeFuncStub -#endif - -#ifdef __ELF__ -#ifdef HAVE_AS_X86_64_UNWIND_SECTION_TYPE - .section .eh_frame,"a",@unwind -#else - .section .eh_frame,"a",@progbits -#endif -.Lframe1: - .long .LECIE1-.LSCIE1 /* Length of Common Information Entry */ -.LSCIE1: - .long 0x0 /* CIE Identifier Tag */ - .byte 0x1 /* CIE Version */ - .ascii "zR\0" /* CIE Augmentation */ - .uleb128 1 /* CIE Code Alignment Factor */ - .sleb128 -8 /* CIE Data Alignment Factor */ - .byte 0x10 /* CIE RA Column */ - .uleb128 1 /* Augmentation size */ - .byte 0x1b /* FDE Encoding (pcrel sdata4) */ - .byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */ - .uleb128 7 - .uleb128 8 - .byte 0x80+16 /* DW_CFA_offset, %rip offset 1*-8 */ - .uleb128 1 - .align 8 -.LECIE1: -.LSFDE1: - .long .LEFDE1-.LASFDE1 /* FDE Length */ -.LASFDE1: - .long .LASFDE1-.Lframe1 /* FDE CIE offset */ -#if HAVE_AS_X86_PCREL - .long .LFB1-. /* FDE initial location */ -#else - .long .LFB1@rel -#endif - .long .LFE1-.LFB1 /* FDE address range */ - .uleb128 0x0 /* Augmentation size */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI0-.LFB1 - .byte 0xe /* DW_CFA_def_cfa_offset */ - .uleb128 16 - .byte 0x86 /* DW_CFA_offset, column 0x6 */ - .uleb128 2 - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI1-.LCFI0 - .byte 0xd /* DW_CFA_def_cfa_register */ - .uleb128 6 - .byte 0x2 /* DW_CFA_advance_loc1 */ - .byte .LCFI2-.LCFI1 - .byte 0xc /* DW_CFA_def_cfa */ - .uleb128 7 - .uleb128 8 - .align 8 -.LEFDE1: -#endif /* __ELF__ */ - -#if defined(__ELF__) && defined(__linux__) - .section .note.GNU-stack,"",@progbits - .section .note.GNU-split-stack,"",@progbits - .section .note.GNU-no-split-stack,"",@progbits -#endif diff --git a/libgo/go/reflect/makefunc_dummy.c b/libgo/go/reflect/makefunc_dummy.c deleted file mode 100644 index 8eff0c1dfac..00000000000 --- a/libgo/go/reflect/makefunc_dummy.c +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "runtime.h" - -/* Dummy function for processors that implement MakeFunc using FFI - rather than having builtin support. */ - -void makeFuncStub (void) __asm__ ("reflect.makeFuncStub"); - -void makeFuncStub (void) -{ - runtime_throw ("impossible call to makeFuncStub"); -} diff --git a/libgo/go/reflect/makefunc_ffi.go b/libgo/go/reflect/makefunc_ffi.go index 40c1ea80fbe..6b61f231127 100644 --- a/libgo/go/reflect/makefunc_ffi.go +++ b/libgo/go/reflect/makefunc_ffi.go @@ -5,52 +5,27 @@ package reflect import ( - "runtime" "unsafe" ) -// The ffi function, written in C, allocates an FFI closure. It -// returns the code and data pointers. When the code pointer is -// called, it will call callback. CIF is an FFI data structure -// allocated as part of the closure, and is returned to ensure that -// the GC retains it. -func ffi(ftyp *funcType, callback func(unsafe.Pointer, unsafe.Pointer)) (code uintptr, data uintptr, cif unsafe.Pointer) - -// The ffiFree function, written in C, releases the FFI closure. -func ffiFree(uintptr) - -// An ffiData holds the information needed to preserve an FFI closure -// for the garbage collector. -type ffiData struct { - code uintptr - data uintptr - cif unsafe.Pointer - callback func(unsafe.Pointer, unsafe.Pointer) -} - -// The makeFuncFFI function uses libffi closures to implement -// reflect.MakeFunc. This is used for processors for which we don't -// have more efficient support. -func makeFuncFFI(ftyp *funcType, fn func(args []Value) (results []Value)) (uintptr, *ffiData) { - callback := func(params, results unsafe.Pointer) { - ffiCall(ftyp, fn, params, results) - } - - code, data, cif := ffi(ftyp, callback) - - c := &ffiData{code: code, data: data, cif: cif, callback: callback} - - runtime.SetFinalizer(c, - func(p *ffiData) { - ffiFree(p.data) - }) - - return code, c -} - -// ffiCall takes pointers to the parameters, calls the function, and -// stores the results back into memory. -func ffiCall(ftyp *funcType, fn func([]Value) []Value, params unsafe.Pointer, results unsafe.Pointer) { +// The makeFuncFFI function, written in C, fills in an FFI closure. +// It arranges for ffiCall to be invoked directly from FFI. +func makeFuncFFI(ftyp *funcType, impl *makeFuncImpl) + +// FFICallbackGo implements the Go side of the libffi callback. +// It is exported so that C code can call it. +// +// The call chain arriving here looks like +// some_go_caller +// ->some_ffi_internals +// ->ffi_callback (in C) +// ->FFICallbackGo +// +// The ffi_callback handles __go_makefunc_can_recover, and +// then passes off the data as received from ffi here. + +func FFICallbackGo(results unsafe.Pointer, params unsafe.Pointer, impl *makeFuncImpl) { + ftyp := impl.typ in := make([]Value, 0, len(ftyp.in)) ap := params for _, rt := range ftyp.in { @@ -61,18 +36,18 @@ func ffiCall(ftyp *funcType, fn func([]Value) []Value, params unsafe.Pointer, re ap = (unsafe.Pointer)(uintptr(ap) + ptrSize) } - out := fn(in) + out := impl.call(in) off := uintptr(0) for i, typ := range ftyp.out { v := out[i] if v.typ != typ { - panic("reflect: function created by MakeFunc using " + funcName(fn) + + panic("reflect: function created by MakeFunc using " + funcName(impl.fn) + " returned wrong type: have " + out[i].typ.String() + " for " + typ.String()) } if v.flag&flagRO != 0 { - panic("reflect: function created by MakeFunc using " + funcName(fn) + + panic("reflect: function created by MakeFunc using " + funcName(impl.fn) + " returned value obtained from unexported field") } diff --git a/libgo/go/reflect/makefunc_ffi_c.c b/libgo/go/reflect/makefunc_ffi_c.c index a3dfd4acd2c..727ae8180ad 100644 --- a/libgo/go/reflect/makefunc_ffi_c.c +++ b/libgo/go/reflect/makefunc_ffi_c.c @@ -10,7 +10,7 @@ #include "go-ffi.h" -#if FFI_CLOSURES +#if FFI_GO_CLOSURES #define USE_LIBFFI_CLOSURES #endif @@ -18,36 +18,28 @@ /* Declare C functions with the names used to call from Go. */ -struct ffi_ret { - void *code; - void *data; - void *cif; -}; - -struct ffi_ret ffi(const struct __go_func_type *ftyp, FuncVal *callback) - __asm__ (GOSYM_PREFIX "reflect.ffi"); - -void ffiFree(void *data) - __asm__ (GOSYM_PREFIX "reflect.ffiFree"); +void makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl) + __asm__ (GOSYM_PREFIX "reflect.makeFuncFFI"); #ifdef USE_LIBFFI_CLOSURES -/* The function that we pass to ffi_prep_closure_loc. This calls the - Go callback function (passed in user_data) with the pointer to the - arguments and the results area. */ +/* The function that we pass to ffi_prep_closure_loc. This calls the Go + function ffiCall with the pointer to the arguments, the results area, + and the closure structure. */ + +void FFICallbackGo(void *result, void **args, ffi_go_closure *closure) + __asm__ (GOSYM_PREFIX "reflect.FFICallbackGo"); static void ffi_callback (ffi_cif *, void *, void **, void *) __asm__ ("reflect.ffi_callback"); static void ffi_callback (ffi_cif* cif __attribute__ ((unused)), void *results, - void **args, void *user_data) + void **args, void *closure) { Location locs[8]; int n; int i; - FuncVal *fv; - void (*f) (void *, void *); /* This function is called from some series of FFI closure functions called by a Go function. We want to see whether the caller of @@ -69,10 +61,7 @@ ffi_callback (ffi_cif* cif __attribute__ ((unused)), void *results, if (i < n) __go_makefunc_ffi_can_recover (locs + i, n - i); - fv = (FuncVal *) user_data; - __go_set_closure (fv); - f = (void *) fv->fn; - f (args, results); + FFICallbackGo(results, args, closure); if (i < n) __go_makefunc_returning (); @@ -80,46 +69,21 @@ ffi_callback (ffi_cif* cif __attribute__ ((unused)), void *results, /* Allocate an FFI closure and arrange to call ffi_callback. */ -struct ffi_ret -ffi (const struct __go_func_type *ftyp, FuncVal *callback) +void +makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl) { ffi_cif *cif; - void *code; - void *data; - struct ffi_ret ret; cif = (ffi_cif *) __go_alloc (sizeof (ffi_cif)); __go_func_to_cif (ftyp, 0, 0, cif); - data = ffi_closure_alloc (sizeof (ffi_closure), &code); - if (data == NULL) - runtime_panicstring ("ffi_closure_alloc failed"); - if (ffi_prep_closure_loc (data, cif, ffi_callback, callback, code) - != FFI_OK) - runtime_panicstring ("ffi_prep_closure_loc failed"); - ret.code = code; - ret.data = data; - ret.cif = cif; - return ret; -} - -/* Free the FFI closure. */ -void -ffiFree (void *data) -{ - ffi_closure_free (data); + ffi_prep_go_closure(impl, cif, ffi_callback); } #else /* !defined(USE_LIBFFI_CLOSURES) */ -struct ffi_ret -ffi(const struct __go_func_type *ftyp, FuncVal *callback) -{ - runtime_panicstring ("libgo built without FFI does not support " - "reflect.MakeFunc"); -} - -void ffiFree(void *data) +void +makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl) { runtime_panicstring ("libgo built without FFI does not support " "reflect.MakeFunc"); diff --git a/libgo/go/reflect/makefunc_s390.c b/libgo/go/reflect/makefunc_s390.c deleted file mode 100644 index 78a960ca2f6..00000000000 --- a/libgo/go/reflect/makefunc_s390.c +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "runtime.h" -#include "go-panic.h" - -#ifdef __s390x__ -# define S390_GO_USE_64_BIT_ABI 1 -# define S390_GO_S390X_ARGS , double f4, double f6 -# define S390_GO_S390X_FIELDS double f4; double f6; - extern void S390xMakeFuncStubGo(void *, void *) - asm ("reflect.S390xMakeFuncStubGo"); -# define S390_GO_MakeFuncStubGo(r, c) S390xMakeFuncStubGo((r), (c)) -#else -# define S390_GO_USE_64_BIT_ABI 0 -# define S390_GO_S390X_ARGS -# define S390_GO_S390X_FIELDS - extern void S390MakeFuncStubGo(void *, void *) - asm ("reflect.S390MakeFuncStubGo"); -# define S390_GO_MakeFuncStubGo(r, c) S390MakeFuncStubGo((r), (c)) - /* Needed to make the unused 64 bit abi conditional code compile. */ -# define f4 f0 -# define f6 f2 -#endif - -/* Structure to store all registers used for parameter passing. */ -typedef struct -{ - long r2; - long r3; - long r4; - long r5; - long r6; - /* Pointer to non-register arguments on the stack. */ - long stack_args; - double f0; - double f2; - S390_GO_S390X_FIELDS -} s390Regs; - -void -makeFuncStub(long r2, long r3, long r4, long r5, long r6, - unsigned long stack_args, double f0, double f2 - S390_GO_S390X_ARGS) - asm ("reflect.makeFuncStub"); - -void -makeFuncStub(long r2, long r3, long r4, long r5, long r6, - unsigned long stack_args, double f0, double f2 - S390_GO_S390X_ARGS) -{ - s390Regs regs; - void *closure; - - /* Store the registers in a structure that is passed on to the Go stub - function. */ - regs.r2 = r2; - regs.r3 = r3; - regs.r4 = r4; - regs.r5 = r5; - regs.r6 = r6; - regs.stack_args = (long)&stack_args; - regs.f0 = f0; - regs.f2 = f2; - if (S390_GO_USE_64_BIT_ABI) { - regs.f4 = f4; - regs.f6 = f6; - } - /* For MakeFunc functions that call recover. */ - __go_makefunc_can_recover(__builtin_return_address(0)); - /* Call the Go stub function. */ - closure = __go_get_closure(); - S390_GO_MakeFuncStubGo(®s, closure); - /* MakeFunc functions can no longer call recover. */ - __go_makefunc_returning(); - /* Restore all possible return registers. */ - if (S390_GO_USE_64_BIT_ABI) { - asm volatile ("lg\t%%r2,0(%0)" : : "a" (®s.r2) : "r2" ); - asm volatile ("ld\t%%f0,0(%0)" : : "a" (®s.f0) : "f0" ); - } else { - asm volatile ("l\t%%r2,0(%0)" : : "a" (®s.r2) : "r2" ); - asm volatile ("l\t%%r3,0(%0)" : : "a" (®s.r3) : "r3" ); - asm volatile ("ld\t%%f0,0(%0)" : : "a" (®s.f0) : "f0" ); - } -} diff --git a/libgo/go/reflect/makefuncgo_386.go b/libgo/go/reflect/makefuncgo_386.go deleted file mode 100644 index c20f0ac3b3e..00000000000 --- a/libgo/go/reflect/makefuncgo_386.go +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// MakeFunc 386 implementation. - -package reflect - -import "unsafe" - -// The assembler stub will pass a pointer to this structure. We -// assume that no parameters are passed in registers--that is, we do -// not support the -mregparm option. On return we will set the -// registers that might hold result values. -type i386Regs struct { - esp uint32 - eax uint32 // Value to return in %eax. - st0 float64 // Value to return in %st(0). - sr bool // Set to true if hidden struct pointer. - sf bool // Set to true if returning float -} - -// MakeFuncStubGo implements the 386 calling convention for MakeFunc. -// This should not be called. It is exported so that assembly code -// can call it. - -func MakeFuncStubGo(regs *i386Regs, c *makeFuncImpl) { - ftyp := c.typ - - // See if the result requires a struct. If it does, the first - // parameter is a pointer to the struct. - retStruct := false - retEmpty := false - switch len(ftyp.out) { - case 0: - retEmpty = true - case 1: - if ftyp.out[0].size == 0 { - retEmpty = true - } else { - switch ftyp.out[0].Kind() { - case Complex64, Complex128, Array, Interface, Slice, String, Struct: - retStruct = true - } - } - default: - size := uintptr(0) - for _, typ := range ftyp.out { - size += typ.size - } - if size == 0 { - retEmpty = true - } else { - retStruct = true - } - } - - in := make([]Value, 0, len(ftyp.in)) - ap := uintptr(regs.esp) - - regs.sr = false - regs.sf = false - var retPtr unsafe.Pointer - if retStruct { - retPtr = *(*unsafe.Pointer)(unsafe.Pointer(ap)) - ap += ptrSize - regs.sr = true - } - - for _, rt := range ftyp.in { - ap = align(ap, ptrSize) - - // We have to copy the argument onto the heap in case - // the function hangs on the reflect.Value we pass it. - p := unsafe_New(rt) - memmove(p, unsafe.Pointer(ap), rt.size) - - v := Value{rt, p, flag(rt.Kind()) | flagIndir} - in = append(in, v) - ap += rt.size - } - - // Call the real function. - - out := c.call(in) - - if len(out) != len(ftyp.out) { - panic("reflect: wrong return count from function created by MakeFunc") - } - - for i, typ := range ftyp.out { - v := out[i] - if v.typ != typ { - panic("reflect: function created by MakeFunc using " + funcName(c.fn) + - " returned wrong type: have " + - out[i].typ.String() + " for " + typ.String()) - } - if v.flag&flagRO != 0 { - panic("reflect: function created by MakeFunc using " + funcName(c.fn) + - " returned value obtained from unexported field") - } - } - - if retEmpty { - return - } - - if retStruct { - off := uintptr(0) - for i, typ := range ftyp.out { - v := out[i] - off = align(off, uintptr(typ.fieldAlign)) - addr := unsafe.Pointer(uintptr(retPtr) + off) - if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) { - *(*unsafe.Pointer)(addr) = v.ptr - } else { - memmove(addr, v.ptr, typ.size) - } - off += typ.size - } - regs.eax = uint32(uintptr(retPtr)) - return - } - - if len(ftyp.out) != 1 { - panic("inconsistency") - } - - v := out[0] - switch v.Kind() { - case Ptr, UnsafePointer, Chan, Func, Map: - regs.eax = uint32(uintptr(v.pointer())) - case Float32, Float64: - regs.st0 = v.Float() - regs.sf = true - default: - memmove(unsafe.Pointer(®s.eax), v.ptr, v.typ.size) - } -} diff --git a/libgo/go/reflect/makefuncgo_amd64.go b/libgo/go/reflect/makefuncgo_amd64.go deleted file mode 100644 index a236aa26795..00000000000 --- a/libgo/go/reflect/makefuncgo_amd64.go +++ /dev/null @@ -1,496 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// MakeFunc amd64 implementation. - -package reflect - -import "unsafe" - -// The assembler stub will pass a pointer to this structure. -// This will come in holding all the registers that might hold -// function parameters. On return we will set the registers that -// might hold result values. -type amd64Regs struct { - rax uint64 - rdi uint64 - rsi uint64 - rdx uint64 - rcx uint64 - r8 uint64 - r9 uint64 - rsp uint64 - xmm0 [2]uint64 - xmm1 [2]uint64 - xmm2 [2]uint64 - xmm3 [2]uint64 - xmm4 [2]uint64 - xmm5 [2]uint64 - xmm6 [2]uint64 - xmm7 [2]uint64 -} - -// Argument classifications. The amd64 ELF ABI uses several more, but -// these are the only ones that arise for Go types. -type amd64Class int - -const ( - amd64Integer amd64Class = iota - amd64SSE - amd64NoClass - amd64Memory -) - -// amd64Classify returns the one or two register classes needed to -// pass the value of type. Go types never need more than two -// registers. amd64Memory means the value is stored in memory. -// amd64NoClass means the register is not used. -func amd64Classify(typ *rtype) (amd64Class, amd64Class) { - switch typ.Kind() { - default: - panic("internal error--unknown kind in amd64Classify") - - case Bool, Int, Int8, Int16, Int32, Int64, - Uint, Uint8, Uint16, Uint32, Uint64, - Uintptr, Chan, Func, Map, Ptr, UnsafePointer: - - return amd64Integer, amd64NoClass - - case Float32, Float64, Complex64: - return amd64SSE, amd64NoClass - - case Complex128: - return amd64SSE, amd64SSE - - case Array: - if typ.size == 0 { - return amd64NoClass, amd64NoClass - } else if typ.size > 16 { - return amd64Memory, amd64NoClass - } - atyp := (*arrayType)(unsafe.Pointer(typ)) - eclass1, eclass2 := amd64Classify(atyp.elem) - if eclass1 == amd64Memory { - return amd64Memory, amd64NoClass - } - if eclass2 == amd64NoClass && typ.size > 8 { - eclass2 = eclass1 - } - return eclass1, eclass2 - - case Interface: - return amd64Integer, amd64Integer - - case Slice: - return amd64Memory, amd64NoClass - - case String: - return amd64Integer, amd64Integer - - case Struct: - if typ.size == 0 { - return amd64NoClass, amd64NoClass - } else if typ.size > 16 { - return amd64Memory, amd64NoClass - } - var first, second amd64Class - f := amd64NoClass - onFirst := true - styp := (*structType)(unsafe.Pointer(typ)) - for _, field := range styp.fields { - if onFirst && field.offset >= 8 { - first = f - f = amd64NoClass - onFirst = false - } - fclass1, fclass2 := amd64Classify(field.typ) - f = amd64MergeClasses(f, fclass1) - if fclass2 != amd64NoClass { - if !onFirst { - panic("amd64Classify inconsistent") - } - first = f - f = fclass2 - onFirst = false - } - } - if onFirst { - first = f - second = amd64NoClass - } else { - second = f - } - if first == amd64Memory || second == amd64Memory { - return amd64Memory, amd64NoClass - } - return first, second - } -} - -// amd64MergeClasses merges two register classes as described in the -// amd64 ELF ABI. -func amd64MergeClasses(c1, c2 amd64Class) amd64Class { - switch { - case c1 == c2: - return c1 - case c1 == amd64NoClass: - return c2 - case c2 == amd64NoClass: - return c1 - case c1 == amd64Memory || c2 == amd64Memory: - return amd64Memory - case c1 == amd64Integer || c2 == amd64Integer: - return amd64Integer - default: - return amd64SSE - } -} - -// MakeFuncStubGo implements the amd64 calling convention for -// MakeFunc. This should not be called. It is exported so that -// assembly code can call it. - -func MakeFuncStubGo(regs *amd64Regs, c *makeFuncImpl) { - ftyp := c.typ - - // See if the result requires a struct. If it does, the first - // parameter is a pointer to the struct. - var ret1, ret2 amd64Class - switch len(ftyp.out) { - case 0: - ret1, ret2 = amd64NoClass, amd64NoClass - case 1: - ret1, ret2 = amd64Classify(ftyp.out[0]) - default: - off := uintptr(0) - f := amd64NoClass - onFirst := true - for _, rt := range ftyp.out { - off = align(off, uintptr(rt.fieldAlign)) - - if onFirst && off >= 8 { - ret1 = f - f = amd64NoClass - onFirst = false - } - - off += rt.size - if off > 16 { - break - } - - fclass1, fclass2 := amd64Classify(rt) - f = amd64MergeClasses(f, fclass1) - if fclass2 != amd64NoClass { - if !onFirst { - panic("amd64Classify inconsistent") - } - ret1 = f - f = fclass2 - onFirst = false - } - } - if off > 16 { - ret1, ret2 = amd64Memory, amd64NoClass - } else { - if onFirst { - ret1, ret2 = f, amd64NoClass - } else { - ret2 = f - } - } - if ret1 == amd64Memory || ret2 == amd64Memory { - ret1, ret2 = amd64Memory, amd64NoClass - } - } - - in := make([]Value, 0, len(ftyp.in)) - intreg := 0 - ssereg := 0 - ap := uintptr(regs.rsp) - - maxIntregs := 6 // When we support Windows, this would be 4. - maxSSEregs := 8 - - if ret1 == amd64Memory { - // We are returning a value in memory, which means - // that the first argument is a hidden parameter - // pointing to that return area. - intreg++ - } - -argloop: - for _, rt := range ftyp.in { - c1, c2 := amd64Classify(rt) - - fl := flag(rt.Kind()) - if c2 == amd64NoClass { - - // Argument is passed in a single register or - // in memory. - - switch c1 { - case amd64NoClass: - v := Value{rt, nil, fl | flagIndir} - in = append(in, v) - continue argloop - case amd64Integer: - if intreg < maxIntregs { - reg := amd64IntregVal(regs, intreg) - iw := unsafe.Pointer(reg) - if k := rt.Kind(); k != Ptr && k != UnsafePointer { - iw = unsafe.Pointer(®) - fl |= flagIndir - } - v := Value{rt, iw, fl} - in = append(in, v) - intreg++ - continue argloop - } - case amd64SSE: - if ssereg < maxSSEregs { - reg := amd64SSEregVal(regs, ssereg) - v := Value{rt, unsafe.Pointer(®), fl | flagIndir} - in = append(in, v) - ssereg++ - continue argloop - } - } - - in, ap = amd64Memarg(in, ap, rt) - continue argloop - } - - // Argument is passed in two registers. - - nintregs := 0 - nsseregs := 0 - switch c1 { - case amd64Integer: - nintregs++ - case amd64SSE: - nsseregs++ - default: - panic("inconsistent") - } - switch c2 { - case amd64Integer: - nintregs++ - case amd64SSE: - nsseregs++ - default: - panic("inconsistent") - } - - // If the whole argument does not fit in registers, it - // is passed in memory. - - if intreg+nintregs > maxIntregs || ssereg+nsseregs > maxSSEregs { - in, ap = amd64Memarg(in, ap, rt) - continue argloop - } - - var word1, word2 uintptr - switch c1 { - case amd64Integer: - word1 = amd64IntregVal(regs, intreg) - intreg++ - case amd64SSE: - word1 = amd64SSEregVal(regs, ssereg) - ssereg++ - } - switch c2 { - case amd64Integer: - word2 = amd64IntregVal(regs, intreg) - intreg++ - case amd64SSE: - word2 = amd64SSEregVal(regs, ssereg) - ssereg++ - } - - p := unsafe_New(rt) - *(*uintptr)(p) = word1 - *(*uintptr)(unsafe.Pointer(uintptr(p) + ptrSize)) = word2 - v := Value{rt, p, fl | flagIndir} - in = append(in, v) - } - - // All the real arguments have been found and turned into - // Value's. Call the real function. - - out := c.call(in) - - if len(out) != len(ftyp.out) { - panic("reflect: wrong return count from function created by MakeFunc") - } - - for i, typ := range ftyp.out { - v := out[i] - if v.typ != typ { - panic("reflect: function created by MakeFunc using " + funcName(c.fn) + - " returned wrong type: have " + - out[i].typ.String() + " for " + typ.String()) - } - if v.flag&flagRO != 0 { - panic("reflect: function created by MakeFunc using " + funcName(c.fn) + - " returned value obtained from unexported field") - } - } - - if ret1 == amd64NoClass { - return - } - - if ret1 == amd64Memory { - // The address of the memory area was passed as a - // hidden parameter in %rdi. - ptr := unsafe.Pointer(uintptr(regs.rdi)) - off := uintptr(0) - for i, typ := range ftyp.out { - v := out[i] - off = align(off, uintptr(typ.fieldAlign)) - addr := unsafe.Pointer(uintptr(ptr) + off) - if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) { - *(*unsafe.Pointer)(addr) = v.ptr - } else { - memmove(addr, v.ptr, typ.size) - } - off += typ.size - } - return - } - - if len(out) == 1 && ret2 == amd64NoClass { - v := out[0] - var w unsafe.Pointer - switch v.Kind() { - case Ptr, UnsafePointer, Chan, Func, Map: - w = v.pointer() - default: - memmove(unsafe.Pointer(&w), v.ptr, v.typ.size) - } - switch ret1 { - case amd64Integer: - regs.rax = uint64(uintptr(w)) - case amd64SSE: - regs.xmm0[0] = uint64(uintptr(w)) - regs.xmm0[1] = 0 - default: - panic("inconsistency") - } - return - } - - var buf [2]unsafe.Pointer - ptr := unsafe.Pointer(&buf[0]) - off := uintptr(0) - for i, typ := range ftyp.out { - v := out[i] - off = align(off, uintptr(typ.fieldAlign)) - addr := unsafe.Pointer(uintptr(ptr) + off) - if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) { - *(*unsafe.Pointer)(addr) = v.ptr - } else { - memmove(addr, v.ptr, typ.size) - } - off += uintptr(typ.size) - } - - switch ret1 { - case amd64Integer: - regs.rax = *(*uint64)(unsafe.Pointer(&buf[0])) - case amd64SSE: - regs.xmm0[0] = *(*uint64)(unsafe.Pointer(&buf[0])) - regs.xmm0[1] = 0 - default: - panic("inconsistency") - } - - switch ret2 { - case amd64Integer: - reg := *(*uint64)(unsafe.Pointer(&buf[1])) - if ret1 == amd64Integer { - regs.rdx = reg - } else { - regs.rax = reg - } - case amd64SSE: - reg := *(*uint64)(unsafe.Pointer(&buf[1])) - if ret1 == amd64Integer { - regs.xmm0[0] = reg - regs.xmm0[1] = 0 - } else { - regs.xmm1[0] = reg - regs.xmm1[1] = 0 - } - case amd64NoClass: - default: - panic("inconsistency") - } -} - -// The amd64Memarg function adds an argument passed in memory. -func amd64Memarg(in []Value, ap uintptr, rt *rtype) ([]Value, uintptr) { - ap = align(ap, ptrSize) - ap = align(ap, uintptr(rt.align)) - - // We have to copy the argument onto the heap in case the - // function hangs onto the reflect.Value we pass it. - p := unsafe_New(rt) - memmove(p, unsafe.Pointer(ap), rt.size) - - v := Value{rt, p, flag(rt.Kind()) | flagIndir} - in = append(in, v) - ap += rt.size - return in, ap -} - -// The amd64IntregVal function returns the value of integer register i. -func amd64IntregVal(regs *amd64Regs, i int) uintptr { - var r uint64 - switch i { - case 0: - r = regs.rdi - case 1: - r = regs.rsi - case 2: - r = regs.rdx - case 3: - r = regs.rcx - case 4: - r = regs.r8 - case 5: - r = regs.r9 - default: - panic("amd64IntregVal: bad index") - } - return uintptr(r) -} - -// The amd64SSEregVal function returns the value of SSE register i. -// Note that although SSE registers can hold two uinptr's, for the -// types we use in Go we only ever use the least significant one. The -// most significant one would only be used for 128 bit types. -func amd64SSEregVal(regs *amd64Regs, i int) uintptr { - var r uint64 - switch i { - case 0: - r = regs.xmm0[0] - case 1: - r = regs.xmm1[0] - case 2: - r = regs.xmm2[0] - case 3: - r = regs.xmm3[0] - case 4: - r = regs.xmm4[0] - case 5: - r = regs.xmm5[0] - case 6: - r = regs.xmm6[0] - case 7: - r = regs.xmm7[0] - } - return uintptr(r) -} diff --git a/libgo/go/reflect/makefuncgo_s390.go b/libgo/go/reflect/makefuncgo_s390.go deleted file mode 100644 index 47daa77f6bb..00000000000 --- a/libgo/go/reflect/makefuncgo_s390.go +++ /dev/null @@ -1,454 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// MakeFunc s390 implementation. - -package reflect - -import "unsafe" - -// Convenience types and constants. -const s390_arch_stack_slot_align uintptr = 4 -const s390_num_gr = 5 -const s390_num_fr = 2 - -type s390_arch_gr_t uint32 -type s390_arch_fr_t uint64 - -// The assembler stub will pass a pointer to this structure. -// This will come in holding all the registers that might hold -// function parameters. On return we will set the registers that -// might hold result values. -type s390_regs struct { - r2 s390_arch_gr_t - r3 s390_arch_gr_t - r4 s390_arch_gr_t - r5 s390_arch_gr_t - r6 s390_arch_gr_t - stack_args s390_arch_gr_t - f0 s390_arch_fr_t - f2 s390_arch_fr_t -} - -// Argument classifications that arise for Go types. -type s390_arg_t int - -const ( - s390_general_reg s390_arg_t = iota - s390_general_reg_pair - s390_float_reg - // Argument passed as a pointer to an in-memory value. - s390_mem_ptr - s390_empty -) - -// s390ClassifyParameter returns the register class needed to -// pass the value of type TYP. s390_empty means the register is -// not used. The second and third return values are the offset of -// an rtype parameter passed in a register (second) or stack slot -// (third). -func s390ClassifyParameter(typ *rtype) (s390_arg_t, uintptr, uintptr) { - offset := s390_arch_stack_slot_align - typ.Size() - if typ.Size() > s390_arch_stack_slot_align { - offset = 0 - } - switch typ.Kind() { - default: - panic("internal error--unknown kind in s390ClassifyParameter") - case Bool, Int, Int8, Int16, Int32, Uint, Uint8, Uint16, Uint32: - return s390_general_reg, offset, offset - case Int64, Uint64: - return s390_general_reg_pair, 0, 0 - case Uintptr, Chan, Func, Map, Ptr, UnsafePointer: - return s390_general_reg, 0, 0 - case Float32, Float64: - return s390_float_reg, 0, offset - case Complex64, Complex128: - // Complex numbers are passed by reference. - return s390_mem_ptr, 0, 0 - case Array, Struct: - var ityp *rtype - var length int - - if typ.Size() == 0 { - return s390_empty, 0, 0 - } - switch typ.Size() { - default: - // Pointer to memory. - return s390_mem_ptr, 0, 0 - case 1, 2: - // Pass in an integer register. - return s390_general_reg, offset, offset - - case 4, 8: - // See below. - } - if typ.Kind() == Array { - atyp := (*arrayType)(unsafe.Pointer(typ)) - length = atyp.Len() - ityp = atyp.elem - } else { - styp := (*structType)(unsafe.Pointer(typ)) - length = len(styp.fields) - ityp = styp.fields[0].typ - } - if length == 1 { - class, off_reg, off_slot := s390ClassifyParameter(ityp) - if class == s390_float_reg { - // The array (stored in a structure) or struct - // is "equivalent to a floating point type" as - // defined in the S390 Abi. Note that this - // can only be the case in the case 4 of the - // switch above. - return s390_float_reg, off_reg, off_slot - } - } - switch typ.Size() { - case 4: - return s390_general_reg, offset, offset - case 8: - return s390_general_reg_pair, 0, 0 - default: - return s390_general_reg, 0, 0 - } - case Interface, String: - // Structure of size 8. - return s390_general_reg_pair, 0, 0 - - case Slice: - return s390_mem_ptr, 0, 0 - } -} - -// s390ClassifyReturn returns the register classes needed to -// return the value of type TYP. s390_empty means the register is -// not used. The second value is the offset of an rtype return -// parameter if stored in a register. -func s390ClassifyReturn(typ *rtype) (s390_arg_t, uintptr) { - offset := s390_arch_stack_slot_align - typ.Size() - if typ.Size() > s390_arch_stack_slot_align { - offset = 0 - } - switch typ.Kind() { - default: - panic("internal error--unknown kind in s390ClassifyReturn") - case Bool, Int, Int8, Int16, Int32, - Uint, Uint8, Uint16, Uint32, Uintptr: - - return s390_general_reg, offset - case Int64, Uint64: - return s390_general_reg_pair, 0 - case Chan, Func, Map, Ptr, UnsafePointer: - return s390_general_reg, 0 - case Float32, Float64: - return s390_float_reg, 0 - case Complex64, Complex128: - return s390_mem_ptr, 0 - case Interface, Slice, String: - return s390_mem_ptr, 0 - case Array, Struct: - if typ.size == 0 { - return s390_empty, 0 - } - // No optimization is done for returned structures and arrays. - return s390_mem_ptr, 0 - } -} - -// Given a value of type *rtype left aligned in an unsafe.Pointer, -// reload the value so that it can be stored in a general or -// floating point register. For general registers the value is -// sign extend and right aligned. -func s390ReloadForRegister(typ *rtype, w uintptr, offset uintptr) uintptr { - var do_sign_extend bool = false - var gr s390_arch_gr_t - - switch typ.Kind() { - case Int, Int8, Int16, Int32: - do_sign_extend = true - default: - // Handle all other cases in the next switch. - } - switch typ.size { - case 1: - if do_sign_extend == true { - se := int32(*(*int8)(unsafe.Pointer(&w))) - gr = *(*s390_arch_gr_t)(unsafe.Pointer(&se)) - } else { - e := int32(*(*uint8)(unsafe.Pointer(&w))) - gr = *(*s390_arch_gr_t)(unsafe.Pointer(&e)) - } - case 2: - if do_sign_extend == true { - se := int32(*(*int16)(unsafe.Pointer(&w))) - gr = *(*s390_arch_gr_t)(unsafe.Pointer(&se)) - } else { - e := int32(*(*uint16)(unsafe.Pointer(&w))) - gr = *(*s390_arch_gr_t)(unsafe.Pointer(&e)) - } - default: - panic("reflect: bad size in s390ReloadForRegister") - } - - return *(*uintptr)(unsafe.Pointer(&gr)) -} - -// MakeFuncStubGo implements the s390 calling convention for -// MakeFunc. This should not be called. It is exported so that -// assembly code can call it. -func S390MakeFuncStubGo(regs *s390_regs, c *makeFuncImpl) { - ftyp := c.typ - gr := 0 - fr := 0 - ap := uintptr(regs.stack_args) - - // See if the result requires a struct. If it does, the first - // parameter is a pointer to the struct. - var ret_class s390_arg_t - var ret_off_reg uintptr - var ret_type *rtype - - switch len(ftyp.out) { - case 0: - ret_type = nil - ret_class, ret_off_reg = s390_empty, 0 - case 1: - ret_type = ftyp.out[0] - ret_class, ret_off_reg = s390ClassifyReturn(ret_type) - default: - ret_type = nil - ret_class, ret_off_reg = s390_mem_ptr, 0 - } - in := make([]Value, 0, len(ftyp.in)) - if ret_class == s390_mem_ptr { - // We are returning a value in memory, which means - // that the first argument is a hidden parameter - // pointing to that return area. - gr++ - } - -argloop: - for _, rt := range ftyp.in { - class, off_reg, off_slot := s390ClassifyParameter(rt) - fl := flag(rt.Kind()) - switch class { - case s390_empty: - v := Value{rt, nil, fl | flagIndir} - in = append(in, v) - continue argloop - case s390_general_reg: - // Values stored in a general register are right - // aligned. - if gr < s390_num_gr { - val := s390_general_reg_val(regs, gr) - iw := unsafe.Pointer(&val) - k := rt.Kind() - if k != Ptr && k != UnsafePointer { - ix := uintptr(unsafe.Pointer(&val)) - ix += off_reg - iw = unsafe.Pointer(ix) - fl |= flagIndir - } - v := Value{rt, iw, fl} - in = append(in, v) - gr++ - } else { - in, ap = s390_add_stackreg( - in, ap, rt, off_slot) - } - continue argloop - case s390_general_reg_pair: - // 64-bit integers and structs are passed in a register - // pair. - if gr+1 < s390_num_gr { - val := uint64(s390_general_reg_val(regs, gr))<<32 + uint64(s390_general_reg_val(regs, gr+1)) - iw := unsafe.Pointer(&val) - v := Value{rt, iw, fl | flagIndir} - in = append(in, v) - gr += 2 - } else { - in, ap = s390_add_stackreg(in, ap, rt, off_slot) - gr = s390_num_gr - } - continue argloop - case s390_float_reg: - // In a register, floats are left aligned, but in a - // stack slot they are right aligned. - if fr < s390_num_fr { - val := s390_float_reg_val(regs, fr) - ix := uintptr(unsafe.Pointer(&val)) - v := Value{ - rt, unsafe.Pointer(unsafe.Pointer(ix)), - fl | flagIndir, - } - in = append(in, v) - fr++ - } else { - in, ap = s390_add_stackreg( - in, ap, rt, off_slot) - } - continue argloop - case s390_mem_ptr: - if gr < s390_num_gr { - // Register holding a pointer to memory. - val := s390_general_reg_val(regs, gr) - v := Value{ - rt, unsafe.Pointer(uintptr(val)), - fl | flagIndir} - in = append(in, v) - gr++ - } else { - // Stack slot holding a pointer to memory. - in, ap = s390_add_memarg(in, ap, rt) - } - continue argloop - } - panic("reflect: argtype not handled in MakeFunc:argloop") - } - - // All the real arguments have been found and turned into - // Values. Call the real function. - - out := c.call(in) - - if len(out) != len(ftyp.out) { - panic("reflect: wrong return count from function created by MakeFunc") - } - - for i, typ := range ftyp.out { - v := out[i] - if v.typ != typ { - panic( - "reflect: function created by MakeFunc using " + - funcName(c.fn) + " returned wrong type: have " + - out[i].typ.String() + " for " + typ.String()) - } - if v.flag&flagRO != 0 { - panic( - "reflect: function created by MakeFunc using " + - funcName(c.fn) + " returned value obtained " + - "from unexported field") - } - } - - switch ret_class { - case s390_general_reg, s390_float_reg, s390_general_reg_pair: - // Single return value in a general or floating point register. - v := out[0] - var w uintptr - switch v.Kind() { - case Ptr, UnsafePointer, Chan, Func, Map: - w = uintptr(v.pointer()) - default: - memmove(unsafe.Pointer(&w), v.ptr, v.typ.size) - if ret_off_reg != 0 { - w = s390ReloadForRegister( - ret_type, w, ret_off_reg) - } - } - if ret_class == s390_float_reg { - regs.f0 = s390_arch_fr_t(uintptr(w)) - } else if ret_class == s390_general_reg { - regs.r2 = s390_arch_gr_t(uintptr(w)) - } else { - regs.r2 = s390_arch_gr_t(uintptr(w) >> 32) - regs.r3 = s390_arch_gr_t(uintptr(w) & 0xffffffff) - } - - case s390_mem_ptr: - // The address of the memory area was passed as a hidden - // parameter in %r2. Multiple return values are always returned - // in an in-memory structure. - ptr := unsafe.Pointer(uintptr(regs.r2)) - off := uintptr(0) - for i, typ := range ftyp.out { - v := out[i] - off = align(off, uintptr(typ.fieldAlign)) - addr := unsafe.Pointer(uintptr(ptr) + off) - if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) { - *(*unsafe.Pointer)(addr) = v.ptr - } else { - memmove(addr, v.ptr, typ.size) - } - off += typ.size - } - - case s390_empty: - } - - return -} - -// The s390_add_stackreg function adds an argument passed on the -// stack that could be passed in a register. -func s390_add_stackreg(in []Value, ap uintptr, rt *rtype, offset uintptr) ([]Value, uintptr) { - // If we're not already at the beginning of a stack slot, round up to - // the beginning of the next one. - ap = align(ap, s390_arch_stack_slot_align) - // If offset is > 0, the data is right aligned on the stack slot. - ap += offset - - // We have to copy the argument onto the heap in case the - // function hangs onto the reflect.Value we pass it. - p := unsafe_New(rt) - memmove(p, unsafe.Pointer(ap), rt.size) - - v := Value{rt, p, flag(rt.Kind()) | flagIndir} - in = append(in, v) - ap += rt.size - ap = align(ap, s390_arch_stack_slot_align) - - return in, ap -} - -// The s390_add_memarg function adds an argument passed in memory. -func s390_add_memarg(in []Value, ap uintptr, rt *rtype) ([]Value, uintptr) { - // If we're not already at the beginning of a stack slot, - // round up to the beginning of the next one. - ap = align(ap, s390_arch_stack_slot_align) - - // We have to copy the argument onto the heap in case the - // function hangs onto the reflect.Value we pass it. - p := unsafe_New(rt) - memmove(p, *(*unsafe.Pointer)(unsafe.Pointer(ap)), rt.size) - - v := Value{rt, p, flag(rt.Kind()) | flagIndir} - in = append(in, v) - ap += s390_arch_stack_slot_align - - return in, ap -} - -// The s390_general_reg_val function returns the value of integer register GR. -func s390_general_reg_val(regs *s390_regs, gr int) s390_arch_gr_t { - switch gr { - case 0: - return regs.r2 - case 1: - return regs.r3 - case 2: - return regs.r4 - case 3: - return regs.r5 - case 4: - return regs.r6 - default: - panic("s390_general_reg_val: bad integer register") - } -} - -// The s390_float_reg_val function returns the value of float register FR. -func s390_float_reg_val(regs *s390_regs, fr int) uintptr { - var r s390_arch_fr_t - switch fr { - case 0: - r = regs.f0 - case 1: - r = regs.f2 - default: - panic("s390_float_reg_val: bad floating point register") - } - return uintptr(r) -} diff --git a/libgo/go/reflect/makefuncgo_s390x.go b/libgo/go/reflect/makefuncgo_s390x.go deleted file mode 100644 index 6e510156b34..00000000000 --- a/libgo/go/reflect/makefuncgo_s390x.go +++ /dev/null @@ -1,436 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// MakeFunc s390x implementation. - -package reflect - -import "unsafe" - -// Convenience types and constants. -const s390x_arch_stack_slot_align uintptr = 8 -const s390x_num_gr = 5 -const s390x_num_fr = 4 - -type s390x_arch_gr_t uint64 -type s390x_arch_fr_t uint64 - -// The assembler stub will pass a pointer to this structure. -// This will come in holding all the registers that might hold -// function parameters. On return we will set the registers that -// might hold result values. -type s390x_regs struct { - r2 s390x_arch_gr_t - r3 s390x_arch_gr_t - r4 s390x_arch_gr_t - r5 s390x_arch_gr_t - r6 s390x_arch_gr_t - stack_args s390x_arch_gr_t - f0 s390x_arch_fr_t - f2 s390x_arch_fr_t - f4 s390x_arch_fr_t - f6 s390x_arch_fr_t -} - -// Argument classifications that arise for Go types. -type s390x_arg_t int - -const ( - s390x_general_reg s390x_arg_t = iota - s390x_float_reg - // Argument passed as a pointer to an in-memory value. - s390x_mem_ptr - s390x_empty -) - -// s390xClassifyParameter returns the register class needed to -// pass the value of type TYP. s390x_empty means the register is -// not used. The second and third return values are the offset of -// an rtype parameter passed in a register (second) or stack slot -// (third). -func s390xClassifyParameter(typ *rtype) (s390x_arg_t, uintptr, uintptr) { - offset := s390x_arch_stack_slot_align - typ.Size() - switch typ.Kind() { - default: - panic("internal error--unknown kind in s390xClassifyParameter") - case Bool, Int, Int8, Int16, Int32, Uint, Uint8, Uint16, Uint32: - return s390x_general_reg, offset, offset - case Int64, Uint64, Uintptr, Chan, Func, Map, Ptr, UnsafePointer: - return s390x_general_reg, 0, 0 - case Float32, Float64: - return s390x_float_reg, 0, offset - case Complex64, Complex128: - // Complex numbers are passed by reference. - return s390x_mem_ptr, 0, 0 - case Array, Struct: - var ityp *rtype - var length int - - if typ.Size() == 0 { - return s390x_empty, 0, 0 - } - switch typ.Size() { - default: - // Pointer to memory. - return s390x_mem_ptr, 0, 0 - case 1, 2: - // Pass in an integer register. - return s390x_general_reg, offset, offset - - case 4, 8: - // See below. - } - if typ.Kind() == Array { - atyp := (*arrayType)(unsafe.Pointer(typ)) - length = atyp.Len() - ityp = atyp.elem - } else { - styp := (*structType)(unsafe.Pointer(typ)) - length = len(styp.fields) - ityp = styp.fields[0].typ - } - if length == 1 { - class, off_reg, off_slot := s390xClassifyParameter(ityp) - if class == s390x_float_reg { - // The array (stored in a structure) or struct - // is "equivalent to a floating point type" as - // defined in the S390x Abi. Note that this - // can only be the case in the cases 4 and 8 of - // the switch above. - return s390x_float_reg, off_reg, off_slot - } - } - // Otherwise pass in an integer register. - switch typ.Size() { - case 4, 8: - return s390x_general_reg, offset, offset - default: - return s390x_general_reg, 0, 0 - } - case Interface, Slice, String: - return s390x_mem_ptr, 0, 0 - } -} - -// s390xClassifyReturn returns the register classes needed to -// return the value of type TYP. s390_empty means the register is -// not used. The second value is the offset of an rtype return -// parameter if stored in a register. -func s390xClassifyReturn(typ *rtype) (s390x_arg_t, uintptr) { - offset := s390x_arch_stack_slot_align - typ.Size() - switch typ.Kind() { - default: - panic("internal error--unknown kind in s390xClassifyReturn") - case Bool, Int, Int8, Int16, Int32, Int64, - Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: - - return s390x_general_reg, offset - case Chan, Func, Map, Ptr, UnsafePointer: - return s390x_general_reg, 0 - case Float32, Float64: - return s390x_float_reg, 0 - case Complex64, Complex128: - return s390x_mem_ptr, 0 - case Interface, Slice, String: - return s390x_mem_ptr, 0 - case Array, Struct: - if typ.size == 0 { - return s390x_empty, 0 - } - // No optimization is done for returned structures and arrays. - return s390x_mem_ptr, 0 - } -} - -// Given a value of type *rtype left aligned in an unsafe.Pointer, -// reload the value so that it can be stored in a general or -// floating point register. For general registers the value is -// sign extend and right aligned. -func s390xReloadForRegister(typ *rtype, w uintptr, offset uintptr) uintptr { - var do_sign_extend bool = false - var gr s390x_arch_gr_t - - switch typ.Kind() { - case Int, Int8, Int16, Int32, Int64: - do_sign_extend = true - default: - // Handle all other cases in the next switch. - } - switch typ.size { - case 1: - if do_sign_extend == true { - se := int64(*(*int8)(unsafe.Pointer(&w))) - gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&se)) - } else { - e := int64(*(*uint8)(unsafe.Pointer(&w))) - gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&e)) - } - case 2: - if do_sign_extend == true { - se := int64(*(*int16)(unsafe.Pointer(&w))) - gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&se)) - } else { - e := int64(*(*uint16)(unsafe.Pointer(&w))) - gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&e)) - } - case 4: - if do_sign_extend == true { - se := int64(*(*int32)(unsafe.Pointer(&w))) - gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&se)) - } else { - e := int64(*(*uint32)(unsafe.Pointer(&w))) - gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&e)) - } - default: - panic("reflect: bad size in s390xReloadForRegister") - } - - return *(*uintptr)(unsafe.Pointer(&gr)) -} - -// MakeFuncStubGo implements the s390x calling convention for -// MakeFunc. This should not be called. It is exported so that -// assembly code can call it. -func S390xMakeFuncStubGo(regs *s390x_regs, c *makeFuncImpl) { - ftyp := c.typ - gr := 0 - fr := 0 - ap := uintptr(regs.stack_args) - - // See if the result requires a struct. If it does, the first - // parameter is a pointer to the struct. - var ret_class s390x_arg_t - var ret_off_reg uintptr - var ret_type *rtype - - switch len(ftyp.out) { - case 0: - ret_type = nil - ret_class, ret_off_reg = s390x_empty, 0 - case 1: - ret_type = ftyp.out[0] - ret_class, ret_off_reg = s390xClassifyReturn(ret_type) - default: - ret_type = nil - ret_class, ret_off_reg = s390x_mem_ptr, 0 - } - in := make([]Value, 0, len(ftyp.in)) - if ret_class == s390x_mem_ptr { - // We are returning a value in memory, which means - // that the first argument is a hidden parameter - // pointing to that return area. - gr++ - } - -argloop: - for _, rt := range ftyp.in { - class, off_reg, off_slot := s390xClassifyParameter(rt) - fl := flag(rt.Kind()) - switch class { - case s390x_empty: - v := Value{rt, nil, fl | flagIndir} - in = append(in, v) - continue argloop - case s390x_general_reg: - // Values stored in a general register are right - // aligned. - if gr < s390x_num_gr { - val := s390x_general_reg_val(regs, gr) - iw := unsafe.Pointer(val) - k := rt.Kind() - if k != Ptr && k != UnsafePointer { - ix := uintptr(unsafe.Pointer(&val)) - ix += off_reg - iw = unsafe.Pointer(ix) - fl |= flagIndir - } - v := Value{rt, iw, fl} - in = append(in, v) - gr++ - } else { - in, ap = s390x_add_stackreg( - in, ap, rt, off_slot) - } - continue argloop - case s390x_float_reg: - // In a register, floats are left aligned, but in a - // stack slot they are right aligned. - if fr < s390x_num_fr { - val := s390x_float_reg_val(regs, fr) - ix := uintptr(unsafe.Pointer(&val)) - v := Value{ - rt, unsafe.Pointer(unsafe.Pointer(ix)), - fl | flagIndir, - } - in = append(in, v) - fr++ - } else { - in, ap = s390x_add_stackreg( - in, ap, rt, off_slot) - } - continue argloop - case s390x_mem_ptr: - if gr < s390x_num_gr { - // Register holding a pointer to memory. - val := s390x_general_reg_val(regs, gr) - v := Value{ - rt, unsafe.Pointer(val), fl | flagIndir} - in = append(in, v) - gr++ - } else { - // Stack slot holding a pointer to memory. - in, ap = s390x_add_memarg(in, ap, rt) - } - continue argloop - } - panic("reflect: argtype not handled in MakeFunc:argloop") - } - - // All the real arguments have been found and turned into - // Values. Call the real function. - - out := c.call(in) - - if len(out) != len(ftyp.out) { - panic("reflect: wrong return count from function created by MakeFunc") - } - - for i, typ := range ftyp.out { - v := out[i] - if v.typ != typ { - panic( - "reflect: function created by MakeFunc using " + - funcName(c.fn) + " returned wrong type: have " + - out[i].typ.String() + " for " + typ.String()) - } - if v.flag&flagRO != 0 { - panic( - "reflect: function created by MakeFunc using " + - funcName(c.fn) + " returned value obtained " + - "from unexported field") - } - } - - switch ret_class { - case s390x_general_reg, s390x_float_reg: - // Single return value in a general or floating point register. - v := out[0] - var w uintptr - switch v.Kind() { - case Ptr, UnsafePointer, Chan, Func, Map: - w = uintptr(v.pointer()) - default: - memmove(unsafe.Pointer(&w), v.ptr, v.typ.size) - if ret_off_reg != 0 { - w = s390xReloadForRegister( - ret_type, w, ret_off_reg) - } - } - if ret_class == s390x_float_reg { - regs.f0 = s390x_arch_fr_t(w) - } else { - regs.r2 = s390x_arch_gr_t(w) - } - - case s390x_mem_ptr: - // The address of the memory area was passed as a hidden - // parameter in %r2. Multiple return values are always returned - // in an in-memory structure. - ptr := unsafe.Pointer(uintptr(regs.r2)) - off := uintptr(0) - for i, typ := range ftyp.out { - v := out[i] - off = align(off, uintptr(typ.fieldAlign)) - addr := unsafe.Pointer(uintptr(ptr) + off) - if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) { - *(*unsafe.Pointer)(addr) = v.ptr - } else { - memmove(addr, v.ptr, typ.size) - } - off += typ.size - } - - case s390x_empty: - } - - return -} - -// The s390x_add_stackreg function adds an argument passed on the -// stack that could be passed in a register. -func s390x_add_stackreg(in []Value, ap uintptr, rt *rtype, offset uintptr) ([]Value, uintptr) { - // If we're not already at the beginning of a stack slot, round up to - // the beginning of the next one. - ap = align(ap, s390x_arch_stack_slot_align) - // If offset is > 0, the data is right aligned on the stack slot. - ap += offset - - // We have to copy the argument onto the heap in case the - // function hangs onto the reflect.Value we pass it. - p := unsafe_New(rt) - memmove(p, unsafe.Pointer(ap), rt.size) - - v := Value{rt, p, flag(rt.Kind()) | flagIndir} - in = append(in, v) - ap += rt.size - ap = align(ap, s390x_arch_stack_slot_align) - - return in, ap -} - -// The s390x_add_memarg function adds an argument passed in memory. -func s390x_add_memarg(in []Value, ap uintptr, rt *rtype) ([]Value, uintptr) { - // If we're not already at the beginning of a stack slot, - // round up to the beginning of the next one. - ap = align(ap, s390x_arch_stack_slot_align) - - // We have to copy the argument onto the heap in case the - // function hangs onto the reflect.Value we pass it. - p := unsafe_New(rt) - memmove(p, *(*unsafe.Pointer)(unsafe.Pointer(ap)), rt.size) - - v := Value{rt, p, flag(rt.Kind()) | flagIndir} - in = append(in, v) - ap += s390x_arch_stack_slot_align - - return in, ap -} - -// The s390x_general_reg_val function returns the value of integer register GR. -func s390x_general_reg_val(regs *s390x_regs, gr int) uintptr { - var r s390x_arch_gr_t - switch gr { - case 0: - r = regs.r2 - case 1: - r = regs.r3 - case 2: - r = regs.r4 - case 3: - r = regs.r5 - case 4: - r = regs.r6 - default: - panic("s390x_general_reg_val: bad integer register") - } - return uintptr(r) -} - -// The s390x_float_reg_val function returns the value of float register FR. -func s390x_float_reg_val(regs *s390x_regs, fr int) uintptr { - var r s390x_arch_fr_t - switch fr { - case 0: - r = regs.f0 - case 1: - r = regs.f2 - case 2: - r = regs.f4 - case 3: - r = regs.f6 - default: - panic("s390x_float_reg_val: bad floating point register") - } - return uintptr(r) -} diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index 09210b37b70..7cc4f7f8bfd 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -308,9 +308,6 @@ func (v Value) CallSlice(in []Value) []Value { var callGC bool // for testing; see TestCallMethodJump -var makeFuncStubFn = makeFuncStub -var makeFuncStubCode = **(**uintptr)(unsafe.Pointer(&makeFuncStubFn)) - func (v Value) call(op string, in []Value) []Value { // Get function pointer, type. t := v.typ @@ -388,17 +385,6 @@ func (v Value) call(op string, in []Value) []Value { } nout := t.NumOut() - // If target is makeFuncStub, short circuit the unpack onto stack / - // pack back into []Value for the args and return values. Just do the - // call directly. - // We need to do this here because otherwise we have a situation where - // reflect.callXX calls makeFuncStub, neither of which knows the - // layout of the args. That's bad for precise gc & stack copying. - x := (*makeFuncImpl)(fn) - if x.code == makeFuncStubCode { - return x.call(in) - } - if v.flag&flagMethod != 0 { nin++ } @@ -1120,16 +1106,6 @@ func (v Value) Pointer() uintptr { case Chan, Map, Ptr, UnsafePointer: return uintptr(v.pointer()) case Func: - if v.flag&flagMethod != 0 { - // As the doc comment says, the returned pointer is an - // underlying code pointer but not necessarily enough to - // identify a single function uniquely. All method expressions - // created via reflect have the same underlying code pointer, - // so their Pointers are equal. The function used here must - // match the one used in makeMethodValue. - f := makeFuncStub - return **(**uintptr)(unsafe.Pointer(&f)) - } p := v.pointer() // Non-nil func value points at data block. // First word of data block is actual code. diff --git a/libgo/runtime/go-ffi.c b/libgo/runtime/go-ffi.c index 175c583bf45..89da23dab1b 100644 --- a/libgo/runtime/go-ffi.c +++ b/libgo/runtime/go-ffi.c @@ -30,8 +30,6 @@ static ffi_type *go_struct_to_ffi (const struct __go_struct_type *) __attribute__ ((no_split_stack)); static ffi_type *go_string_to_ffi (void) __attribute__ ((no_split_stack)); static ffi_type *go_interface_to_ffi (void) __attribute__ ((no_split_stack)); -static ffi_type *go_complex_to_ffi (ffi_type *) - __attribute__ ((no_split_stack, unused)); static ffi_type *go_type_to_ffi (const struct __go_type_descriptor *) __attribute__ ((no_split_stack)); static ffi_type *go_func_return_ffi (const struct __go_func_type *) @@ -155,7 +153,15 @@ go_interface_to_ffi (void) return ret; } -/* Return an ffi_type for a Go complex type. */ + +#ifndef FFI_TARGET_HAS_COMPLEX_TYPE +/* If libffi hasn't been updated for this target to support complex, + pretend complex is a structure. Warning: This does not work for + all ABIs. Eventually libffi should be updated for all targets + and this should go away. */ + +static ffi_type *go_complex_to_ffi (ffi_type *) + __attribute__ ((no_split_stack)); static ffi_type * go_complex_to_ffi (ffi_type *float_type) @@ -170,6 +176,7 @@ go_complex_to_ffi (ffi_type *float_type) ret->elements[2] = NULL; return ret; } +#endif /* Return an ffi_type for a type described by a __go_type_descriptor. */ @@ -194,23 +201,25 @@ go_type_to_ffi (const struct __go_type_descriptor *descriptor) return &ffi_type_double; abort (); case GO_COMPLEX64: -#ifdef __alpha__ - runtime_throw("the libffi library does not support Complex64 type with " - "reflect.Call or runtime.SetFinalizer"); -#else if (sizeof (float) == 4) - return go_complex_to_ffi (&ffi_type_float); - abort (); + { +#ifdef FFI_TARGET_HAS_COMPLEX_TYPE + return &ffi_type_complex_float; +#else + return go_complex_to_ffi (&ffi_type_float); #endif + } + abort (); case GO_COMPLEX128: -#ifdef __alpha__ - runtime_throw("the libffi library does not support Complex128 type with " - "reflect.Call or runtime.SetFinalizer"); -#else if (sizeof (double) == 8) - return go_complex_to_ffi (&ffi_type_double); - abort (); + { +#ifdef FFI_TARGET_HAS_COMPLEX_TYPE + return &ffi_type_complex_double; +#else + return go_complex_to_ffi (&ffi_type_double); #endif + } + abort (); case GO_INT16: return &ffi_type_sint16; case GO_INT32: diff --git a/libgo/runtime/go-reflect-call.c b/libgo/runtime/go-reflect-call.c index dfc703eb2c8..29e814a793f 100644 --- a/libgo/runtime/go-reflect-call.c +++ b/libgo/runtime/go-reflect-call.c @@ -12,11 +12,10 @@ #include "go-alloc.h" #include "go-assert.h" #include "go-type.h" - -#ifdef USE_LIBFFI - #include "go-ffi.h" +#if defined(USE_LIBFFI) && FFI_GO_CLOSURES + /* The functions in this file are only called from reflect_call. As reflect_call calls a libffi function, which will be compiled without -fsplit-stack, it will always run with a large stack. */ @@ -202,11 +201,7 @@ go_set_results (const struct __go_func_type *func, unsigned char *call_result, 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 we must pass a closure pointer via - __go_set_closure. The pointer to pass is simply FUNC_VAL. */ + regardless of FUNC_TYPE, it is passed as a pointer. */ void reflect_call (const struct __go_func_type *func_type, FuncVal *func_val, @@ -221,9 +216,7 @@ 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); + ffi_call_go (&cif, func_val->fn, call_result, params, func_val); /* Some day we may need to free result values if RESULTS is NULL. */ diff --git a/libgo/runtime/malloc.goc b/libgo/runtime/malloc.goc index b05c5fa4e22..43323e25874 100644 --- a/libgo/runtime/malloc.goc +++ b/libgo/runtime/malloc.goc @@ -84,7 +84,6 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag) MLink *v, *next; byte *tiny; bool incallback; - void *closure; if(size == 0) { // All 0-length allocations use this pointer. @@ -96,10 +95,6 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag) m = runtime_m(); g = runtime_g(); - // We should not be called in between __go_set_closure and the - // actual function call, but cope with it if we are. - closure = g->closure; - incallback = false; if(m->mcache == nil && g->ncgo > 0) { // For gccgo this case can occur when a cgo or SWIG function @@ -180,7 +175,6 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag) m->locks--; if(incallback) runtime_entersyscall(); - g->closure = closure; return v; } } @@ -267,8 +261,6 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag) if(incallback) runtime_entersyscall(); - g->closure = closure; - return v; } diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c index 0867abfd168..662dd875762 100644 --- a/libgo/runtime/mgc0.c +++ b/libgo/runtime/mgc0.c @@ -133,8 +133,8 @@ clearpools(void) // clear sync.Pool's if(poolcleanup != nil) { - __go_set_closure(poolcleanup); - poolcleanup->fn(); + __builtin_call_with_static_chain(poolcleanup->fn(), + poolcleanup); } for(pp=runtime_allp; (p=*pp) != nil; pp++) { diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c index 20fbc0a6182..c4f27fb6bbb 100644 --- a/libgo/runtime/proc.c +++ b/libgo/runtime/proc.c @@ -3310,26 +3310,6 @@ runtime_proc_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj enqueue1(wbufp, (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; -} - // Return whether we are waiting for a GC. This gc toolchain uses // preemption instead. bool diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h index 1f1358ae947..515ae58ff85 100644 --- a/libgo/runtime/runtime.h +++ b/libgo/runtime/runtime.h @@ -195,7 +195,6 @@ struct Location struct G { - void* closure; // Closure value. Defer* defer; Panic* panic; void* exception; // current exception being thrown @@ -833,9 +832,6 @@ int32 getproccount(void); #define PREFETCH(p) __builtin_prefetch(p) -void __go_set_closure(void*); -void* __go_get_closure(void); - bool runtime_gcwaiting(void); void runtime_badsignal(int); Defer* runtime_newdefer(void); diff --git a/libgo/runtime/time.goc b/libgo/runtime/time.goc index ee24b9c52df..b77ad3333d3 100644 --- a/libgo/runtime/time.goc +++ b/libgo/runtime/time.goc @@ -237,8 +237,7 @@ timerproc(void* dummy __attribute__ ((unused))) arg = t->arg; seq = t->seq; runtime_unlock(&timers); - __go_set_closure(fv); - f(arg, seq); + __builtin_call_with_static_chain(f(arg, seq), fv); // clear f and arg to avoid leak while sleeping for next timer f = nil; -- 2.30.2