From 7748c44eed2c53ce82b9d45a9f629f68f8cc4f99 Mon Sep 17 00:00:00 2001 From: Matthew Leach Date: Wed, 10 Feb 2021 20:58:18 +0000 Subject: [PATCH] [function-call] get_entry_point_for_fn: implement Implement the above function using the FFI closure API. This allows us to handle taking a function pointer into a bic evaluated function. --- src/evaluate.c | 5 +-- src/function-call.c | 87 +++++++++++++++++++++++++++++++++++++++++++++ src/function-call.h | 2 ++ 3 files changed, 92 insertions(+), 2 deletions(-) diff --git a/src/evaluate.c b/src/evaluate.c index 6a3dcae..df3fb65 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -2471,9 +2471,9 @@ static tree handle_addr_fn_def(tree fndef) live_var = make_live_var(ptr_type); - /* tLV_VAL(live_var)->D_T_PTR = get_entry_point_for_fn(fndef); */ + tLV_VAL(live_var)->D_T_PTR = get_entry_point_for_fn(fndef); - return NULL; + return live_var; } static tree eval_expr_list(tree expr_list, int depth) @@ -2646,6 +2646,7 @@ static tree __evaluate_1(tree t, int depth) { case T_IDENTIFIER: result = eval_identifier(t, depth + 1); break; case T_FN_CALL: result = eval_fn_call(t, depth + 1); break; + case T_FN: result = eval_self(t, depth + 1); break; case T_DECL: result = eval_decl(t, depth + 1); break; case T_ASSIGN: result = eval_assign(t, depth + 1); break; case T_FLOAT: result = eval_self(t, depth + 1); break; diff --git a/src/function-call.c b/src/function-call.c index 04316ed..01ec670 100644 --- a/src/function-call.c +++ b/src/function-call.c @@ -8,6 +8,7 @@ #include "function-call.h" #include "evaluate.h" #include "gc.h" +#include "spec-resolver.h" static ffi_type *type_stack[32]; static void *val_stack[32]; @@ -111,3 +112,89 @@ void do_ext_call(void *function_address, tree args, tree ret_lv, enable_gc(); } + +static void closure_entry(ffi_cif *cif, void *ret, void **ffi_args, void *user) +{ + tree closure = (tree)user; + tree arg, + args = tCLOSURE_ARG_TYPES(closure), + arg_chain = tree_make(CHAIN_HEAD), + fn_call = tree_make(T_FN_CALL); + int n = 0; + + for_each_tree(arg, args) { + tree new_arg; + + switch (TYPE(arg)){ +#define DEFCTYPE(TNAME, DESC, STDINTSZ, FMT, FFMEM) \ + case TNAME: \ + new_arg = make_live_var(arg); \ + tLV_VAL(new_arg)->TNAME = *((STDINTSZ *)(ffi_args[n])); \ + break; +#include "ctypes.def" +#undef DEFCTYPE + default: + eval_die(tCLOSURE_FN(closure), "Unknown argument type in closure entry"); + } + + n++; + tree_chain(new_arg, arg_chain); + } + + tFNCALL_ID(fn_call) = tCLOSURE_FN(closure); + tFNCALL_ARGS(fn_call) = arg_chain; + + evaluate(fn_call, ""); +} + +void *get_entry_point_for_fn(tree fndef) +{ + void *ret; + tree arg, args = tFN_ARGS(fndef), + ret_type = tFN_RET_TYPE(fndef); + tree arg_chain = tree_make(CHAIN_HEAD), + closure = tree_make(T_CLOSURE); + ffi_type *ffi_ret_type = &ffi_type_void; + tCLOSURE_CIF(closure) = malloc(sizeof(*tCLOSURE_CIF(closure))); + + n = 0; + + for_each_tree(arg, args) { + tree arg_type; + tree declarator; + + if (!is_T_DECL(arg)) + eval_die(arg, "Unknown type arg chain, expecting decl"); + + arg_type = resolve_decl_specs_to_type(tDECL_SPECS(arg)); + declarator = tDECL_DECLS(arg); + + if (is_T_POINTER(tDECL_DECLS(arg))) + resolve_ptr_type(&declarator, &arg_type); + + if (!is_T_IDENTIFIER(declarator)) + eval_die(arg, "Unknown declarator type in closure allocation"); + + type_stack[n++] = get_ffi_type(TYPE(arg_type)); + tree_chain(arg_type, arg_chain); + } + + if (!is_D_T_VOID(ret_type)) + ffi_ret_type = get_ffi_type(TYPE(ret_type)); + + tCLOSURE_FN(closure) = fndef; + tCLOSURE_ARG_TYPES(closure) = arg_chain; + tCLOSURE_RET_TYPE(closure) = ret_type; + + tCLOSURE_CLOSURE(closure) = ffi_closure_alloc(sizeof(*closure), &ret); + + ffi_prep_cif(tCLOSURE_CIF(closure), FFI_DEFAULT_ABI, n, ffi_ret_type, &type_stack); + + ffi_prep_closure_loc(tCLOSURE_CLOSURE(closure), + tCLOSURE_CIF(closure), + &closure_entry, + (void *)closure, + ret); + + return ret; +} diff --git a/src/function-call.h b/src/function-call.h index 04e4515..335b74b 100644 --- a/src/function-call.h +++ b/src/function-call.h @@ -12,3 +12,5 @@ void do_ext_call(void *function_address, tree args, tree ret_lv, int *variadic_pos); + +void *get_entry_point_for_fn(tree fndef);