diff --git a/.gitignore b/.gitignore index d421d4f..6c3d637 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ tmp *.d *.dSYM *.a +*.lock # Packages # ############ diff --git a/README.md b/README.md index 8ac2d10..90b58d9 100644 --- a/README.md +++ b/README.md @@ -2,23 +2,21 @@ Interface to C functions on mruby. it's based on [libffi](http://sourceware.org/libffi/). - ## Build status [![Build Status](https://secure.travis-ci.org/mobiruby/mruby-cfunc.png)](http://travis-ci.org/mobiruby/mruby-cfunc) - ## Install It's mrbgems. -When you use in your project, please add below to your ``build_config.rb``. +When you use in your project, please add below to your `build_config.rb`. ```ruby conf.gem 'path/to/here' do |g| # g.use_pkg_config # use pkg-config for libffi linking # g.download_libffi # download and link latest libffi - + # if your libffi is installed in a non standard path # g.cc.include_paths << '[...]/include' # g.linker.library_paths << '[...]/lib' @@ -29,28 +27,60 @@ If you want to run tests, please run below command. make test +## Windows -## Todo +To compile on windows you have to provie dlfcn-win32 libraray. + +- install ruby from rubyinstaller.org - get newest with devkit, 64bit +- after installing run as admin: + +`ridk install 1 2 3` -* Test! -* Improve error handling -* Support anonymous struct -* Examples -* Documents +- run msys2 console & install library: +`pacman -S mingw-w64-x86_64-dlfcn` + +- active ridk ruby build system by adding at the top of you Rakefile line: + +`ruby RubyInstaller::Runtime.enable_msys_apps ` + +- then add to your build_config.rb - to build libffi & link it staically: + +```ruby +MRuby::Build.new do |conf| + toolchain :gcc + conf.gem mgem: "cfunc" do |gem| + gem.download_libffi + gem.linker.flags << "-static" + end + + # ... rest of build_config.rb +end +``` + +- now you can build mruby with cfunc mgem! :) + +## Todo + +- Test! +- Improve error handling +- Support anonymous struct +- Examples +- Documents ## Contributing Feel free to open tickets or send pull requests with improvements. Thanks in advance for your help! - ## Authors Original Authors "MobiRuby developers" are [https://github.com/mobiruby/mobiruby-ios/tree/master/AUTHORS](https://github.com/mobiruby/mobiruby-ios/tree/master/AUTHORS) - ## License See Copyright Notice in [cfunc.h](https://github.com/mobiruby/mruby-cfunc/blob/master/include/cfunc.h). +``` + +``` diff --git a/examples/windows_cfunc1.rb b/examples/windows_cfunc1.rb new file mode 100644 index 0000000..304473c --- /dev/null +++ b/examples/windows_cfunc1.rb @@ -0,0 +1,43 @@ +module Win32 + module User32 + # win32 api compatibile version + # each libcall format is like this: + # - return tyupe + # - libraray + # - function to call + # - variable number of arguments to function + # - last param CFunc::Int.ew(X) - where X is number of arguments you pass above + DLL = CFunc.libcall(CFunc::Pointer, "kernel32.dll", "LoadLibraryA", "user32.dll", CFunc::Int.new(1)) + MessageBeep = begin + ptr = CFunc.libcall(CFunc::Pointer, "kernel32.dll", "GetProcAddress", DLL, "MessageBeep", CFunc::Int.new(2)) + CFunc::FunctionPointer.new(ptr).tap do |func| + func.arguments_type = [CFunc::UInt32] + func.result_type = CFunc::UInt32 + end + end + + MB_ICONASTERISK = 0x40 + + # shortcut version - it's a little bit slower, because it will try to open user32.dll again + MessageBox = proc do |text, caption, type| + CFunc.libcall( + CFunc::UInt32, # retrun type + "user32.dll", # dll + "MessageBoxA", # function + nil, text, caption, CFunc::Int.new(type), # args + CFunc::Int.new(4) # number of args + ) + end + + MB_OKCANCEL = 0x1 + end +end + +# then you can call MessageBeep like that +Win32::User32::MessageBeep.call(Win32::User32::MB_ICONASTERISK) + +# if you want get return value: +ret = Win32::User32::MessageBeep.call(Win32::User32::MB_ICONASTERISK).value + +# and calling shortcut version +Win32::User32::MessageBox.("MRuby MessageBox", "MRuby MessageBox", Win32::User32::MB_OKCANCEL) diff --git a/include/cfunc.h b/include/cfunc.h index 39587bc..4886a8c 100644 --- a/include/cfunc.h +++ b/include/cfunc.h @@ -33,7 +33,7 @@ #include "mruby/value.h" struct cfunc_state { - struct RClass *namespace; + struct RClass *ns; struct RClass *type_class; struct RClass *void_class; @@ -57,19 +57,20 @@ struct cfunc_state { static inline struct cfunc_state * cfunc_state(mrb_state *mrb, struct RClass* obj) { + mrb_value state; if(obj == NULL) { - obj = (struct RClass*) mrb_object(mrb_vm_const_get(mrb, mrb_intern_cstr(mrb, "CFunc"))); + obj = mrb_module_get(mrb, "CFunc"); } - mrb_value state = mrb_mod_cv_get(mrb, obj, mrb_intern_cstr(mrb, "cfunc_state")); - return (struct cfunc_state *)mrb_voidp(state); + state = mrb_mod_cv_get(mrb, obj, mrb_intern_lit(mrb, "cfunc_state")); + return (struct cfunc_state *)mrb_cptr(state); } static inline void set_cfunc_state(mrb_state *mrb, struct RClass* klass, struct cfunc_state *state) { - mrb_value mstate = mrb_voidp_value(mrb, state); - mrb_mod_cv_set(mrb, klass, mrb_intern_cstr(mrb, "cfunc_state"), mstate); + mrb_value mstate = mrb_cptr_value(mrb, state); + mrb_mod_cv_set(mrb, klass, mrb_intern_lit(mrb, "cfunc_state"), mstate); } #endif diff --git a/include/cfunc_closure.h b/include/cfunc_closure.h index e4a9697..04bf88b 100644 --- a/include/cfunc_closure.h +++ b/include/cfunc_closure.h @@ -29,6 +29,8 @@ struct cfunc_closure_data { mrb_value return_type; void *closure_pointer; + + int packed_args_size; }; #define cfunc_closure_data_pointer(mrb, val) \ diff --git a/include/vector.h b/include/vector.h index a71134b..fcce06c 100644 --- a/include/vector.h +++ b/include/vector.h @@ -101,7 +101,7 @@ void check_length(vector_p vec); /* Destroy the vector and free all the memory associated with it. */ void destroy_vector(vector_p vec); /* Swaps the pointers at indices i and j in the vector */ -void vector_swap(vector_p vec, int i, int j); +void vector_swap(vector_p vec, size_t i, size_t j); void vector_enqueue(vector_p vec, void* data); diff --git a/mrbgem.rake b/mrbgem.rake index b4e9f58..3ac897e 100644 --- a/mrbgem.rake +++ b/mrbgem.rake @@ -4,31 +4,51 @@ MRuby::Gem::Specification.new('mruby-cfunc') do |spec| spec.license = 'MIT' spec.authors = 'MobiRuby developers' + add_test_dependency 'mruby-print', core: 'mruby-print' + add_dependency 'mruby-enumerator', core: 'mruby-enumerator' + + rubyvm1_rbx = "#{dir}/test/_rubyvm1.rbx" + rubyvm1_c = "#{build_dir}/test/_rubyvm1.c" + rubyvm1_o = rubyvm1_c.ext('o') + spec.test_objs << rubyvm1_o + spec.test_preload = "#{dir}/test/mobitest.rb" + + file rubyvm1_o => rubyvm1_c + file rubyvm1_c => [rubyvm1_rbx, build.mrbcfile] do |t| + FileUtils.mkdir_p File.dirname t.name + open(rubyvm1_c, 'w') do |f| + f.puts '#include ' + build.mrbc.run f, rubyvm1_rbx, 'mruby_data__rubyvm1' + end + end + def spec.use_pkg_config(pkg_config='pkg-config') self.linker.flags << `"#{pkg_config}" libffi --libs-only-L --libs-only-other`.chomp [self.cc, self.cxx, self.objc, self.mruby.cc, self.mruby.cxx, self.mruby.objc].each do |cc| - cc.include_paths << `"#{pkg_config}" libffi --cflags`.chomp + cc.flags << `"#{pkg_config}" libffi --cflags`.chomp end end - def spec.download_libffi(libffi_version = '3.0.13', tar = 'tar') + def spec.download_libffi(libffi_version = '3.3', tar = 'tar') libffi_url = "ftp://sourceware.org/pub/libffi/libffi-#{libffi_version}.tar.gz" - libffi_build_root = "build/libffi/#{build.name}" + libffi_build_root = "#{MRUBY_ROOT}/build/libffi/#{build.name}" libffi_dir = "#{libffi_build_root}/libffi-#{libffi_version}" libffi_a = "#{libffi_dir}/lib/libffi.a" unless File.exists?(libffi_a) puts "Downloading #{libffi_url}" - open(libffi_url, 'r') do |ftp| + URI.open(libffi_url, 'rb') do |ftp| libffi_tar = ftp.read puts "Extracting" FileUtils.mkdir_p libffi_build_root - IO.popen("#{tar} xfz - -C #{filename libffi_build_root}", 'w') do |f| + IO.popen("#{tar} xfz - -C #{filename libffi_build_root}", 'wb') do |f| f.write libffi_tar end puts "Done" end - sh %Q{(cd #{filename libffi_dir} && CC=#{build.cc.command} CFLAGS="#{build.cc.all_flags.gsub('\\','\\\\').gsub('"', '\\"')}" ./configure --prefix=`pwd` && make clean install)} + Dir.chdir(filename libffi_dir) do + sh %Q{env CC=#{build.cc.command} CFLAGS="#{build.cc.all_flags.gsub('\\', '\\\\').gsub('"', '\\"')}" ./configure --prefix="#{Dir.pwd}" && make clean install} + end end self.linker.library_paths << File.dirname(libffi_a) @@ -37,6 +57,13 @@ MRuby::Gem::Specification.new('mruby-cfunc') do |spec| end end + if spec.respond_to?(:search_package) && spec.search_package('libffi') + spec.linker.libraries << 'pthread' << 'dl' + spec.cc.flags << %w(-pthread) + spec.linker.flags << "-Wl,--export-dynamic,--dynamic-list=#{spec.dir}/test/func.txt" + next + end + spec.linker.libraries << %w(ffi dl pthread) if ENV['OS'] == 'Windows_NT' @@ -55,19 +82,5 @@ MRuby::Gem::Specification.new('mruby-cfunc') do |spec| # spec.objs << ["#{LIBFFI_DIR}/lib/libffi.a"] # spec.test_rbfiles = Dir.glob("#{dir}/test/*.rb") # spec.test_objs = Dir.glob("#{dir}/test/*.{c,cpp,m,asm,S}").map { |f| f.relative_path_from(dir).pathmap("#{build_dir}/%X.o") } - spec.test_preload = "#{dir}/test/mobitest.rb" - - rubyvm1_rbx = "#{dir}/test/_rubyvm1.rbx" - rubyvm1_c = "#{build_dir}/test/_rubyvm1.c" - rubyvm1_o = rubyvm1_c.ext('o') - spec.test_objs << rubyvm1_o - - file rubyvm1_o => rubyvm1_c - file rubyvm1_c => rubyvm1_rbx do |t| - open(rubyvm1_c, 'w') do |f| - f.puts '#include ' - build.mrbc.run f, rubyvm1_rbx, 'mruby_data__rubyvm1' - end - end end diff --git a/run_test.rb b/run_test.rb index b5cfd02..9e9fafa 100644 --- a/run_test.rb +++ b/run_test.rb @@ -11,9 +11,9 @@ MRuby::Build.new do |conf| toolchain :gcc - conf.gembox 'default' + # conf.gembox 'default' - conf.gem "#{root}/mrbgems/mruby-eval" + # conf.gem "#{root}/mrbgems/mruby-eval" conf.gem File.expand_path(File.dirname(__FILE__)) do |g| # g.use_pkg_config diff --git a/src/cfunc.c b/src/cfunc.c index 4b8fec9..3d3671f 100644 --- a/src/cfunc.c +++ b/src/cfunc.c @@ -45,22 +45,23 @@ void mrb_mruby_cfunc_gem_init(mrb_state* mrb) { struct RClass *ns = mrb_define_module(mrb, "CFunc"); - struct cfunc_state *state = mrb_malloc(mrb, sizeof(struct cfunc_state)); + struct cfunc_state *state = (struct cfunc_state*)mrb_malloc(mrb, sizeof(struct cfunc_state)); + int ai; set_cfunc_state(mrb, ns, state); - state->namespace = ns; + state->ns = ns; - int ai = mrb_gc_arena_save(mrb); + ai = mrb_gc_arena_save(mrb); init_cfunc_type(mrb, ns); mrb_gc_arena_restore(mrb, ai); init_cfunc_pointer(mrb, ns); mrb_gc_arena_restore(mrb, ai); init_cfunc_struct(mrb, ns); mrb_gc_arena_restore(mrb, ai); init_cfunc_closure(mrb, ns); mrb_gc_arena_restore(mrb, ai); init_cfunc_call(mrb, ns); mrb_gc_arena_restore(mrb, ai); init_cfunc_rubyvm(mrb, ns); mrb_gc_arena_restore(mrb, ai); - init_cfunc_platform(mrb, ns); mrb_gc_arena_restore(mrb, ai); + init_cfunc_platform(mrb, ns); mrb_gc_arena_restore(mrb, ai); - mrb_define_class_method(mrb, ns, "mrb_state", cfunc_mrb_state, ARGS_NONE()); - mrb_define_class_method(mrb, ns, "errno", cfunc_errno, ARGS_NONE()); - mrb_define_class_method(mrb, ns, "strerror", cfunc_strerror, ARGS_NONE()); + mrb_define_class_method(mrb, ns, "mrb_state", cfunc_mrb_state, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, ns, "errno", cfunc_errno, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, ns, "strerror", cfunc_strerror, MRB_ARGS_NONE()); } void diff --git a/src/cfunc_call.c b/src/cfunc_call.c index 458679f..b6ba4a0 100644 --- a/src/cfunc_call.c +++ b/src/cfunc_call.c @@ -49,25 +49,34 @@ get_proc_address(const char* funcname) static mrb_value cfunc_call(mrb_state *mrb, mrb_value self) { - int margc; + mrb_int margc; mrb_value mresult_type, mname, *margs; void **values = NULL; ffi_type **args = NULL; + void *fp = NULL; + mrb_sym sym_to_ffi_value; + int i; + mrb_value nil_ary[1]; + ffi_type *result_type; + mrb_value mresult = mrb_nil_value(); + ffi_cif cif; mrb_get_args(mrb, "oo*", &mresult_type, &mname, &margs, &margc); - void *fp = NULL; - if(mrb_string_p(mname) || mrb_symbol_p(mname)) { + if (mrb_symbol_p(mname)) { + mname = mrb_str_to_str(mrb, mname); + } + if(mrb_string_p(mname)) { #ifndef _WIN32 void *dlh = dlopen(NULL, RTLD_LAZY); fp = dlsym(dlh, mrb_string_value_ptr(mrb, mname)); - dlclose(dlh); + // dlclose(dlh); #else fp = get_proc_address(mrb_string_value_ptr(mrb, mname)); #endif if(fp == NULL) { - mrb_raisef(mrb, E_NAME_ERROR, "can't find C function %s", mrb_string_value_ptr(mrb, mname)); + mrb_raisef(mrb, E_NAME_ERROR, "can't find C function %S", mname); goto cfunc_call_exit; } } @@ -79,13 +88,11 @@ cfunc_call(mrb_state *mrb, mrb_value self) } } - args = mrb_malloc(mrb, sizeof(ffi_type*) * margc); - values = mrb_malloc(mrb, sizeof(void*) * margc); - mrb_sym sym_to_ffi_value = mrb_intern_cstr(mrb, "to_ffi_value"); + args = (ffi_type**)mrb_malloc(mrb, sizeof(ffi_type*) * margc); + values = (void**)mrb_malloc(mrb, sizeof(void*) * margc); + sym_to_ffi_value = mrb_intern_lit(mrb, "to_ffi_value"); - mrb_value nil_ary[1]; nil_ary[0] = mrb_nil_value(); - int i; for(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; @@ -97,14 +104,12 @@ cfunc_call(mrb_state *mrb, mrb_value self) } } - ffi_type *result_type = rclass_to_mrb_ffi_type(mrb, mrb_class_ptr(mresult_type))->ffi_type_value; + 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)) { @@ -116,15 +121,15 @@ cfunc_call(mrb_state *mrb, mrb_value self) else { result = NULL; } - ffi_call(&cif, fp, result, values); - + ffi_call(&cif, (void(*)())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); + mrb_raisef(mrb, E_NAME_ERROR, "Can't find C function %S", mname); goto cfunc_call_exit; } @@ -138,21 +143,30 @@ cfunc_call(mrb_state *mrb, mrb_value self) static mrb_value cfunc_libcall(mrb_state *mrb, mrb_value self) { - int margc; + mrb_int margc; mrb_value mresult_type, mlib, mname, *margs; void **values = NULL; ffi_type **args = NULL; + void *fp = NULL; + mrb_sym sym_to_ffi_value; + mrb_value nil_ary[1]; + int i; + ffi_type *result_type; + mrb_value mresult = mrb_nil_value(); + ffi_cif cif; mrb_get_args(mrb, "oSo*", &mresult_type, &mlib, &mname, &margs, &margc); - void *fp = NULL; - if((mrb_string_p(mname) || mrb_symbol_p(mname))) { + if (mrb_symbol_p(mname)) { + mname = mrb_str_to_str(mrb, mname); + } + if(mrb_string_p(mname)) { void *dlh = dlopen(mrb_string_value_ptr(mrb, mlib), RTLD_LAZY); fp = dlsym(dlh, mrb_string_value_ptr(mrb, mname)); dlclose(dlh); if(fp == NULL) { - mrb_raisef(mrb, E_NAME_ERROR, "can't find C function %s", mrb_string_value_ptr(mrb, mname)); + mrb_raisef(mrb, E_NAME_ERROR, "can't find C function %S", mname); goto cfunc_call_exit; } } @@ -164,13 +178,11 @@ cfunc_libcall(mrb_state *mrb, mrb_value self) } } - args = mrb_malloc(mrb, sizeof(ffi_type*) * margc); - values = mrb_malloc(mrb, sizeof(void*) * margc); - mrb_sym sym_to_ffi_value = mrb_intern_cstr(mrb, "to_ffi_value"); + args = (ffi_type**)mrb_malloc(mrb, sizeof(ffi_type*) * margc); + values = (void**)mrb_malloc(mrb, sizeof(void*) * margc); + sym_to_ffi_value = mrb_intern_lit(mrb, "to_ffi_value"); - mrb_value nil_ary[1]; nil_ary[0] = mrb_nil_value(); - int i; for(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; @@ -182,14 +194,12 @@ cfunc_libcall(mrb_state *mrb, mrb_value self) } } - ffi_type *result_type = rclass_to_mrb_ffi_type(mrb, mrb_class_ptr(mresult_type))->ffi_type_value; + 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)) { @@ -201,7 +211,7 @@ cfunc_libcall(mrb_state *mrb, mrb_value self) else { result = NULL; } - ffi_call(&cif, fp, result, values); + ffi_call(&cif, (void(*)())fp, result, values); if(result) { mrb_value result_ptr = cfunc_pointer_new_with_pointer(mrb, result, true); @@ -209,7 +219,7 @@ cfunc_libcall(mrb_state *mrb, mrb_value self) } } else { - mrb_raisef(mrb, E_NAME_ERROR, "Can't find C function %s", mname); + mrb_raisef(mrb, E_NAME_ERROR, "Can't find C function %S", mname); goto cfunc_call_exit; } @@ -222,6 +232,6 @@ cfunc_libcall(mrb_state *mrb, mrb_value self) void init_cfunc_call(mrb_state *mrb, struct RClass* module) { - mrb_define_class_method(mrb, module, "call", cfunc_call, ARGS_ANY()); - mrb_define_module_function(mrb, module, "libcall", cfunc_libcall, ARGS_ANY()); + mrb_define_class_method(mrb, module, "call", cfunc_call, MRB_ARGS_ANY()); + mrb_define_module_function(mrb, module, "libcall", cfunc_libcall, MRB_ARGS_ANY()); } diff --git a/src/cfunc_closure.c b/src/cfunc_closure.c index afa336d..8c81a6b 100644 --- a/src/cfunc_closure.c +++ b/src/cfunc_closure.c @@ -25,7 +25,8 @@ static void cfunc_closure_destructor(mrb_state *mrb, void *p_) { - struct cfunc_closure_data *p = p_; + struct cfunc_closure_data *p = (struct cfunc_closure_data*)p_; + if (p->closure) { ffi_closure_free(p->closure); } @@ -55,9 +56,14 @@ mrb_value cfunc_closure_initialize(mrb_state *mrb, mrb_value self) { struct cfunc_closure_data *data; - data = mrb_data_check_get_ptr(mrb, self, &cfunc_closure_data_type); + mrb_value rettype_mrb, block, args_mrb; + ffi_type *return_ffi_type; + int i; + void *closure_pointer = NULL; + + data = (struct cfunc_closure_data*)mrb_data_check_get_ptr(mrb, self, &cfunc_closure_data_type); if (!data) { - data = mrb_malloc(mrb, sizeof(struct cfunc_closure_data)); + data = (struct cfunc_closure_data*)mrb_malloc(mrb, sizeof(struct cfunc_closure_data)); } data->refer = 0; data->autofree = 0; @@ -67,31 +73,29 @@ cfunc_closure_initialize(mrb_state *mrb, mrb_value self) data->mrb = mrb; data->closure = NULL; data->arg_types = NULL; + data->packed_args_size = -1; - mrb_value rettype_mrb, block, args_mrb; mrb_get_args(mrb, "&oo", &block, &rettype_mrb, &args_mrb); data->argc = RARRAY_LEN(args_mrb); - ffi_type *return_ffi_type = rclass_to_mrb_ffi_type(mrb, mrb_class_ptr(rettype_mrb))->ffi_type_value; + return_ffi_type = rclass_to_mrb_ffi_type(mrb, mrb_class_ptr(rettype_mrb))->ffi_type_value; data->return_type = rettype_mrb; - data->arg_ffi_types = mrb_malloc(mrb, sizeof(ffi_type*) * data->argc); - data->arg_types = mrb_malloc(mrb, sizeof(mrb_value) * data->argc); - int i; + data->arg_ffi_types = (ffi_type**)mrb_malloc(mrb, sizeof(ffi_type*) * data->argc); + data->arg_types = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * data->argc); for (i = 0; i < data->argc; ++i) { data->arg_types[i] = mrb_ary_ref(mrb, args_mrb, i); data->arg_ffi_types[i] = rclass_to_mrb_ffi_type(mrb, mrb_class_ptr(data->arg_types[i]))->ffi_type_value; } - mrb_iv_set(mrb, self, mrb_intern_cstr(data->mrb, "@block"), block); + mrb_iv_set(mrb, self, mrb_intern_lit(data->mrb, "@block"), block); - void *closure_pointer = NULL; - data->closure = ffi_closure_alloc(sizeof(ffi_closure) + sizeof(void*), &closure_pointer); - data->cif = mrb_malloc(mrb, sizeof(ffi_cif)); + data->closure = (ffi_closure*)ffi_closure_alloc(sizeof(ffi_closure) + sizeof(void*), &closure_pointer); + data->cif = (ffi_cif*)mrb_malloc(mrb, sizeof(ffi_cif)); if (data->closure) { if (ffi_prep_cif(data->cif, FFI_DEFAULT_ABI, data->argc, return_ffi_type, data->arg_ffi_types) == FFI_OK) { - if (ffi_prep_closure_loc(data->closure, data->cif, cfunc_closure_call_binding, mrb_object(self), closure_pointer) == FFI_OK) { + if (ffi_prep_closure_loc(data->closure, data->cif, cfunc_closure_call_binding, mrb_ptr(self), closure_pointer) == FFI_OK) { set_cfunc_pointer_data((struct cfunc_type_data *)data, closure_pointer); return self; } @@ -107,28 +111,46 @@ 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); + struct cfunc_closure_data *data = (struct cfunc_closure_data*)DATA_PTR(self); + mrb_state *mrb = data->mrb; - int ai = mrb_gc_arena_save(data->mrb); + int ai = mrb_gc_arena_save(mrb); - mrb_value *ary = mrb_malloc(data->mrb, sizeof(mrb_value) * data->argc); + mrb_value *ary = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * data->argc); int i; + void *packed_args; + mrb_value packed_args_value, block, result, ret_pointer; + void *p; + if (data->packed_args_size == -1) { + // calculate packed args size + size_t result = 0; + for (i = 0; i < data->argc; ++i) { + ffi_type const *t = data->arg_ffi_types[i]; + result += t->size + ((t->alignment - (t->size % t->alignment)) % t->alignment); + } + data->packed_args_size = result; + } + packed_args = mrb_malloc(mrb, data->packed_args_size); + packed_args_value = cfunc_pointer_new_with_pointer(mrb, packed_args, true); + p = packed_args; 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); + ffi_type const *t = data->arg_ffi_types[i]; + mrb_value pointer; + memcpy(p, args[i], t->size); + pointer = cfunc_pointer_new_with_pointer(mrb, p, false); + mrb_iv_set(mrb, pointer, mrb_intern_lit(mrb, "parent_pointer"), packed_args_value); // for GC + p = ((uint8_t*)p) + t->size + ((t->alignment - (t->size % t->alignment)) % t->alignment); + ary[i] = mrb_funcall(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); + block = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@block")); + result = mrb_funcall_argv(mrb, block, mrb_intern_lit(mrb, "call"), data->argc, ary); + mrb_free(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); + ret_pointer = cfunc_pointer_new_with_pointer(mrb, ret, false); + mrb_funcall(mrb, data->return_type, "set", 2, ret_pointer, result); - mrb_gc_arena_restore(data->mrb, ai); + mrb_gc_arena_restore(mrb, ai); } @@ -170,10 +192,10 @@ cfunc_closure_mrb_to_data(mrb_state *mrb, mrb_value val, struct cfunc_type_data static struct mrb_ffi_type closure_mrb_ffi_type = { .name = "Closure", .ffi_type_value = &ffi_type_pointer, - .mrb_to_c = &cfunc_closure_mrb_to_c, - .c_to_mrb = &cfunc_closure_c_to_mrb, + .data_to_mrb = &cfunc_closure_data_to_mrb, .mrb_to_data = &cfunc_closure_mrb_to_data, - .data_to_mrb = &cfunc_closure_data_to_mrb + .c_to_mrb = &cfunc_closure_c_to_mrb, + .mrb_to_c = &cfunc_closure_mrb_to_c }; @@ -182,10 +204,11 @@ init_cfunc_closure(mrb_state *mrb, struct RClass* module) { struct cfunc_state *state = cfunc_state(mrb, module); struct RClass *closure_class = mrb_define_class_under(mrb, module, "Closure", state->pointer_class); + mrb_value ffi_type; state->closure_class = closure_class; - mrb_value ffi_type = mrb_obj_value(Data_Wrap_Struct(mrb, mrb->object_class, &cfunc_closure_ffi_type_data_type, &closure_mrb_ffi_type)); - mrb_obj_iv_set(mrb, (struct RObject*)closure_class, mrb_intern_cstr(mrb, "@ffi_type"), ffi_type); + ffi_type = mrb_obj_value(Data_Wrap_Struct(mrb, mrb->object_class, &cfunc_closure_ffi_type_data_type, &closure_mrb_ffi_type)); + mrb_obj_iv_set(mrb, (struct RObject*)closure_class, mrb_intern_lit(mrb, "@ffi_type"), ffi_type); - mrb_define_method(mrb, closure_class, "initialize", cfunc_closure_initialize, ARGS_ANY()); + mrb_define_method(mrb, closure_class, "initialize", cfunc_closure_initialize, MRB_ARGS_ANY()); } diff --git a/src/cfunc_platform.c b/src/cfunc_platform.c index 0cd52a7..964e416 100644 --- a/src/cfunc_platform.c +++ b/src/cfunc_platform.c @@ -45,7 +45,7 @@ void init_cfunc_platform(mrb_state *mrb, struct RClass* module) { struct RClass *struct_class = mrb_define_class_under(mrb, module, "Platform", mrb->object_class); - mrb_define_class_method(mrb, struct_class, "is_posix?", cfunc_platform_is_posix, ARGS_NONE()); - mrb_define_class_method(mrb, struct_class, "is_win32?", cfunc_platform_is_win32, ARGS_NONE()); - mrb_define_class_method(mrb, struct_class, "is_darwin?", cfunc_platform_is_darwin, ARGS_NONE()); + mrb_define_class_method(mrb, struct_class, "is_posix?", cfunc_platform_is_posix, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, struct_class, "is_win32?", cfunc_platform_is_win32, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, struct_class, "is_darwin?", cfunc_platform_is_darwin, MRB_ARGS_NONE()); } diff --git a/src/cfunc_pointer.c b/src/cfunc_pointer.c index 12ca494..b61545f 100644 --- a/src/cfunc_pointer.c +++ b/src/cfunc_pointer.c @@ -62,14 +62,15 @@ void set_cfunc_pointer_data(struct cfunc_type_data *data, void *p) mrb_value cfunc_pointer_class_malloc(mrb_state *mrb, mrb_value klass) { - struct cfunc_type_data *data = mrb_malloc(mrb, sizeof(struct cfunc_type_data)); + struct cfunc_type_data *data = (struct cfunc_type_data*)mrb_malloc(mrb, sizeof(struct cfunc_type_data)); + mrb_int alloc_size; data->refer = false; data->autofree = false; - mrb_int alloc_size; mrb_get_args(mrb, "i", &alloc_size); set_cfunc_pointer_data(data, mrb_malloc(mrb, alloc_size)); + data->autofree = true; return mrb_obj_value(Data_Wrap_Struct(mrb, mrb_class_ptr(klass), &cfunc_pointer_data_type, data)); } @@ -78,13 +79,14 @@ cfunc_pointer_class_malloc(mrb_state *mrb, mrb_value klass) mrb_value cfunc_pointer_new_with_pointer(mrb_state *mrb, void *p, bool autofree) { - struct cfunc_type_data *data = mrb_malloc(mrb, sizeof(struct cfunc_type_data)); + struct cfunc_type_data *data = (struct cfunc_type_data*)mrb_malloc(mrb, sizeof(struct cfunc_type_data)); + struct cfunc_state *state; data->refer = false; data->autofree = autofree; set_cfunc_pointer_data(data, p); - struct cfunc_state *state = cfunc_state(mrb, NULL); + state = cfunc_state(mrb, NULL); return mrb_obj_value(Data_Wrap_Struct(mrb, state->pointer_class, &cfunc_pointer_data_type, data)); } @@ -93,17 +95,18 @@ mrb_value cfunc_pointer_refer(mrb_state *mrb, mrb_value klass) { struct RClass *c = mrb_class_ptr(klass); - struct cfunc_type_data *data = mrb_malloc(mrb, sizeof(struct cfunc_type_data)); + struct cfunc_type_data *data = (struct cfunc_type_data*)mrb_malloc(mrb, sizeof(struct cfunc_type_data)); + mrb_value pointer; + struct RObject *obj; data->refer = true; data->autofree = false; - mrb_value pointer; mrb_get_args(mrb, "o", &pointer); data->value._pointer = cfunc_pointer_ptr(pointer); - struct RObject *obj = (struct RObject *)Data_Wrap_Struct(mrb, c, &cfunc_pointer_data_type, data); - mrb_obj_iv_set(mrb, obj, mrb_intern_cstr(mrb, "parent_pointer"), pointer); // keep for GC + obj = (struct RObject *)Data_Wrap_Struct(mrb, c, &cfunc_pointer_data_type, data); + mrb_obj_iv_set(mrb, obj, mrb_intern_lit(mrb, "parent_pointer"), pointer); // keep for GC return mrb_obj_value(obj); } @@ -112,17 +115,19 @@ mrb_value cfunc_pointer_initialize(mrb_state *mrb, mrb_value self) { struct cfunc_type_data *data; - data = mrb_data_check_get_ptr(mrb, self, &cfunc_pointer_data_type); + mrb_value ptr; + int argc; + + data = (struct cfunc_type_data*)mrb_data_check_get_ptr(mrb, self, &cfunc_pointer_data_type); if(!data) { - data = mrb_malloc(mrb, sizeof(struct cfunc_type_data)); + data = (struct cfunc_type_data*)mrb_malloc(mrb, sizeof(struct cfunc_type_data)); DATA_PTR(self) = data; DATA_TYPE(self) = &cfunc_pointer_data_type; } data->refer = false; data->autofree = false; - mrb_value ptr; - int argc = mrb_get_args(mrb, "|o", &ptr); + argc = mrb_get_args(mrb, "|o", &ptr); if(argc == 0) { set_cfunc_pointer_data(data, NULL); } @@ -137,7 +142,7 @@ cfunc_pointer_initialize(mrb_state *mrb, mrb_value self) mrb_value cfunc_pointer_realloc(mrb_state *mrb, mrb_value self) { - struct cfunc_type_data *data = DATA_PTR(self); + struct cfunc_type_data *data = (struct cfunc_type_data*)DATA_PTR(self); mrb_int alloc_size; mrb_get_args(mrb, "i", &alloc_size); @@ -150,7 +155,7 @@ cfunc_pointer_realloc(mrb_state *mrb, mrb_value self) mrb_value cfunc_pointer_free(mrb_state *mrb, mrb_value self) { - struct cfunc_type_data *data = DATA_PTR(self); + struct cfunc_type_data *data = (struct cfunc_type_data*)DATA_PTR(self); mrb_free(mrb, get_cfunc_pointer_data(data)); data->autofree = false; @@ -163,15 +168,15 @@ cfunc_pointer_free(mrb_state *mrb, mrb_value self) mrb_value cfunc_pointer_inspect(mrb_state *mrb, mrb_value self) { - struct cfunc_type_data *data = DATA_PTR(self); + struct cfunc_type_data *data = (struct cfunc_type_data*)DATA_PTR(self); + char cstr[256]; mrb_value type = mrb_funcall(mrb, mrb_obj_value(mrb_class(mrb, self)), "type", 0); - const char* classname = mrb_class_name(mrb, (struct RClass*)mrb_object(type)); + const char* classname = mrb_class_name(mrb, mrb_class_ptr(type)); if(!classname) { classname = "Unknown pointer"; } - char cstr[256]; snprintf(cstr, sizeof(cstr), "<%s pointer=%p>", classname, get_cfunc_pointer_data(data)); return mrb_str_new_cstr(mrb, cstr); @@ -181,7 +186,7 @@ cfunc_pointer_inspect(mrb_state *mrb, mrb_value self) mrb_value cfunc_pointer_is_null(mrb_state *mrb, mrb_value self) { - struct cfunc_type_data *data = DATA_PTR(self); + struct cfunc_type_data *data = (struct cfunc_type_data*)DATA_PTR(self); return (get_cfunc_pointer_data(data) == NULL) ? mrb_true_value() : mrb_false_value(); } @@ -189,7 +194,7 @@ cfunc_pointer_is_null(mrb_state *mrb, mrb_value self) mrb_value cfunc_pointer_autofree(mrb_state *mrb, mrb_value self) { - struct cfunc_type_data *data = DATA_PTR(self); + struct cfunc_type_data *data = (struct cfunc_type_data*)DATA_PTR(self); data->autofree = true; return self; } @@ -198,26 +203,18 @@ cfunc_pointer_autofree(mrb_state *mrb, mrb_value self) mrb_value cfunc_pointer_to_s(mrb_state *mrb, mrb_value self) { - struct cfunc_type_data *data = DATA_PTR(self); - size_t len; - mrb_value str; - struct RString *s; + struct cfunc_type_data *data = (struct cfunc_type_data*)DATA_PTR(self); const char* p = (const char*)get_cfunc_pointer_data(data); - - len = strlen(p); - str = mrb_str_new(mrb, 0, len); - s = mrb_str_ptr(str); - strcpy(s->ptr, p); - s->len = strlen(s->ptr); - return str; + return mrb_str_new_cstr(mrb, p); } mrb_value cfunc_pointer_offset(mrb_state *mrb, mrb_value self) { - struct cfunc_type_data *data = DATA_PTR(self); + struct cfunc_type_data *data = (struct cfunc_type_data*)DATA_PTR(self); mrb_int offset; + mrb_get_args(mrb, "i", &offset); if(offset == 0) { @@ -225,7 +222,7 @@ cfunc_pointer_offset(mrb_state *mrb, mrb_value self) } else { 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_cstr(mrb, "parent_pointer"), self); // keep for GC + mrb_obj_iv_set(mrb, mrb_obj_ptr(ptr), mrb_intern_lit(mrb, "parent_pointer"), self); // keep for GC return ptr; } } @@ -234,8 +231,10 @@ cfunc_pointer_offset(mrb_state *mrb, mrb_value self) mrb_value cfunc_pointer_addr(mrb_state *mrb, mrb_value self) { - struct cfunc_type_data *data = DATA_PTR(self); + struct cfunc_type_data *data = (struct cfunc_type_data*)DATA_PTR(self); void *ptr = NULL; + mrb_value obj; + if(data->refer) { ptr = data->value._pointer; } @@ -243,8 +242,8 @@ cfunc_pointer_addr(mrb_state *mrb, mrb_value self) ptr = &data->value._pointer; } - mrb_value obj = cfunc_pointer_new_with_pointer(mrb, ptr, false); - mrb_obj_iv_set(mrb, mrb_obj_ptr(obj), mrb_intern_cstr(mrb, "parent_pointer"), self); // keep for GC + obj = cfunc_pointer_new_with_pointer(mrb, ptr, false); + mrb_obj_iv_set(mrb, mrb_obj_ptr(obj), mrb_intern_lit(mrb, "parent_pointer"), self); // keep for GC return obj; } @@ -252,8 +251,18 @@ cfunc_pointer_addr(mrb_state *mrb, mrb_value self) static mrb_value cfunc_string_addr(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_cstr(mrb, "parent_pointer"), self); // keep for GC + mrb_value ptr; + // move string to heap + mrb_str_modify(mrb, RSTRING(self)); + if (RSTR_EMBED_P(RSTRING(self))) { + mrb_int const tmp_s = RSTRING_LEN(self); + mrb_str_resize(mrb, self, RSTRING_EMBED_LEN_MAX + 1); + mrb_str_resize(mrb, self, tmp_s); + mrb_assert(!RSTR_EMBED_P(RSTRING(self))); + } + + ptr = cfunc_pointer_new_with_pointer(mrb, &RSTRING(self)->as.heap.ptr, false); + mrb_obj_iv_set(mrb, mrb_obj_ptr(ptr), mrb_intern_lit(mrb, "parent_pointer"), self); // keep for GC return ptr; } @@ -295,7 +304,7 @@ static void cfunc_pointer_ffi_data_destructor(mrb_state *mrb, void *p_) { // ToDo: when *p_ was local scope variant? -}; +} const struct mrb_data_type cfunc_pointer_ffi_data_type = { @@ -306,10 +315,10 @@ const struct mrb_data_type cfunc_pointer_ffi_data_type = { static struct mrb_ffi_type pointer_mrb_ffi_type = { .name = "Pointer", .ffi_type_value = &ffi_type_pointer, - .mrb_to_c = &cfunc_pointer_mrb_to_c, - .c_to_mrb = &cfunc_pointer_c_to_mrb, + .data_to_mrb = &cfunc_pointer_data_to_mrb, .mrb_to_data = &cfunc_pointer_mrb_to_data, - .data_to_mrb = &cfunc_pointer_data_to_mrb + .c_to_mrb = &cfunc_pointer_c_to_mrb, + .mrb_to_c = &cfunc_pointer_mrb_to_c }; @@ -320,23 +329,23 @@ init_cfunc_pointer(mrb_state *mrb, struct RClass* module) struct RClass *pointer_class = mrb_define_class_under(mrb, module, "Pointer", state->type_class); mrb_value ffi_type = mrb_obj_value(Data_Wrap_Struct(mrb, mrb->object_class, &cfunc_pointer_ffi_data_type, &pointer_mrb_ffi_type)); - mrb_obj_iv_set(mrb, (struct RObject*)pointer_class, mrb_intern_cstr(mrb, "@ffi_type"), ffi_type); + mrb_obj_iv_set(mrb, (struct RObject*)pointer_class, mrb_intern_lit(mrb, "@ffi_type"), ffi_type); state->pointer_class = pointer_class; - mrb_define_class_method(mrb, pointer_class, "refer", cfunc_pointer_refer, ARGS_REQ(1)); - mrb_define_class_method(mrb, pointer_class, "malloc", cfunc_pointer_class_malloc, ARGS_REQ(1)); + mrb_define_class_method(mrb, pointer_class, "refer", cfunc_pointer_refer, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, pointer_class, "malloc", cfunc_pointer_class_malloc, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, pointer_class, "initialize", cfunc_pointer_initialize, ARGS_ANY()); - mrb_define_method(mrb, pointer_class, "realloc", cfunc_pointer_realloc, ARGS_REQ(1)); - mrb_define_method(mrb, pointer_class, "free", cfunc_pointer_free, ARGS_NONE()); - mrb_define_method(mrb, pointer_class, "inspect", cfunc_pointer_inspect, ARGS_NONE()); - mrb_define_method(mrb, pointer_class, "is_null?", cfunc_pointer_is_null, ARGS_NONE()); - mrb_define_method(mrb, pointer_class, "autofree", cfunc_pointer_autofree, ARGS_NONE()); + mrb_define_method(mrb, pointer_class, "initialize", cfunc_pointer_initialize, MRB_ARGS_ANY()); + mrb_define_method(mrb, pointer_class, "realloc", cfunc_pointer_realloc, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, pointer_class, "free", cfunc_pointer_free, MRB_ARGS_NONE()); + mrb_define_method(mrb, pointer_class, "inspect", cfunc_pointer_inspect, MRB_ARGS_NONE()); + mrb_define_method(mrb, pointer_class, "is_null?", cfunc_pointer_is_null, MRB_ARGS_NONE()); + mrb_define_method(mrb, pointer_class, "autofree", cfunc_pointer_autofree, MRB_ARGS_NONE()); - mrb_define_method(mrb, pointer_class, "offset", cfunc_pointer_offset, ARGS_REQ(1)); - mrb_define_method(mrb, pointer_class, "to_s", cfunc_pointer_to_s, ARGS_NONE()); + mrb_define_method(mrb, pointer_class, "offset", cfunc_pointer_offset, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, pointer_class, "to_s", cfunc_pointer_to_s, MRB_ARGS_NONE()); // add method to system classes - mrb_define_method(mrb, mrb->string_class, "addr", cfunc_string_addr, ARGS_NONE()); - mrb_obj_iv_set(mrb, (struct RObject *)mrb->string_class, mrb_intern_cstr(mrb, "@ffi_type"), ffi_type); + mrb_define_method(mrb, mrb->string_class, "addr", cfunc_string_addr, MRB_ARGS_NONE()); + mrb_obj_iv_set(mrb, (struct RObject *)mrb->string_class, mrb_intern_lit(mrb, "@ffi_type"), ffi_type); } diff --git a/src/cfunc_rubyvm.c b/src/cfunc_rubyvm.c index eedd6a6..48398d0 100644 --- a/src/cfunc_rubyvm.c +++ b/src/cfunc_rubyvm.c @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -40,13 +41,15 @@ struct task_arg { }; +enum queue_task_status { + queue_task_queued, + queue_task_running, + queue_task_finished +}; + struct queue_task { char* name; - enum queue_task_status { - queue_task_queued, - queue_task_running, - queue_task_finished - } status; + enum queue_task_status status; struct task_arg **args; int args_len; @@ -63,57 +66,59 @@ struct queue_task { struct task_arg* mrb_value_to_task_arg(mrb_state *mrb, mrb_value v) { - struct task_arg *arg = mrb_malloc(mrb, sizeof(struct task_arg)); + struct task_arg *arg = (struct task_arg*)mrb_malloc(mrb, sizeof(struct task_arg)); arg->tt = mrb_type(v); switch (mrb_type(v)) { case MRB_TT_FALSE: + if (mrb_nil_p(v)) { + arg->value.i = 0; + break; + } + /* fall through */ case MRB_TT_TRUE: + arg->value.i = 1; + break; case MRB_TT_FIXNUM: - arg->value.i = v.value.i; - break; + arg->value.i = mrb_integer(v); + break; case MRB_TT_FLOAT: - arg->value.f = v.value.f; - break; + arg->value.f = mrb_float(v); + break; case MRB_TT_SYMBOL: - { - size_t len; - const char* name = mrb_sym2name_len(mrb, v.value.sym, &len); - arg->value.string.len = len; - arg->value.string.ptr = mrb_malloc(mrb, len + 1); - memcpy(arg->value.string.ptr, name, len + 1); - } - break; + { + mrb_int len; + const char* name = mrb_sym_name_len(mrb, mrb_symbol(v), &len); + arg->value.string.len = len; + arg->value.string.ptr = (char*)mrb_malloc(mrb, len + 1); + memcpy(arg->value.string.ptr, name, len + 1); + } + break; case MRB_TT_STRING: - { - struct RString *str = mrb_str_ptr(v); - arg->value.string.len = str->len; - arg->value.string.ptr = mrb_malloc(mrb, arg->value.string.len+1); - memcpy(arg->value.string.ptr, str->ptr, arg->value.string.len+1); - } - break; + { + arg->value.string.len = RSTRING_LEN(v); + arg->value.string.ptr = (char*)mrb_malloc(mrb, arg->value.string.len+1); + memcpy(arg->value.string.ptr, RSTRING_PTR(v), arg->value.string.len+1); + } + break; case MRB_TT_ARRAY: - { - struct RArray *ary = mrb_ary_ptr(v); - - arg->value.array.len = ary->len; - arg->value.array.ptr = mrb_malloc(mrb, ary->len * sizeof(struct task_arg)); - - int i; - for(i=0; ilen; i++) { - arg->value.array.ptr[i] = mrb_value_to_task_arg(mrb, ary->ptr[i]); - } + { + arg->value.array.len = RARRAY_LEN(v); + arg->value.array.ptr = (struct task_arg**)mrb_malloc(mrb, RARRAY_LEN(v) * sizeof(struct task_arg*)); + for(int i=0; ivalue.array.ptr[i] = mrb_value_to_task_arg(mrb, RARRAY_PTR(v)[i]); } - break; + } + break; default: - mrb_free(mrb, arg); - mrb_raise(mrb, E_TYPE_ERROR, "cannot pass to other RubyVM"); - break; + mrb_free(mrb, arg); + mrb_raise(mrb, E_TYPE_ERROR, "cannot pass to other RubyVM"); + break; } return arg; @@ -124,41 +129,45 @@ mrb_value task_arg_to_mrb_value(mrb_state *mrb, struct task_arg* arg) { mrb_value v; - mrb_type(v) = arg->tt; switch (arg->tt) { case MRB_TT_FALSE: + if (arg->value.i == 0) + v = mrb_nil_value(); + else + v = mrb_false_value(); + break; case MRB_TT_TRUE: + v = mrb_true_value(); + break; case MRB_TT_FIXNUM: - v.value.i = arg->value.i; - break; + v = mrb_int_value(mrb, arg->value.i); + break; case MRB_TT_FLOAT: - v.value.f = arg->value.f; - break; + v = mrb_float_value(mrb, arg->value.i); + break; case MRB_TT_SYMBOL: - v.value.sym = mrb_intern_cstr(mrb, arg->value.string.ptr); - break; + v = mrb_symbol_value(mrb_intern_cstr(mrb, arg->value.string.ptr)); + break; case MRB_TT_STRING: - v = mrb_str_new(mrb, arg->value.string.ptr, arg->value.string.len); - break; + v = mrb_str_new(mrb, arg->value.string.ptr, arg->value.string.len); + break; case MRB_TT_ARRAY: - { - v = mrb_ary_new_capa(mrb, arg->value.array.len); - struct RArray *ary = mrb_ary_ptr(v); - ary->len = arg->value.array.len; - int i; - for(i=0; ivalue.array.len; i++) { - ary->ptr[i] = task_arg_to_mrb_value(mrb, arg->value.array.ptr[i]); - } + { + v = mrb_ary_new_capa(mrb, arg->value.array.len); + mrb_ary_resize(mrb, v, arg->value.array.len); + for(int i=0; ivalue.array.len; i++) { + mrb_ary_set(mrb, v, i, task_arg_to_mrb_value(mrb, arg->value.array.ptr[i])); } - break; + } + break; default: - mrb_raise(mrb, E_TYPE_ERROR, "cannot pass to other RubyVM"); - break; + mrb_raise(mrb, E_TYPE_ERROR, "cannot pass to other RubyVM"); + break; } return v; @@ -181,6 +190,7 @@ free_task_arg(mrb_state *mrb, struct task_arg* arg) int i; for(i=0; ivalue.array.len; i++) { free_task_arg(mrb, arg->value.array.ptr[i]); + mrb_free(mrb, arg->value.array.ptr[i]); } mrb_free(mrb, arg->value.array.ptr); } @@ -200,9 +210,13 @@ free_queue_task(mrb_state *mrb, struct queue_task* task) int i; for(i=0; iargs_len; ++i) { free_task_arg(mrb, task->args[i]); + mrb_free(mrb, task->args[i]); } mrb_free(mrb, task->args); + + free_task_arg(mrb, task->result); mrb_free(mrb, task->result); + mrb_free(mrb, task->name); mrb_free(mrb, task); } @@ -211,10 +225,25 @@ free_queue_task(mrb_state *mrb, struct queue_task* task) static void -cfunc_rubyvm_data_destructor(mrb_state *mrb, void *p_) +cfunc_rubyvm_data_destructor(mrb_state *mrb, void *p) { - // todo -}; + struct cfunc_rubyvm_data *vm = (struct cfunc_rubyvm_data*)p; + if (!vm) { return; } + + pthread_cancel(vm->thread); + + while (vm->queue->length != 0) { + struct queue_task *task = (struct queue_task*)vector_dequeue(vm->queue); + free_queue_task(mrb, task); + } + destroy_vector(vm->queue); + + mrb_close(vm->state); + + pthread_mutex_destroy(&vm->queue_mutex); + pthread_cond_destroy(&vm->queue_cond); + mrb_free(mrb, vm); +} const struct mrb_data_type cfunc_rubyvm_data_type = { @@ -228,7 +257,7 @@ static void cfunc_rubyvm_task_data_destructor(mrb_state *mrb, void *p) { free_queue_task(mrb, (struct queue_task*)p); -}; +} const struct mrb_data_type cfunc_rubyvm_task_data_type = { @@ -239,43 +268,51 @@ const struct mrb_data_type cfunc_rubyvm_task_data_type = { void* cfunc_rubyvm_open(void *args) { - struct cfunc_rubyvm_data *data = args; + struct cfunc_rubyvm_data *data = (struct cfunc_rubyvm_data*)args; mrb_state *mrb = mrb_open(); + mrb_irep* irep; data->state = mrb; - + #ifdef DISABLE_GEMS init_cfunc_module(mrb); #endif - mrb_irep* irep = mrb_read_irep(mrb, data->mrb_data); + irep = mrb_read_irep(mrb, data->mrb_data); + + mrb_toplevel_run(mrb, mrb_proc_new(mrb, irep)); - mrb_run(mrb, mrb_proc_new(mrb, irep), mrb_top_self(mrb)); + mrb_irep_decref(mrb, irep); if (mrb->exc) { return NULL; } while(true) { + struct queue_task *task; + mrb_sym taskname; + int args_len; + mrb_value *args; + int i; + mrb_value result; pthread_mutex_lock(&data->queue_mutex); while(data->queue->length == 0) { pthread_cond_wait(&data->queue_cond, &data->queue_mutex); } - - struct queue_task *task = vector_dequeue(data->queue); + + task = (struct queue_task*)vector_dequeue(data->queue); task->status = queue_task_running; - mrb_sym taskname = mrb_intern_cstr(mrb, task->name); + taskname = mrb_intern_cstr(mrb, task->name); - int args_len = task->args_len; - mrb_value *args = mrb_malloc(mrb, sizeof(struct task_arg) * task->args_len); - int i; + args_len = task->args_len; + args = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * task->args_len); for(i=0; iargs_len; ++i) { args[i] = task_arg_to_mrb_value(data->state, task->args[i]); } pthread_mutex_unlock(&data->queue_mutex); - mrb_value result = mrb_funcall_argv(mrb, mrb_top_self(data->state), taskname, args_len, args); + result = mrb_funcall_argv(mrb, mrb_top_self(data->state), taskname, args_len, args); task->result = mrb_value_to_task_arg(mrb, result); task->status = queue_task_finished; pthread_cond_signal(&task->sync_cond); @@ -291,13 +328,18 @@ cfunc_rubyvm_open(void *args) mrb_value cfunc_rubyvm_dispatch(mrb_state *mrb, mrb_value self) { - struct cfunc_rubyvm_data *data = mrb_data_check_get_ptr(mrb, self, &cfunc_rubyvm_data_type); + struct cfunc_rubyvm_data *data = (struct cfunc_rubyvm_data*)mrb_data_check_get_ptr(mrb, self, &cfunc_rubyvm_data_type); mrb_value name_obj, *args; - int args_len; + mrb_int args_len; + struct queue_task *task; + const char* name; + int name_len; + int i; + struct cfunc_state *state; mrb_get_args(mrb, "o*", &name_obj, &args, &args_len); - struct queue_task *task = mrb_malloc(mrb, sizeof(struct queue_task)); + task = (struct queue_task*)mrb_malloc(mrb, sizeof(struct queue_task)); task->refcount = 2; task->result = NULL; task->status = queue_task_queued; @@ -305,14 +347,13 @@ cfunc_rubyvm_dispatch(mrb_state *mrb, mrb_value self) pthread_mutex_init(&task->sync_mutex, NULL); pthread_cond_init(&task->sync_cond, NULL); - const char* name = mrb_string_value_ptr(mrb, name_obj); - int name_len = strlen(name); - task->name = mrb_malloc(mrb, name_len+1); + name = mrb_str_to_cstr(mrb, mrb_str_to_str(mrb, name_obj)); + name_len = strlen(name); + task->name = (char*)mrb_malloc(mrb, name_len+1); strncpy(task->name, name, name_len+1); task->args_len = args_len; - task->args = mrb_malloc(mrb, sizeof(struct task_arg) * task->args_len); - int i; + task->args = (struct task_arg**)mrb_malloc(mrb, sizeof(struct task_arg*) * task->args_len); for(i=0; iargs[i] = mrb_value_to_task_arg(mrb, args[i]); } @@ -322,7 +363,7 @@ cfunc_rubyvm_dispatch(mrb_state *mrb, mrb_value self) pthread_cond_signal(&data->queue_cond); pthread_mutex_unlock(&data->queue_mutex); - struct cfunc_state *state = cfunc_state(mrb, mrb_obj_ptr(self)->c); + state = cfunc_state(mrb, mrb_obj_ptr(self)->c); return mrb_obj_value((struct RObject *)Data_Wrap_Struct(mrb, state->rubyvm_task_class, &cfunc_rubyvm_task_data_type, task)); } @@ -330,7 +371,7 @@ cfunc_rubyvm_dispatch(mrb_state *mrb, mrb_value self) mrb_value cfunc_rubyvm_task_status(mrb_state *mrb, mrb_value self) { - struct queue_task *task = DATA_PTR(self); + struct queue_task *task = (struct queue_task*)DATA_PTR(self); return mrb_fixnum_value(task->status); } @@ -338,7 +379,7 @@ cfunc_rubyvm_task_status(mrb_state *mrb, mrb_value self) mrb_value cfunc_rubyvm_task_result(mrb_state *mrb, mrb_value self) { - struct queue_task *task = DATA_PTR(self); + struct queue_task *task = (struct queue_task*)DATA_PTR(self); return task_arg_to_mrb_value(mrb, task->result); } @@ -346,7 +387,7 @@ cfunc_rubyvm_task_result(mrb_state *mrb, mrb_value self) mrb_value cfunc_rubyvm_task_wait(mrb_state *mrb, mrb_value self) { - struct queue_task *task = DATA_PTR(self); + struct queue_task *task = (struct queue_task*)DATA_PTR(self); if(task->status == queue_task_queued || task->status == queue_task_running) { pthread_mutex_lock(&task->sync_mutex); pthread_cond_wait(&task->sync_cond, &task->sync_mutex); @@ -362,21 +403,24 @@ cfunc_rubyvm_class_thread(mrb_state *mrb, mrb_value klass) { // init bindle data with RubyVM object struct RClass *c = mrb_class_ptr(klass); - struct cfunc_rubyvm_data *data = mrb_malloc(mrb, sizeof(struct cfunc_rubyvm_data)); + struct cfunc_rubyvm_data *data = (struct cfunc_rubyvm_data*)mrb_malloc(mrb, sizeof(struct cfunc_rubyvm_data)); mrb_value self = mrb_obj_value((struct RObject *)Data_Wrap_Struct(mrb, c, &cfunc_rubyvm_data_type, data)); + void *dlh; // load script mrb_value filename, str; mrb_get_args(mrb, "S", &filename); - str = mrb_str_new_cstr(mrb, "mruby_data_"); + str = mrb_str_new_lit(mrb, "mruby_data_"); mrb_str_concat(mrb, str, mrb_str_new(mrb, RSTRING_PTR(filename), RSTRING_LEN(filename))); - void *dlh = dlopen(NULL, RTLD_LAZY); + dlh = dlopen(NULL, RTLD_LAZY); data->mrb_data = (const uint8_t *)dlsym(dlh, RSTRING_PTR(str)); if (!data->mrb_data) { dlclose(dlh); - mrb_raisef(mrb, E_SCRIPT_ERROR, "file '%s' not found.", RSTRING_PTR(str)); + mrb_free(mrb, data); + DATA_PTR(self) = NULL; + mrb_raisef(mrb, E_SCRIPT_ERROR, "file '%S' not found.", str); } // initial pthread @@ -393,20 +437,21 @@ void init_cfunc_rubyvm(mrb_state *mrb, struct RClass* module) { struct cfunc_state *state = cfunc_state(mrb, module); + struct RClass *rubyvm_task_class; struct RClass *rubyvm_class = mrb_define_class_under(mrb, module, "RubyVM", mrb->object_class); state->rubyvm_class = rubyvm_class; set_cfunc_state(mrb, rubyvm_class, state); - mrb_define_class_method(mrb, rubyvm_class, "thread", cfunc_rubyvm_class_thread, ARGS_REQ(1)); - mrb_define_method(mrb, rubyvm_class, "dispatch", cfunc_rubyvm_dispatch, ARGS_ANY()); + mrb_define_class_method(mrb, rubyvm_class, "thread", cfunc_rubyvm_class_thread, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, rubyvm_class, "dispatch", cfunc_rubyvm_dispatch, MRB_ARGS_ANY()); - struct RClass *rubyvm_task_class = mrb_define_class_under(mrb, rubyvm_class, "Task", mrb->object_class); + rubyvm_task_class = mrb_define_class_under(mrb, rubyvm_class, "Task", mrb->object_class); state->rubyvm_task_class = rubyvm_task_class; - mrb_define_method(mrb, rubyvm_task_class, "wait", cfunc_rubyvm_task_wait, ARGS_NONE()); - mrb_define_method(mrb, rubyvm_task_class, "result", cfunc_rubyvm_task_result, ARGS_NONE()); - mrb_define_method(mrb, rubyvm_task_class, "status", cfunc_rubyvm_task_status, ARGS_NONE()); + mrb_define_method(mrb, rubyvm_task_class, "wait", cfunc_rubyvm_task_wait, MRB_ARGS_NONE()); + mrb_define_method(mrb, rubyvm_task_class, "result", cfunc_rubyvm_task_result, MRB_ARGS_NONE()); + mrb_define_method(mrb, rubyvm_task_class, "status", cfunc_rubyvm_task_status, MRB_ARGS_NONE()); mrb_define_const(mrb, rubyvm_task_class, "QUEUED", mrb_fixnum_value(queue_task_queued)); mrb_define_const(mrb, rubyvm_task_class, "RUNNING", mrb_fixnum_value(queue_task_running)); diff --git a/src/cfunc_struct.c b/src/cfunc_struct.c index 913d452..a9f8491 100644 --- a/src/cfunc_struct.c +++ b/src/cfunc_struct.c @@ -20,10 +20,13 @@ #include static void -cfunc_struct_data_destructor(mrb_state *mrb, void *p_) +cfunc_struct_data_destructor(mrb_state *mrb, void *p) { - // todo -}; + struct mrb_ffi_type *mft = (struct mrb_ffi_type*)p; + mrb_free(mrb, mft->ffi_type_value->elements); + mrb_free(mrb, mft->ffi_type_value); + mrb_free(mrb, p); +} const struct mrb_data_type cfunc_struct_data_type = { @@ -50,29 +53,32 @@ mrb_value cfunc_struct_define_struct(mrb_state *mrb, mrb_value klass) { mrb_value elements_mrb; + ffi_type *tm_type; + ffi_type **tm_type_elements; + int i; + struct mrb_ffi_type *mft; + mrb_value __ffi_type; mrb_get_args(mrb, "A", &elements_mrb); - struct RArray *elements = mrb_ary_ptr(elements_mrb); - ffi_type *tm_type = mrb_malloc(mrb, sizeof(ffi_type)); + tm_type = (ffi_type*)mrb_malloc(mrb, sizeof(ffi_type)); tm_type->type = FFI_TYPE_STRUCT; tm_type->size = tm_type->alignment = 0; - ffi_type **tm_type_elements = mrb_malloc(mrb, sizeof(ffi_type*) * (elements->len + 1)); - int i; - for(i = 0; i < elements->len; ++i) { - tm_type_elements[i] = rclass_to_mrb_ffi_type(mrb, mrb_class_ptr(elements->ptr[i]))->ffi_type_value; + tm_type_elements = (ffi_type**)mrb_malloc(mrb, sizeof(ffi_type*) * (RARRAY_LEN(elements_mrb) + 1)); + for(i = 0; i < RARRAY_LEN(elements_mrb); ++i) { + tm_type_elements[i] = rclass_to_mrb_ffi_type(mrb, mrb_class_ptr(RARRAY_PTR(elements_mrb)[i]))->ffi_type_value; } tm_type_elements[i] = NULL; tm_type->elements = tm_type_elements; - struct mrb_ffi_type *mft = mrb_malloc(mrb, sizeof(struct mrb_ffi_type)); + mft = (struct mrb_ffi_type*)mrb_malloc(mrb, sizeof(struct mrb_ffi_type)); mft->name = mrb_class_name(mrb, mrb_class_ptr(klass)); mft->ffi_type_value = tm_type; mft->mrb_to_c = &cfunc_type_ffi_struct_mrb_to_c; mft->c_to_mrb = &cfunc_type_ffi_struct_c_to_mrb; - mrb_value __ffi_type = mrb_obj_value(Data_Wrap_Struct(mrb, mrb->object_class, &cfunc_struct_data_type, mft)); - mrb_obj_iv_set(mrb, (struct RObject*)(mrb_class_ptr(klass)), mrb_intern_cstr(mrb, "@ffi_type"), __ffi_type); + __ffi_type = mrb_obj_value(Data_Wrap_Struct(mrb, mrb->object_class, &cfunc_struct_data_type, mft)); + mrb_obj_iv_set(mrb, (struct RObject*)(mrb_class_ptr(klass)), mrb_intern_lit(mrb, "@ffi_type"), __ffi_type); return mrb_nil_value(); } @@ -86,5 +92,5 @@ init_cfunc_struct(mrb_state *mrb, struct RClass* module) set_cfunc_state(mrb, struct_class, state); state->struct_class = struct_class; - mrb_define_class_method(mrb, struct_class, "define_struct", cfunc_struct_define_struct, ARGS_REQ(1)); + mrb_define_class_method(mrb, struct_class, "define_struct", cfunc_struct_define_struct, MRB_ARGS_REQ(1)); } diff --git a/src/cfunc_type.c b/src/cfunc_type.c index d4f0768..c6cf3d6 100644 --- a/src/cfunc_type.c +++ b/src/cfunc_type.c @@ -44,13 +44,13 @@ rclass_to_mrb_ffi_type(mrb_state *mrb, struct RClass *cls) { struct RClass *cls_ = cls; while(cls) { - mrb_value ffi_type = mrb_obj_iv_get(mrb, (struct RObject*)cls, mrb_intern_cstr(mrb, "@ffi_type")); + mrb_value ffi_type = mrb_obj_iv_get(mrb, (struct RObject*)cls, mrb_intern_lit(mrb, "@ffi_type")); if(mrb_test(ffi_type)) { return (struct mrb_ffi_type*)DATA_PTR(ffi_type); } cls = cls->super; } - mrb_raisef(mrb, E_TYPE_ERROR, "%s cannot convert to C value", mrb_class_name(mrb, cls_)); + mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot convert to C value", mrb_class_path(mrb, cls_)); return NULL; } @@ -66,7 +66,7 @@ mrb_value_to_mrb_ffi_type(mrb_state *mrb, mrb_value val) case MRB_TT_FALSE: return rclass_to_mrb_ffi_type(mrb, cfunc_state(mrb, NULL)->sint32_class); default: - return rclass_to_mrb_ffi_type(mrb, mrb_object(val)->c); + return rclass_to_mrb_ffi_type(mrb, mrb_class(mrb, val)); } } @@ -75,17 +75,18 @@ static mrb_value cfunc_type_class_refer(mrb_state *mrb, mrb_value klass) { struct RClass *c = mrb_class_ptr(klass); - struct cfunc_type_data *data = mrb_malloc(mrb, sizeof(struct cfunc_type_data)); + struct cfunc_type_data *data = (struct cfunc_type_data*)mrb_malloc(mrb, sizeof(struct cfunc_type_data)); + mrb_value pointer; + struct RObject *obj; data->autofree = false; - mrb_value pointer; mrb_get_args(mrb, "o", &pointer); data->refer = true; data->value._pointer = cfunc_pointer_ptr(pointer); - struct RObject *obj = (struct RObject *)Data_Wrap_Struct(mrb, c, &cfunc_type_data, data); - mrb_obj_iv_set(mrb, obj, mrb_intern_cstr(mrb, "parent_pointer"), pointer); // keep for GC + obj = (struct RObject *)Data_Wrap_Struct(mrb, c, &cfunc_type_data, data); + mrb_obj_iv_set(mrb, obj, mrb_intern_lit(mrb, "parent_pointer"), pointer); // keep for GC return mrb_obj_value(obj); } @@ -94,9 +95,11 @@ static mrb_value cfunc_type_initialize(mrb_state *mrb, mrb_value self) { struct cfunc_type_data *data; - data = mrb_data_check_get_ptr(mrb, self, &cfunc_type_data); + mrb_value val; + int argc; + data = (struct cfunc_type_data*)mrb_data_check_get_ptr(mrb, self, &cfunc_type_data); if (!data) { - data = mrb_malloc(mrb, sizeof(struct cfunc_type_data)); + data = (struct cfunc_type_data*)mrb_malloc(mrb, sizeof(struct cfunc_type_data)); data->value._uint64 = 0; } data->autofree = false; @@ -104,10 +107,9 @@ cfunc_type_initialize(mrb_state *mrb, mrb_value self) DATA_PTR(self) = data; DATA_TYPE(self) = &cfunc_type_data; - mrb_value val; - int argc = mrb_get_args(mrb, "|o", &val); + argc = mrb_get_args(mrb, "|o", &val); if(argc > 0) { - struct mrb_ffi_type *mft = rclass_to_mrb_ffi_type(mrb, mrb_object(self)->c); + struct mrb_ffi_type *mft = rclass_to_mrb_ffi_type(mrb, mrb_class(mrb, self)); if(mft && mft->mrb_to_data) { mft->mrb_to_data(mrb, val, data); } @@ -140,9 +142,10 @@ mrb_value cfunc_type_class_get(mrb_state *mrb, mrb_value klass) { mrb_value pointer; + struct mrb_ffi_type *mft; mrb_get_args(mrb, "o", &pointer); - struct mrb_ffi_type *mft = rclass_to_mrb_ffi_type(mrb, mrb_class_ptr(klass)); + mft = rclass_to_mrb_ffi_type(mrb, mrb_class_ptr(klass)); return mft->c_to_mrb(mrb, cfunc_pointer_ptr(pointer)); } @@ -151,9 +154,10 @@ mrb_value cfunc_type_class_set(mrb_state *mrb, mrb_value klass) { mrb_value pointer, val; + struct mrb_ffi_type *mft; mrb_get_args(mrb, "oo", &pointer, &val); - struct mrb_ffi_type *mft = rclass_to_mrb_ffi_type(mrb, mrb_class_ptr(klass)); + mft = rclass_to_mrb_ffi_type(mrb, mrb_class_ptr(klass)); mft->mrb_to_c(mrb, val, cfunc_pointer_ptr(pointer)); return val; @@ -164,7 +168,7 @@ mrb_value cfunc_type_get_value(mrb_state *mrb, mrb_value self) { struct cfunc_type_data *data = (struct cfunc_type_data*)DATA_PTR(self); - struct mrb_ffi_type *mft = rclass_to_mrb_ffi_type(mrb, mrb_object(self)->c); + struct mrb_ffi_type *mft = rclass_to_mrb_ffi_type(mrb, mrb_class(mrb, self)); return mft->data_to_mrb(mrb, data); } @@ -173,10 +177,12 @@ mrb_value cfunc_type_set_value(mrb_state *mrb, mrb_value self) { mrb_value val; + struct cfunc_type_data *data; + struct mrb_ffi_type *mft; mrb_get_args(mrb, "o", &val); - struct cfunc_type_data *data = (struct cfunc_type_data*)DATA_PTR(self); - struct mrb_ffi_type *mft = rclass_to_mrb_ffi_type(mrb, mrb_object(self)->c); + data = (struct cfunc_type_data*)DATA_PTR(self); + mft = rclass_to_mrb_ffi_type(mrb, mrb_class(mrb, self)); mft->mrb_to_data(mrb, val, data); return val; @@ -196,7 +202,7 @@ cfunc_type_addr(mrb_state *mrb, mrb_value self) 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 + mrb_obj_iv_set(mrb, mrb_obj_ptr(ptr), mrb_intern_lit(mrb, "parent_pointer"), self); // keep for GC return ptr; } @@ -248,8 +254,8 @@ int64_t mrb_to_int64(mrb_state *mrb, mrb_value val) } default: - mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %s given", - mrb_obj_classname(mrb, val)); + mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %S given", + mrb_class_path(mrb, mrb_class(mrb, val))); } return 0; // can't reach here } @@ -291,8 +297,8 @@ mrb_float float_value(mrb_state *mrb, mrb_value val) } default: - mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %s given", - mrb_obj_classname(mrb, val)); + mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %S given", + mrb_class_path(mrb, mrb_class(mrb, val))); } return 0.0; // can't reach here } @@ -303,11 +309,12 @@ mrb_value cfunc_uint64_class_get(mrb_state *mrb, mrb_value klass) { mrb_value pointer; + uint64_t uint64; mrb_get_args(mrb, "o", &pointer); - uint64_t uint64 = *(uint64_t*)cfunc_pointer_ptr(pointer); + uint64 = *(uint64_t*)cfunc_pointer_ptr(pointer); - if(uint64 > UINT32_MAX) { + if(uint64 > MRB_INT_MAX) { mrb_raise(mrb, E_TYPE_ERROR, "too big. Use low, high"); } return int64_to_mrb(mrb, uint64); @@ -366,9 +373,10 @@ mrb_value cfunc_uint64_set_low(mrb_state *mrb, mrb_value self) { mrb_value val; + struct cfunc_type_data *data; mrb_get_args(mrb, "o", &val); - struct cfunc_type_data *data = (struct cfunc_type_data*)DATA_PTR(self); + data = (struct cfunc_type_data*)DATA_PTR(self); data->value._uint64 = (data->value._uint64 & 0xffffffff00000000) | (((uint64_t)mrb_to_int64(mrb, val)) & 0xffffffff); return val; } @@ -386,9 +394,10 @@ mrb_value cfunc_uint64_set_high(mrb_state *mrb, mrb_value self) { mrb_value val; + struct cfunc_type_data *data; mrb_get_args(mrb, "o", &val); - struct cfunc_type_data *data = (struct cfunc_type_data*)DATA_PTR(self); + data = (struct cfunc_type_data*)DATA_PTR(self); data->value._uint64 = (data->value._uint64 & 0x00000000ffffffff) | (((uint64_t)mrb_to_int64(mrb, val)) << 32); return val; @@ -412,11 +421,12 @@ mrb_value cfunc_sint64_class_get(mrb_state *mrb, mrb_value klass) { mrb_value pointer; + int64_t sint64; mrb_get_args(mrb, "o", &pointer); - int64_t sint64 = *(int64_t*)cfunc_pointer_ptr(pointer); + sint64 = *(int64_t*)cfunc_pointer_ptr(pointer); - if(sint64 > INT32_MAX || sint64 < INT32_MIN) { + if(sint64 > MRB_INT_MAX || sint64 < MRB_INT_MIN) { mrb_raise(mrb, E_TYPE_ERROR, "out of range. Use low, high"); } return int64_to_mrb(mrb, sint64); @@ -462,7 +472,7 @@ cfunc_nil_addr(mrb_state *mrb, mrb_value self) 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 + mrb_obj_iv_set(mrb, mrb_obj_ptr(ptr), mrb_intern_lit(mrb, "parent_pointer"), self); // keep for GC return ptr; } @@ -588,26 +598,26 @@ cfunc_type_ffi_##name##_mrb_to_data(mrb_state *mrb, mrb_value val, struct cfunc_ { \ .name = #name_, \ .ffi_type_value = &ffi_type_##type_, \ - .mrb_to_c = &cfunc_type_ffi_##type_##_mrb_to_c, \ - .c_to_mrb = &cfunc_type_ffi_##type_##_c_to_mrb, \ + .data_to_mrb = &cfunc_type_ffi_##type_##_data_to_mrb, \ .mrb_to_data = &cfunc_type_ffi_##type_##_mrb_to_data, \ - .data_to_mrb = &cfunc_type_ffi_##type_##_data_to_mrb \ + .c_to_mrb = &cfunc_type_ffi_##type_##_c_to_mrb, \ + .mrb_to_c = &cfunc_type_ffi_##type_##_mrb_to_c \ } -define_cfunc_type(sint8, &ffi_type_sint8, int8_t, int64_to_mrb, mrb_to_int64); -define_cfunc_type(uint8, &ffi_type_uint8, uint8_t, int64_to_mrb, mrb_to_int64); +define_cfunc_type(sint8, &ffi_type_sint8, int8_t, int64_to_mrb, mrb_to_int64) +define_cfunc_type(uint8, &ffi_type_uint8, uint8_t, int64_to_mrb, mrb_to_int64) -define_cfunc_type(sint16, &ffi_type_sint16, int16_t, int64_to_mrb, mrb_to_int64); -define_cfunc_type(uint16, &ffi_type_uint16, uint16_t, int64_to_mrb, mrb_to_int64); +define_cfunc_type(sint16, &ffi_type_sint16, int16_t, int64_to_mrb, mrb_to_int64) +define_cfunc_type(uint16, &ffi_type_uint16, uint16_t, int64_to_mrb, mrb_to_int64) -define_cfunc_type(sint32, &ffi_type_sint32, int32_t, int64_to_mrb, mrb_to_int64); -define_cfunc_type(uint32, &ffi_type_uint32, uint32_t, int64_to_mrb, mrb_to_int64); +define_cfunc_type(sint32, &ffi_type_sint32, int32_t, int64_to_mrb, mrb_to_int64) +define_cfunc_type(uint32, &ffi_type_uint32, uint32_t, int64_to_mrb, mrb_to_int64) -define_cfunc_type(sint64, &ffi_type_sint64, int64_t, int64_to_mrb, mrb_to_int64); -define_cfunc_type(uint64, &ffi_type_uint64, uint64_t, int64_to_mrb, mrb_to_int64); +define_cfunc_type(sint64, &ffi_type_sint64, int64_t, int64_to_mrb, mrb_to_int64) +define_cfunc_type(uint64, &ffi_type_uint64, uint64_t, int64_to_mrb, mrb_to_int64) -define_cfunc_type(float, &ffi_type_float, float, mrb_float_value, float_value); -define_cfunc_type(double, &ffi_type_double, double, mrb_float_value, float_value); +define_cfunc_type(float, &ffi_type_float, float, mrb_float_value, float_value) +define_cfunc_type(double, &ffi_type_double, double, mrb_float_value, float_value) static struct mrb_ffi_type types[] = { @@ -638,71 +648,73 @@ void init_cfunc_type(mrb_state *mrb, struct RClass* module) { struct cfunc_state *state = cfunc_state(mrb, module); struct RClass *type_class = mrb_define_class_under(mrb, module, "Type", mrb->object_class); + int ai, map_size, i; + mrb_value mod; + struct RClass *uint64_class, *sint64_class; MRB_SET_INSTANCE_TT(type_class, MRB_TT_DATA); state->type_class = type_class; set_cfunc_state(mrb, type_class, state); - int ai = mrb_gc_arena_save(mrb); - mrb_define_class_method(mrb, type_class, "refer", cfunc_type_class_refer, ARGS_REQ(1)); - mrb_define_class_method(mrb, type_class, "size", cfunc_type_size, ARGS_NONE()); - mrb_define_class_method(mrb, type_class, "align", cfunc_type_align, ARGS_NONE()); - mrb_define_class_method(mrb, type_class, "get", cfunc_type_class_get, ARGS_REQ(1)); - mrb_define_class_method(mrb, type_class, "set", cfunc_type_class_set, ARGS_REQ(2)); - - mrb_define_method(mrb, type_class, "initialize", cfunc_type_initialize, ARGS_ANY()); - mrb_define_method(mrb, type_class, "value", cfunc_type_get_value, ARGS_NONE()); - mrb_define_method(mrb, type_class, "value=", cfunc_type_set_value, ARGS_REQ(1)); - mrb_define_method(mrb, type_class, "addr", cfunc_type_addr, ARGS_NONE()); - mrb_define_method(mrb, type_class, "to_ffi_value", cfunc_type_addr, ARGS_NONE()); + ai = mrb_gc_arena_save(mrb); + mrb_define_class_method(mrb, type_class, "refer", cfunc_type_class_refer, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, type_class, "size", cfunc_type_size, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, type_class, "align", cfunc_type_align, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, type_class, "get", cfunc_type_class_get, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, type_class, "set", cfunc_type_class_set, MRB_ARGS_REQ(2)); + + mrb_define_method(mrb, type_class, "initialize", cfunc_type_initialize, MRB_ARGS_ANY()); + mrb_define_method(mrb, type_class, "value", cfunc_type_get_value, MRB_ARGS_NONE()); + mrb_define_method(mrb, type_class, "value=", cfunc_type_set_value, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, type_class, "addr", cfunc_type_addr, MRB_ARGS_NONE()); + mrb_define_method(mrb, type_class, "to_ffi_value", cfunc_type_addr, MRB_ARGS_NONE()); DONE; - int map_size = sizeof(types) / sizeof(struct mrb_ffi_type); - int i; + map_size = sizeof(types) / sizeof(struct mrb_ffi_type); for(i = 0; i < map_size; ++i) { struct RClass *new_class = mrb_define_class_under(mrb, module, types[i].name, type_class); mrb_value ffi_type = mrb_obj_value(Data_Wrap_Struct(mrb, mrb->object_class, &cfunc_class_ffi_data_type, &types[i])); - mrb_obj_iv_set(mrb, (struct RObject*)new_class, mrb_intern_cstr(mrb, "@ffi_type"), ffi_type); + mrb_obj_iv_set(mrb, (struct RObject*)new_class, mrb_intern_lit(mrb, "@ffi_type"), ffi_type); } DONE; - mrb_value mod = mrb_obj_value(module); - state->void_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_cstr(mrb, "Void"))); - state->uint8_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_cstr(mrb, "UInt8"))); - state->sint8_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_cstr(mrb, "SInt8"))); - state->uint16_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_cstr(mrb, "UInt16"))); - state->sint16_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_cstr(mrb, "SInt16"))); - state->uint32_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_cstr(mrb, "UInt32"))); - state->sint32_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_cstr(mrb, "SInt32"))); - state->uint64_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_cstr(mrb, "UInt64"))); - state->sint64_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_cstr(mrb, "SInt64"))); - state->float_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_cstr(mrb, "Float"))); - state->double_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_cstr(mrb, "Double"))); + mod = mrb_obj_value(module); + state->void_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_lit(mrb, "Void"))); + state->uint8_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_lit(mrb, "UInt8"))); + state->sint8_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_lit(mrb, "SInt8"))); + state->uint16_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_lit(mrb, "UInt16"))); + state->sint16_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_lit(mrb, "SInt16"))); + state->uint32_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_lit(mrb, "UInt32"))); + state->sint32_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_lit(mrb, "SInt32"))); + state->uint64_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_lit(mrb, "UInt64"))); + state->sint64_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_lit(mrb, "SInt64"))); + state->float_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_lit(mrb, "Float"))); + state->double_class = mrb_class_ptr(mrb_const_get(mrb, mod, mrb_intern_lit(mrb, "Double"))); DONE; - mrb_define_class_method(mrb, mrb->nil_class, "size", cfunc_nil_size, ARGS_NONE()); - mrb_define_class_method(mrb, mrb->nil_class, "align", cfunc_nil_align, ARGS_NONE()); + mrb_define_class_method(mrb, mrb->nil_class, "size", cfunc_nil_size, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, mrb->nil_class, "align", cfunc_nil_align, MRB_ARGS_NONE()); DONE; // uint64 specific - struct RClass *uint64_class = state->uint64_class; - mrb_define_class_method(mrb, uint64_class, "get", cfunc_uint64_class_get, ARGS_REQ(1)); - mrb_define_method(mrb, uint64_class, "value", cfunc_uint64_get_value, ARGS_NONE()); - mrb_define_method(mrb, uint64_class, "low", cfunc_uint64_get_low, ARGS_NONE()); - mrb_define_method(mrb, uint64_class, "low=", cfunc_uint64_set_low, ARGS_REQ(1)); - mrb_define_method(mrb, uint64_class, "high", cfunc_uint64_get_high, ARGS_NONE()); - mrb_define_method(mrb, uint64_class, "high=", cfunc_uint64_set_high, ARGS_REQ(1)); - mrb_define_method(mrb, uint64_class, "to_s", cfunc_uint64_to_s, ARGS_REQ(1)); - mrb_define_method(mrb, uint64_class, "divide", cfunc_uint64_divide, ARGS_REQ(1)); + uint64_class = state->uint64_class; + mrb_define_class_method(mrb, uint64_class, "get", cfunc_uint64_class_get, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, uint64_class, "value", cfunc_uint64_get_value, MRB_ARGS_NONE()); + mrb_define_method(mrb, uint64_class, "low", cfunc_uint64_get_low, MRB_ARGS_NONE()); + mrb_define_method(mrb, uint64_class, "low=", cfunc_uint64_set_low, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, uint64_class, "high", cfunc_uint64_get_high, MRB_ARGS_NONE()); + mrb_define_method(mrb, uint64_class, "high=", cfunc_uint64_set_high, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, uint64_class, "to_s", cfunc_uint64_to_s, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, uint64_class, "divide", cfunc_uint64_divide, MRB_ARGS_REQ(1)); DONE; // sint64 specific - struct RClass *sint64_class = state->sint64_class; - mrb_define_class_method(mrb, sint64_class, "get", cfunc_sint64_class_get, ARGS_REQ(1)); - mrb_define_method(mrb, sint64_class, "value", cfunc_sint64_get_value, ARGS_NONE()); - mrb_define_method(mrb, sint64_class, "low", cfunc_uint64_get_low, ARGS_NONE()); - mrb_define_method(mrb, sint64_class, "low=", cfunc_uint64_set_low, ARGS_REQ(1)); - mrb_define_method(mrb, sint64_class, "high", cfunc_uint64_get_high, ARGS_NONE()); - mrb_define_method(mrb, sint64_class, "high=", cfunc_uint64_set_high, ARGS_REQ(1)); - mrb_define_method(mrb, sint64_class, "to_s", cfunc_int64_to_s, ARGS_REQ(1)); + sint64_class = state->sint64_class; + mrb_define_class_method(mrb, sint64_class, "get", cfunc_sint64_class_get, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, sint64_class, "value", cfunc_sint64_get_value, MRB_ARGS_NONE()); + mrb_define_method(mrb, sint64_class, "low", cfunc_uint64_get_low, MRB_ARGS_NONE()); + mrb_define_method(mrb, sint64_class, "low=", cfunc_uint64_set_low, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, sint64_class, "high", cfunc_uint64_get_high, MRB_ARGS_NONE()); + mrb_define_method(mrb, sint64_class, "high=", cfunc_uint64_set_high, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, sint64_class, "to_s", cfunc_int64_to_s, MRB_ARGS_REQ(1)); DONE; } diff --git a/src/cfunc_utils.c b/src/cfunc_utils.c index 23ed150..890c6ef 100644 --- a/src/cfunc_utils.c +++ b/src/cfunc_utils.c @@ -25,5 +25,5 @@ cfunc_mrb_raise_without_jump(mrb_state *mrb, struct RClass *c, const char *fmt, if (n < 0) { n = 0; } - mrb->exc = (struct RObject*)mrb_object(mrb_exc_new(mrb, c, buf, n)); + mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, c, buf, n)); } diff --git a/src/vector.c b/src/vector.c index 7e6c41c..064290c 100644 --- a/src/vector.c +++ b/src/vector.c @@ -106,7 +106,7 @@ int vector_set(vector_p vec, size_t i, void* data){ } int vector_insert(vector_p vec, size_t i, void* data){ - int x; + size_t x; if(i > vec->length) return -1; @@ -121,7 +121,7 @@ int vector_insert(vector_p vec, size_t i, void* data){ } void vector_remove(vector_p vec, size_t i){ - int x; + size_t x; if(i >= vec->length) return; vec->length--; @@ -131,7 +131,7 @@ void vector_remove(vector_p vec, size_t i){ } int vector_index(vector_p vec, void* data){ - int x; + size_t x; for(x=0;xlength;++x){ if(vec->data[x] == data){ return x; @@ -146,7 +146,7 @@ void destroy_vector(vector_p vec){ } -void vector_swap(vector_p vec, int i, int j){ +void vector_swap(vector_p vec, size_t i, size_t j){ void * temp; if(i >= vec->length || j >= vec->length) diff --git a/test/func.c b/test/func.c index 6d1b9d8..9ed7086 100644 --- a/test/func.c +++ b/test/func.c @@ -10,7 +10,7 @@ struct STest { struct STest cfunc_test_func1(struct STest val) { val.z = val.x + val.y; return val; -}; +} struct STest2 { struct STest s; @@ -20,7 +20,7 @@ struct STest2 { struct STest2 cfunc_test_func2(struct STest2 val) { val.xx = (double)(val.s.x + val.s.y) / val.s.z; return val; -}; +} int cfunc_test_func3(int (*func)(uint32_t, uint32_t)) { return func(10, 20); @@ -33,3 +33,17 @@ int cfunc_test_func4(int a, int b) { int check_offset5(uint8_t *p1, uint8_t *p2) { return (p1+5)==p2 ? 1 : 0; } + +static int test_func(uint32_t v1, uint32_t v2) { return v1 + v2; } + +void test_func_ref() { + uint8_t a, b; + + struct STest v1 = {0, 0, 1}; + struct STest2 v2 = { {0, 0, 1}, 0.0 }; + cfunc_test_func1(v1); + cfunc_test_func2(v2); + cfunc_test_func3(test_func); + cfunc_test_func4(0, 1); + check_offset5(&a, &b); +} diff --git a/test/func.txt b/test/func.txt new file mode 100644 index 0000000..01f169b --- /dev/null +++ b/test/func.txt @@ -0,0 +1,8 @@ +{ + cfunc_test_func1; + cfunc_test_func2; + cfunc_test_func3; + cfunc_test_func4; + check_offset5; + mruby_data__rubyvm1; +}; diff --git a/test/main.c b/test/main.c index 40c4349..c91c85f 100644 --- a/test/main.c +++ b/test/main.c @@ -1,11 +1,16 @@ -#include "cfunc.h" - #include "mruby.h" #include "mruby/dump.h" #include "mruby/proc.h" #include "mruby/compile.h" +extern void test_func_ref(); +extern uint8_t const mruby_data__rubyvm1[]; + void mrb_mruby_cfunc_gem_test(mrb_state *mrb) { + uint8_t const *ptr; + test_func_ref(); + ptr = mruby_data__rubyvm1; + (void)ptr; } diff --git a/test/sint64.rb b/test/sint64.rb index bd0a43d..0ed7793 100644 --- a/test/sint64.rb +++ b/test/sint64.rb @@ -34,7 +34,7 @@ sint.value = -1 assert_equal 0xffffffff, sint.low assert_equal 0xffffffff, sint.high - assert_equal -1, CFunc::SInt64.get(sint_ptr) + assert_equal(-1, CFunc::SInt64.get(sint_ptr)) sint = CFunc::SInt64.new(CFunc::SInt16.new(16)) assert_equal 16, sint.value