void cfunc_closure_call_binding(ffi_cif *cif, void *ret, void **args, void *self_) { mrb_value self = mrb_obj_value(self_); struct cfunc_closure_data *data = DATA_PTR(self); int ai = mrb_gc_arena_save(data->mrb); mrb_value *ary = mrb_malloc(data->mrb, sizeof(mrb_value) * data->argc); int i; for (i = 0; i < data->argc; ++i) { // TODO: I felt too much consume memory void *p = mrb_malloc(data->mrb, data->arg_ffi_types[i]->size); memcpy(p, args[i], data->arg_ffi_types[i]->size); mrb_value pointer = cfunc_pointer_new_with_pointer(data->mrb, p, true); ary[i] = mrb_funcall(data->mrb, data->arg_types[i], "refer", 1, pointer); } mrb_value block = mrb_iv_get(data->mrb, self, mrb_intern_cstr(data->mrb, "@block")); mrb_value result = mrb_funcall_argv(data->mrb, block, mrb_intern_cstr(data->mrb, "call"), data->argc, ary); mrb_free(data->mrb, ary); mrb_value ret_pointer = cfunc_pointer_new_with_pointer(data->mrb, ret, false); mrb_funcall(data->mrb, data->return_type, "set", 2, ret_pointer, result); mrb_gc_arena_restore(data->mrb, ai); }
static mrb_value cfunc_string_to_pointer(mrb_state *mrb, mrb_value self) { mrb_value ptr = cfunc_pointer_new_with_pointer(mrb, &RSTRING_PTR(self), false); mrb_obj_iv_set(mrb, mrb_obj_ptr(ptr), mrb_intern(mrb, "parent_pointer"), self); // keep for GC return ptr; }
// nil specific mrb_value cfunc_nil_addr(mrb_state *mrb, mrb_value self) { struct cfunc_type_data *data = (struct cfunc_type_data*)DATA_PTR(self); mrb_value ptr; if(data->refer) { ptr = cfunc_pointer_new_with_pointer(mrb, data->value._pointer, false); } else { ptr = cfunc_pointer_new_with_pointer(mrb, &data->value._pointer, false); } mrb_obj_iv_set(mrb, mrb_obj_ptr(ptr), mrb_intern_cstr(mrb, "parent_pointer"), self); // keep for GC return ptr; }
mrb_value cfunc_pointer_offset(mrb_state *mrb, mrb_value self) { struct cfunc_type_data *data = DATA_PTR(self); int offset; mrb_get_args(mrb, "i", &offset); mrb_value ptr = cfunc_pointer_new_with_pointer(mrb, (void*)((uint8_t*)get_cfunc_pointer_data(data) + offset), false); mrb_obj_iv_set(mrb, mrb_obj_ptr(ptr), mrb_intern(mrb, "parent_pointer"), self); // keep for GC return ptr; }
static mrb_value cfunc_call(mrb_state *mrb, mrb_value self) { int margc; mrb_value mresult_type, mname, *margs; mrb_get_args(mrb, "oo*", &mresult_type, &mname, &margs, &margc); void *dlh = dlopen(NULL, RTLD_LAZY); void *fp = dlsym(dlh, RSTRING_PTR(mname)); ffi_type **args = malloc(sizeof(ffi_type*) * margc); void **values = malloc(sizeof(void*) * margc); mrb_sym to_pointer = mrb_intern(mrb, "to_pointer"); for(int i = 0; i < margc; ++i) { if(!mrb_respond_to(mrb, margs[i], to_pointer)) { // Todo: should free some malloc-ed pointers mrb_raise(mrb, E_TYPE_ERROR, "ignore argument type"); } args[i] = mrb_value_to_mrb_ffi_type(mrb, margs[i])->ffi_type_value; values[i] = mobi_pointer_ptr(mrb_funcall(mrb, margs[i], "to_pointer", 0)); } ffi_type *result_type = rclass_to_mrb_ffi_type(mrb, mrb_class_ptr(mresult_type))->ffi_type_value; if (result_type == NULL) { mrb_raise(mrb, E_ARGUMENT_ERROR, "ignore return type"); } mrb_value mresult = mrb_nil_value(); ffi_cif cif; if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, margc, result_type, args) == FFI_OK) { void *result = result_type->size ? malloc(result_type->size) : NULL; ffi_call(&cif, fp, result, values); if(result) { mrb_value result_ptr = cfunc_pointer_new_with_pointer(mrb, result, 1); mresult = mrb_funcall(mrb, mresult_type, "refer", 1, result_ptr); } } else { // todo mrb_raise(mrb, E_NAME_ERROR, "can't find C function"); } cfunc_call_exit: free(values); free(args); return mresult; }
mrb_value cfunc_pointer_to_pointer(mrb_state *mrb, mrb_value self) { struct cfunc_type_data *data = DATA_PTR(self); void *ptr = NULL; if(data->refer) { ptr = data->value._pointer; } else { ptr = &data->value._pointer; } mrb_value obj = cfunc_pointer_new_with_pointer(mrb, ptr, 0); mrb_obj_iv_set(mrb, mrb_obj_ptr(obj), mrb_intern(mrb, "parent_pointer"), self); // keep for GC return obj; }
static mrb_value cfunc_call(mrb_state *mrb, mrb_value self) { int margc; mrb_value mresult_type, mname, *margs; void **values = NULL; ffi_type **args = NULL; mrb_get_args(mrb, "oo*", &mresult_type, &mname, &margs, &margc); void *fp = NULL; if(mrb_string_p(mname) || mrb_symbol_p(mname)) { void *dlh = dlopen(NULL, RTLD_LAZY); fp = dlsym(dlh, mrb_string_value_ptr(mrb, mname)); dlclose(dlh); } else { fp = cfunc_pointer_ptr(mname); } if(fp == NULL) { mrb_raisef(mrb, E_NAME_ERROR, "can't find C function %s", mrb_string_value_ptr(mrb, mname)); goto cfunc_call_exit; } args = malloc(sizeof(ffi_type*) * margc); values = malloc(sizeof(void*) * margc); mrb_sym sym_to_ffi_value = mrb_intern(mrb, "to_ffi_value"); mrb_value nil_ary[1]; nil_ary[0] = mrb_nil_value(); for(int i = 0; i < margc; ++i) { if(mrb_respond_to(mrb, margs[i], sym_to_ffi_value)) { args[i] = mrb_value_to_mrb_ffi_type(mrb, margs[i])->ffi_type_value; values[i] = cfunc_pointer_ptr(mrb_funcall_argv(mrb, margs[i], sym_to_ffi_value, 1, nil_ary)); } else { cfunc_mrb_raise_without_jump(mrb, E_TYPE_ERROR, "ignore argument type %s", mrb_obj_classname(mrb, margs[i])); goto cfunc_call_exit; } } ffi_type *result_type = rclass_to_mrb_ffi_type(mrb, mrb_class_ptr(mresult_type))->ffi_type_value; if (result_type == NULL) { cfunc_mrb_raise_without_jump(mrb, E_ARGUMENT_ERROR, "ignore return type %s", mrb_class_name(mrb, mrb_class_ptr(mresult_type))); goto cfunc_call_exit; } mrb_value mresult = mrb_nil_value(); ffi_cif cif; if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, margc, result_type, args) == FFI_OK) { void *result; if(result_type->size > sizeof(long)) { result = malloc(result_type->size); } else if(result_type->size) { result = malloc(sizeof(long)); } else { result = NULL; } ffi_call(&cif, fp, result, values); if(result) { mrb_value result_ptr = cfunc_pointer_new_with_pointer(mrb, result, true); mresult = mrb_funcall(mrb, mresult_type, "refer", 1, result_ptr); } } else { mrb_raisef(mrb, E_NAME_ERROR, "Can't find C function %s", mname); goto cfunc_call_exit; } cfunc_call_exit: free(values); free(args); return mresult; }
static mrb_value cfunc_pointer_data_to_mrb(mrb_state *mrb, struct cfunc_type_data *data) { return cfunc_pointer_new_with_pointer(mrb, get_cfunc_pointer_data(data), false); }
static mrb_value cfunc_pointer_c_to_mrb(mrb_state *mrb, void* p) { return cfunc_pointer_new_with_pointer(mrb, *(void**)p, false); }