#include "ikarus-data.h" #include "config.h" #if ENABLE_LIBFFI #include #include #include #undef DEBUG_FFI static void* alloc(size_t n, int m) { void* x = calloc(n, m); if (x == NULL) { fprintf(stderr, "ERROR (ikarus): calloc failed!\n"); exit(-1); } return x; } static ffi_type* scheme_to_ffi_type_cast(int n){ switch (n & 0xF) { case 1: return &ffi_type_void; case 2: return &ffi_type_uint8; case 3: return &ffi_type_sint8; case 4: return &ffi_type_uint16; case 5: return &ffi_type_sint16; case 6: return &ffi_type_uint32; case 7: return &ffi_type_sint32; case 8: return &ffi_type_uint64; case 9: return &ffi_type_sint64; case 10: return &ffi_type_float; case 11: return &ffi_type_double; case 12: return &ffi_type_pointer; default: fprintf(stderr, "INVALID ARG %d", n); exit(-1); } } static void* alloc_room_for_type(int n){ ffi_type* t = scheme_to_ffi_type_cast(n); return alloc(t->size, 1); } extern long extract_num(ikptr x); static void* scheme_to_ffi_value_cast(int n, ikptr p) { void* r = alloc_room_for_type(n); switch (n & 0xF) { case 1: { free(r); return NULL; } case 2: // ffi_type_uint8; case 3: { *((char*)r) = extract_num(p); return r; } case 4: // ffi_type_uint16; case 5: { *((short*)r) = extract_num(p); return r; } case 6: // ffi_type_uint32; case 7: { *((int*)r) = extract_num(p); return r; } case 8: // ffi_type_uint64; case 9: { *((long*)r) = extract_num(p); return r; } case 10: //return &ffi_type_float; { *((float*)r) = flonum_data(p); return r; } case 11: //return &ffi_type_double; { *((double*)r) = flonum_data(p); return r; } case 12: //return &ffi_type_pointer; { *((void**)r) = (void*)ref(p, off_pointer_data); return r; } default: fprintf(stderr, "INVALID ARG %d", n); exit(-1); } } extern ikptr u_to_number(unsigned long x, ikpcb* pcb); extern ikptr s_to_number(signed long x, ikpcb* pcb); extern ikptr d_to_number(double x, ikpcb* pcb); extern ikptr make_pointer(void* x, ikpcb* pcb); static ikptr ffi_to_scheme_value_cast(int n, void* p, ikpcb* pcb) { switch (n & 0xF) { case 1: return void_object; case 2: return u_to_number(*((unsigned char*)p), pcb); case 3: return s_to_number(*((signed char*)p), pcb); case 4: return u_to_number(*((unsigned short*)p), pcb); case 5: return s_to_number(*((signed short*)p), pcb); case 6: return u_to_number(*((unsigned int*)p), pcb); case 7: return s_to_number(*((signed int*)p), pcb); case 8: return u_to_number(*((unsigned long*)p), pcb); case 9: return s_to_number(*((signed long*)p), pcb); case 10: return d_to_number(*((float*)p), pcb); case 11: return d_to_number(*((double*)p), pcb); case 12: return make_pointer(*((void**)p), pcb); default: fprintf(stderr, "INVALID ARG %d", n); exit(-1); } } ikptr ikrt_ffi_prep_cif(ikptr rtptr, ikptr argstptr, ikpcb* pcb) { ffi_cif* cif = alloc(sizeof(ffi_cif), 1); ffi_abi abi = FFI_DEFAULT_ABI; unsigned int nargs = unfix(ref(argstptr, off_vector_length)); ffi_type** argtypes = alloc(sizeof(ffi_type*), nargs+1); int i; for(i=0; iframe_base; ikptr frame_pointer = pcb->frame_pointer; #ifdef DEBUG_FFI fprintf(stderr, "old base=0x%016lx fp=0x%016lx\n", pcb->frame_base, pcb->frame_pointer); #endif if ((frame_base - wordsize) != frame_pointer) { ikptr underflow_handler = ref(frame_base, -wordsize); cont* k = (cont*) pcb->next_k; cont* nk = (cont*) ik_unsafe_alloc(pcb, sizeof(cont)); nk->tag = k->tag; nk->next = (ikptr) k; nk->top = frame_pointer; #ifdef DEBUG_FFI fprintf(stderr, "rp=0x%016lx\n", ref(frame_pointer, 0)); #endif nk->size = frame_base - frame_pointer - wordsize; #ifdef DEBUG_FFI fprintf(stderr, "frame size=%ld\n", nk->size); #endif pcb->next_k = vector_tag + (ikptr)nk; pcb->frame_base = frame_pointer; pcb->frame_pointer = frame_pointer - wordsize; #ifdef DEBUG_FFI fprintf(stderr, "new base=0x%016lx fp=0x%016lx\n", pcb->frame_base, pcb->frame_pointer); fprintf(stderr, "uf=0x%016lx\n", underflow_handler); #endif ref(pcb->frame_pointer, 0) = underflow_handler; } else { #ifdef DEBUG_FFI fprintf(stderr, "already sealed\n"); #endif } return void_object; } ikptr ikrt_call_back(ikptr proc, ikpcb* pcb) { ikrt_seal_scheme_stack(pcb); ikptr old_k = pcb->next_k; pcb->next_k = 0; ikptr entry_point = ref(proc, off_closure_code); ikptr system_stack = pcb->system_stack; #ifdef DEBUG_FFI fprintf(stderr, "system_stack = 0x%016lx\n", pcb->system_stack); #endif ikptr code_ptr = entry_point - off_code_data; ikptr rv = ik_exec_code(pcb, code_ptr, 0, proc); #ifdef DEBUG_FFI fprintf(stderr, "system_stack = 0x%016lx\n", pcb->system_stack); #endif ikptr rv2 = ref(pcb->frame_pointer, -2*wordsize); #ifdef DEBUG_FFI fprintf(stderr, "rv=0x%016lx 0x%016lx\n", rv, rv2); #endif pcb->next_k = old_k; pcb->frame_pointer = pcb->frame_base - wordsize; #ifdef DEBUG_FFI fprintf(stderr, "rp=0x%016lx\n", ref(pcb->frame_pointer, 0)); #endif pcb->system_stack = system_stack; return rv2; } ikptr ikrt_ffi_call(ikptr data, ikptr argsvec, ikpcb* pcb) { ikrt_seal_scheme_stack(pcb); ikptr cifptr = ref(data, off_vector_data + 0 * wordsize); ikptr funptr = ref(data, off_vector_data + 1 * wordsize); ikptr typevec = ref(data, off_vector_data + 2 * wordsize); ikptr rtype = ref(data, off_vector_data + 3 * wordsize); ffi_cif* cif = (ffi_cif*) ref(cifptr, off_pointer_data); void* fn = (void*) ref(funptr, off_pointer_data); unsigned int n = unfix(ref(argsvec, off_vector_length)); void** avalues = alloc(sizeof(void*), n+1); int i; for(i=0; iframe_pointer, -2*wordsize)); #endif free(avalues); free(rvalue); return val; } /* ffi_status ffi_prep_cif ( ffi_cif *cif, ffi_abi abi, unsigned int nargs, ffi_type *rtype, ffi_type **argtypes) void *ffi_closure_alloc (size_t size, void **code) void ffi_closure_free (void *writable) ffi_status ffi_prep_closure_loc ( ffi_closure *closure, ffi_cif *cif, void (*fun) (ffi_cif *cif, void *ret, void **args, void *user_data), void *user_data, void *codeloc) */ extern ikpcb* the_pcb; static void generic_callback(ffi_cif *cif, void *ret, void **args, void *user_data){ /* convert args according to cif to scheme values */ /* call into scheme, get the return value */ /* convert the return value to C */ /* put the C return value in *ret */ /* done */ ikptr data = ((callback_locative*)user_data)->data; ikptr proc = ref(data, off_vector_data + 1 * wordsize); ikptr argtypes_conv = ref(data, off_vector_data + 2 * wordsize); ikptr rtype_conv = ref(data, off_vector_data + 3 * wordsize); ikpcb* pcb = the_pcb; ikptr old_system_stack = pcb->system_stack; /* preserve */ ikptr old_next_k = pcb->next_k; /* preserve */ pcb->next_k = 0; ikptr code_entry = ref(proc, off_closure_code); ikptr code_ptr = code_entry - off_code_data; ikptr frame_pointer = pcb->frame_pointer; ikptr frame_base = pcb->frame_base; if ((frame_base - wordsize) != frame_pointer) { fprintf(stderr, "ikarus internal error: INVALID FRAME LAYOUT 0x%016lx .. 0x%016lx\n", frame_base, frame_pointer); exit(-1); } ref(frame_pointer, -2*wordsize) = fix(*((int*)args[0])); ikptr rv = ik_exec_code(pcb, code_ptr, fix(-1), proc); ikptr rv2 = ref(pcb->frame_pointer, -2*wordsize); #ifdef DEBUG_FFI fprintf(stderr, "and back with rv=0x%016lx 0x%016lx!\n", rv, rv2); #endif pcb->system_stack = old_system_stack; pcb->next_k = old_next_k; *((ikptr*)ret) = unfix(rv2); return; } ikptr ikrt_prepare_callback(ikptr data, ikpcb* pcb){ ikptr cifptr = ref(data, off_vector_data + 0 * wordsize); void* codeloc; ffi_closure* closure = ffi_closure_alloc(sizeof(ffi_closure), &codeloc); ffi_cif* cif = (ffi_cif*) ref(cifptr, off_pointer_data); callback_locative* loc = malloc(sizeof(callback_locative)); if(!loc) { fprintf(stderr, "ERROR: ikarus malloc error\n"); exit(-1); } ffi_status st = ffi_prep_closure_loc(closure, cif, generic_callback, loc, codeloc); if (st != FFI_OK) { free(loc); return false_object; } loc->data = data; loc->next = pcb->callbacks; pcb->callbacks = loc; ikptr p = ik_safe_alloc(pcb, pointer_size); ref(p, 0) = pointer_tag; ref(p, wordsize) = (ikptr) codeloc; return p+vector_tag; } int ho (int(*f)(int), int n) { // fprintf(stderr, "HO HO 0x%016lx!\n", (long)f); int n0 = f(n); // fprintf(stderr, "GOT N0\n"); return n0 + f(n); } int ho2 (ikptr fptr, ikptr nptr) { int (*f)(int) = (int(*)(int)) ref(fptr, off_pointer_data); int n = unfix(nptr); // fprintf(stderr, "HO2 HO2 0x%016lx!\n", (long)f); int n0 = f(n); // fprintf(stderr, "GOT N0\n"); return n0 + f(n); } int cadd1 (int n) { return n+1; } void hello_world(int n) { while(n > 0) { fprintf(stderr, "Hello World\n"); n--; } } #else ikptr ikrt_ffi_prep_cif() { return false_object; } ikptr ikrt_ffi_call() { return false_object; } ikptr ikrt_prepare_callback() { return false_object; } #endif