diff options
| -rw-r--r-- | .github/workflows/codeql-analysis.yml | 5 | ||||
| -rw-r--r-- | .github/workflows/oss-fuzz.yml | 2 | ||||
| -rw-r--r-- | build_config/dreamcast_shelf.rb | 73 | ||||
| -rw-r--r-- | doc/guides/compile.md | 2 | ||||
| -rw-r--r-- | doc/guides/link.md | 83 | ||||
| -rw-r--r-- | mrbgems/mruby-bin-config/mruby-config | 4 | ||||
| -rw-r--r-- | mrbgems/mruby-bin-config/mruby-config.bat | 12 | ||||
| -rw-r--r-- | mrbgems/mruby-catch/src/catch.c | 16 | ||||
| -rw-r--r-- | mrbgems/mruby-eval/src/eval.c | 9 | ||||
| -rw-r--r-- | mrbgems/mruby-method/src/method.c | 173 | ||||
| -rw-r--r-- | src/class.c | 27 | ||||
| -rw-r--r-- | src/proc.c | 19 | ||||
| -rw-r--r-- | src/vm.c | 33 | ||||
| -rw-r--r-- | tasks/libmruby.rake | 3 |
14 files changed, 355 insertions, 106 deletions
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index ea9f9bd8e..75f80a558 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -19,11 +19,6 @@ jobs: # a pull request then we can checkout the head. fetch-depth: 2 - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} - # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v1 diff --git a/.github/workflows/oss-fuzz.yml b/.github/workflows/oss-fuzz.yml index 0fd505624..e693b913d 100644 --- a/.github/workflows/oss-fuzz.yml +++ b/.github/workflows/oss-fuzz.yml @@ -16,7 +16,7 @@ jobs: fuzz-seconds: 600 dry-run: false - name: Upload Crash - uses: actions/[email protected] + uses: actions/[email protected] if: failure() with: name: artifacts diff --git a/build_config/dreamcast_shelf.rb b/build_config/dreamcast_shelf.rb index 7e7d6a52e..ee9b260a5 100644 --- a/build_config/dreamcast_shelf.rb +++ b/build_config/dreamcast_shelf.rb @@ -1,8 +1,14 @@ # Cross Compiling configuration for the Sega Dreamcast -# This configuration requires KallistiOS (KOS) -# https://dreamcast.wiki +# https://dreamcast.wiki/Using_Ruby_for_Sega_Dreamcast_development # -# Tested on GNU/Linux, MinGW-w64/MSYS2, Cygwin, macOS and MinGW/MSYS (see below) +# Requires KallistiOS (KOS) +# http://gamedev.allusion.net/softprj/kos/ +# +# Tested on GNU/Linux, macOS and Windows (through MinGW-w64/MSYS2, Cygwin and DreamSDK). +# DreamSDK is based on MinGW/MSYS: https://dreamsdk.org/ +# +# Input this command on the directory where mruby is installed: +# make MRUBY_CONFIG=dreamcast_shelf # MRuby::CrossBuild.new("dreamcast") do |conf| toolchain :gcc @@ -64,31 +70,50 @@ MRuby::CrossBuild.new("dreamcast") do |conf| conf.disable_cxx_exception # Gems from core - # removing mruby-io - conf.gem :core => "mruby-metaprog" - conf.gem :core => "mruby-pack" - conf.gem :core => "mruby-sprintf" - conf.gem :core => "mruby-print" - conf.gem :core => "mruby-math" - conf.gem :core => "mruby-time" - conf.gem :core => "mruby-struct" + # Some Gems are incompatible and were disabled. + + conf.gem :core => "mruby-array-ext" + conf.gem :core => "mruby-binding" + conf.gem :core => "mruby-binding-core" + conf.gem :core => "mruby-catch" + conf.gem :core => "mruby-class-ext" + conf.gem :core => "mruby-cmath" conf.gem :core => "mruby-compar-ext" + conf.gem :core => "mruby-compiler" + conf.gem :core => "mruby-complex" + conf.gem :core => "mruby-enum-chain" conf.gem :core => "mruby-enum-ext" - conf.gem :core => "mruby-string-ext" - conf.gem :core => "mruby-numeric-ext" - conf.gem :core => "mruby-array-ext" + conf.gem :core => "mruby-enum-lazy" + conf.gem :core => "mruby-enumerator" + conf.gem :core => "mruby-error" + conf.gem :core => "mruby-eval" + conf.gem :core => "mruby-exit" + conf.gem :core => "mruby-fiber" conf.gem :core => "mruby-hash-ext" - conf.gem :core => "mruby-range-ext" - conf.gem :core => "mruby-proc-ext" - conf.gem :core => "mruby-symbol-ext" - conf.gem :core => "mruby-random" + conf.gem :core => "mruby-inline-struct" +# conf.gem :core => "mruby-io" + conf.gem :core => "mruby-kernel-ext" + conf.gem :core => "mruby-math" + conf.gem :core => "mruby-metaprog" + conf.gem :core => "mruby-method" + conf.gem :core => "mruby-numeric-ext" conf.gem :core => "mruby-object-ext" conf.gem :core => "mruby-objectspace" - conf.gem :core => "mruby-fiber" - conf.gem :core => "mruby-enumerator" - conf.gem :core => "mruby-enum-lazy" + conf.gem :core => "mruby-os-memsize" + conf.gem :core => "mruby-pack" + conf.gem :core => "mruby-print" + conf.gem :core => "mruby-proc-binding" + conf.gem :core => "mruby-proc-ext" + conf.gem :core => "mruby-random" + conf.gem :core => "mruby-range-ext" + conf.gem :core => "mruby-rational" + conf.gem :core => "mruby-sleep" +# conf.gem :core => "mruby-socket" + conf.gem :core => "mruby-sprintf" + conf.gem :core => "mruby-string-ext" + conf.gem :core => "mruby-struct" + conf.gem :core => "mruby-symbol-ext" +# conf.gem :core => "mruby-test" +# conf.gem :core => "mruby-time" conf.gem :core => "mruby-toplevel-ext" - conf.gem :core => "mruby-kernel-ext" - conf.gem :core => "mruby-class-ext" - conf.gem :core => "mruby-compiler" end diff --git a/doc/guides/compile.md b/doc/guides/compile.md index 7a2ff2a44..740663ff8 100644 --- a/doc/guides/compile.md +++ b/doc/guides/compile.md @@ -527,7 +527,9 @@ convenience. `mruby-config` command prints the configuration used for `libmruby. $ mruby-config --help Usage: mruby-config [switches] switches: + --cc print compiler name --cflags print flags passed to compiler + --ld print linker name --ldflags print flags passed to linker --ldflags-before-libs print flags passed to linker before linked libraries --libs print linked libraries diff --git a/doc/guides/link.md b/doc/guides/link.md new file mode 100644 index 000000000..4bef8414c --- /dev/null +++ b/doc/guides/link.md @@ -0,0 +1,83 @@ +# Linking `libmruby` to your application + +You have two ways to link `libmruby` to your application. + +* using executable gem. +* using normal compilation process + +## Executable Gems + +If your application is relatively small, `mrbgem` is easier way to +create the executable. By tradition, the gem name start with +`mruby-bin-`, e.g. `mruby-bin-debugger`. + +### `mrbgem.rake` file + +The executable name is specified in `mrbgem.rake` file at the top of +your `mrbgem` directory. + +```ruby +MRuby::Gem::Specification.new('mruby-bin-example') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Example for executable command gem' + spec.bins = %w(mruby-example) # <- this is binary name +end +``` + +### Source tree structure + +The source file for the gem executable should be in +`<gem-name>/tools/<bin-name>`. Currently, we support C or C++ source code +(`.c`, `.cpp`, `.cxx`, `.cc`) for the executable. Ruby source files are not +supported. Put the functionality in the different gem and specify dependency to +it in `mrbgem.rake`. + +## Normal compilation process + +The `libmruby` is a normal library so that you can just link it to your +application. Specify proper compiler options (`-I` etc.) and linker options +(`-Lmruby` etc.) to compile and link your application. Specify those options in +your build script (e.g. `Makefile`). + +### Compiler options + +You need to specify compiler options that are compatible to mruby configuration, +for example: + +* `-I` to specify the place for mruby header files +* `-D` to specify mruby configuration macros + +To retrieve compiler options used to build `mruby`, you can use `mruby-config` +command with following options: + +* `--cc` compiler name +* `--cflags` options passed to compiler + +``` +$ mruby-config --cflags +-std=gnu99 -g -O3 -Wall -DMRB_GC_FIXED_ARENA -I/home/matz/work/mruby/include -I/home/matz/work/mruby/build/host/include +``` + +### Linker options + +Just like compiler options, you need to specify linker options that are +compatible to mruby configuration. + +To retrieve linker options, you can use `mruby-config` with following options: + +* `--ld` linker name +* `--ldflags` options passed to linker +* `--ldflags-before-libs` options passed to linker before linked libraries +* `--libs` linked libraries + +``` +$ mruby-config --ldflags +-L/home/matz/work/mruby/build/host/lib + +$ mruby-config --ldflags-before-libs +# <nothing in this case> + +$ mruby-config --libs +-lmruby -lm +``` diff --git a/mrbgems/mruby-bin-config/mruby-config b/mrbgems/mruby-bin-config/mruby-config index 8bbb4ecc6..3adda9e1a 100644 --- a/mrbgems/mruby-bin-config/mruby-config +++ b/mrbgems/mruby-bin-config/mruby-config @@ -4,7 +4,9 @@ print_help() { echo "Usage: mruby-config [switches]" echo " switches:" + echo " --cc print compiler name" echo " --cflags print flags passed to compiler" + echo " --ld print linker name" echo " --ldflags print flags passed to linker" echo " --ldflags-before-libs print flags passed to linker before linked libraries" echo " --libs print linked libraries" @@ -19,7 +21,9 @@ fi while [ $# -gt 0 ]; do case $1 in + --cc) echo MRUBY_CC;; --cflags) echo MRUBY_CFLAGS;; + --ld) echo MRUBY_LD;; --ldflags) echo MRUBY_LDFLAGS;; --ldflags-before-libs) echo MRUBY_LDFLAGS_BEFORE_LIBS;; --libs) echo MRUBY_LIBS;; diff --git a/mrbgems/mruby-bin-config/mruby-config.bat b/mrbgems/mruby-bin-config/mruby-config.bat index a1f7bfdd1..949fea06f 100644 --- a/mrbgems/mruby-bin-config/mruby-config.bat +++ b/mrbgems/mruby-bin-config/mruby-config.bat @@ -3,7 +3,9 @@ :top shift if "%0" equ "" goto :eof +if "%0" equ "--cc" goto cc if "%0" equ "--cflags" goto cflags +if "%0" equ "--ld" goto ld if "%0" equ "--ldflags" goto ldflags if "%0" equ "--ldflags-before-libs" goto ldflagsbeforelibs if "%0" equ "--libs" goto libs @@ -12,10 +14,18 @@ if "%0" equ "--help" goto showhelp echo Invalid Option goto :eof +:cc +echo MRUBY_CC +goto top + :cflags echo MRUBY_CFLAGS goto top +:ld +echo MRUBY_LD +goto top + :libs echo MRUBY_LIBS goto top @@ -35,7 +45,9 @@ goto top :showhelp echo Usage: mruby-config [switches] echo switches: +echo --cc print compiler name echo --cflags print flags passed to compiler +echo --ld print linker name echo --ldflags print flags passed to linker echo --ldflags-before-libs print flags passed to linker before linked libraries echo --libs print linked libraries diff --git a/mrbgems/mruby-catch/src/catch.c b/mrbgems/mruby-catch/src/catch.c index d910cac7f..148639530 100644 --- a/mrbgems/mruby-catch/src/catch.c +++ b/mrbgems/mruby-catch/src/catch.c @@ -61,21 +61,20 @@ static const mrb_irep catch_irep = { 29,0,3,1,0 }; -#define ID_PRESERVED_CATCH MRB_SYM(__preserved_catch_proc) +static const struct RProc catch_proc = { + NULL, NULL, MRB_TT_PROC, 7 /* GC_RED */, MRB_FL_OBJ_IS_FROZEN | MRB_PROC_SCOPE | MRB_PROC_STRICT, + { &catch_irep }, NULL, { NULL } +}; static const mrb_callinfo * find_catcher(mrb_state *mrb, mrb_value tag) { - mrb_value pval = mrb_obj_iv_get(mrb, (struct RObject *)mrb->kernel_module, ID_PRESERVED_CATCH); - mrb_assert(mrb_proc_p(pval)); - const struct RProc *proc = mrb_proc_ptr(pval); - const mrb_callinfo *ci = mrb->c->ci; size_t n = ci - mrb->c->cibase; ci--; for (; n > 0; n--, ci--) { const mrb_value *arg1 = ci->stack + 1; - if (ci->proc == proc && mrb_obj_eq(mrb, *arg1, tag)) { + if (ci->proc == &catch_proc && mrb_obj_eq(mrb, *arg1, tag)) { return ci; } } @@ -109,15 +108,12 @@ mrb_f_throw(mrb_state *mrb, mrb_value self) void mrb_mruby_catch_gem_init(mrb_state *mrb) { - struct RProc *p; mrb_method_t m; MRB_PRESYM_INIT_SYMBOLS(mrb, catch_syms_3); MRB_PRESYM_INIT_SYMBOLS(mrb, catch_syms_1); - p = mrb_proc_new(mrb, &catch_irep); - MRB_METHOD_FROM_PROC(m, p); + MRB_METHOD_FROM_PROC(m, &catch_proc); mrb_define_method_raw(mrb, mrb->kernel_module, MRB_SYM(catch), m); - mrb_obj_iv_set(mrb, (struct RObject *)mrb->kernel_module, ID_PRESERVED_CATCH, mrb_obj_value(p)); mrb_define_method(mrb, mrb->kernel_module, "throw", mrb_f_throw, MRB_ARGS_ARG(1,1)); } diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index 978d4fc30..508f5ffcb 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -131,15 +131,6 @@ exec_irep(mrb_state *mrb, mrb_value self, struct RProc *proc, mrb_func_t posthoo { /* no argument passed from eval() */ mrb->c->ci->argc = 0; - if (mrb->c->ci->acc < 0) { - ptrdiff_t cioff = mrb->c->ci - mrb->c->cibase; - mrb_value ret = mrb_top_run(mrb, proc, self, 0); - if (mrb->exc) { - mrb_exc_raise(mrb, mrb_obj_value(mrb->exc)); - } - mrb->c->ci = mrb->c->cibase + cioff; - return ret; - } /* clear block */ mrb->c->ci->stack[1] = mrb_nil_value(); return mrb_exec_irep(mrb, self, proc, posthook); diff --git a/mrbgems/mruby-method/src/method.c b/mrbgems/mruby-method/src/method.c index 8c8ebcd4f..02eddda9c 100644 --- a/mrbgems/mruby-method/src/method.c +++ b/mrbgems/mruby-method/src/method.c @@ -6,12 +6,126 @@ #include "mruby/string.h" #include "mruby/presym.h" +mrb_noreturn void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args); +mrb_value mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook); + +static mrb_value +args_shift(mrb_state *mrb) +{ + mrb_value *argv = mrb->c->ci->stack + 1; + + if (mrb->c->ci->argc > 0) { + mrb_value obj = argv[0]; + memmove(argv, argv + 1, (mrb->c->ci->argc + 1 /* block */ - 1 /* first value */) * sizeof(mrb_value)); + mrb->c->ci->argc--; + return obj; + } + else if (mrb->c->ci->argc < 0 && RARRAY_LEN(*argv) > 0) { + return mrb_ary_shift(mrb, *argv); + } + else { + mrb_argnum_error(mrb, 0, 1, -1); + return mrb_undef_value(); /* not reached */ + } +} + +static void +args_unshift(mrb_state *mrb, mrb_value obj) +{ + mrb_value *argv = mrb->c->ci->stack + 1; + + if (mrb->c->ci->argc >= 0) { + mrb_value block = argv[mrb->c->ci->argc]; + argv[0] = mrb_ary_new_from_values(mrb, mrb->c->ci->argc, argv); + argv[1] = block; + mrb->c->ci->argc = -1; + } + + mrb_ary_unshift(mrb, *argv, obj); +} + +static struct RProc* +method_missing_prepare(mrb_state *mrb, mrb_sym *mid, mrb_value recv, struct RClass **tc) +{ + const mrb_sym id_method_missing = MRB_SYM(method_missing); + + if (*mid == id_method_missing) { + method_missing: ; + int argc = mrb->c->ci->argc; + mrb_value *argv = mrb->c->ci->stack + 1; + mrb_value args = (argc < 0) ? argv[0] : mrb_ary_new_from_values(mrb, argc, argv); + mrb_method_missing(mrb, *mid, recv, args); + } + + *tc = mrb_class(mrb, recv); + mrb_method_t m = mrb_method_search_vm(mrb, tc, id_method_missing); + if (MRB_METHOD_UNDEF_P(m)) { + goto method_missing; + } + + struct RProc *proc; + if (MRB_METHOD_FUNC_P(m)) { + proc = mrb_proc_new_cfunc(mrb, MRB_METHOD_FUNC(m)); + MRB_PROC_SET_TARGET_CLASS(proc, *tc); + } + else { + proc = MRB_METHOD_PROC(m); + } + + args_unshift(mrb, mrb_symbol_value(*mid)); + *mid = id_method_missing; + + return proc; +} + static struct RObject * method_object_alloc(mrb_state *mrb, struct RClass *mclass) { return (struct RObject*)mrb_obj_alloc(mrb, MRB_TT_OBJECT, mclass); } +static struct RProc* +method_extract_proc(mrb_state *mrb, mrb_value self) +{ + mrb_value obj = mrb_iv_get(mrb, self, MRB_SYM(_proc)); + if (mrb_nil_p(obj)) { + return NULL; + } + else { + mrb_check_type(mrb, obj, MRB_TT_PROC); + return mrb_proc_ptr(obj); + } +} + +static mrb_value +method_extract_receiver(mrb_state *mrb, mrb_value self) +{ + return mrb_iv_get(mrb, self, MRB_SYM(_recv)); +} + +static mrb_sym +method_extract_mid(mrb_state *mrb, mrb_value self) +{ + mrb_value obj = mrb_iv_get(mrb, self, MRB_SYM(_name)); + mrb_check_type(mrb, obj, MRB_TT_SYMBOL); + return mrb_symbol(obj); +} + +static struct RClass* +method_extract_owner(mrb_state *mrb, mrb_value self) +{ + mrb_value obj = mrb_iv_get(mrb, self, MRB_SYM(_owner)); + switch (mrb_type(obj)) { + case MRB_TT_CLASS: + case MRB_TT_MODULE: + case MRB_TT_SCLASS: + break; + default: + mrb_raise(mrb, E_TYPE_ERROR, "not class/module as owner of method object"); + } + return mrb_class_ptr(obj); +} + static void bind_check(mrb_state *mrb, mrb_value recv, mrb_value owner) { @@ -109,61 +223,40 @@ method_eql(mrb_state *mrb, mrb_value self) #undef IV_GET static mrb_value -mcall(mrb_state *mrb, mrb_value recv, mrb_value proc, mrb_value name, struct RClass *owner, - mrb_int argc, const mrb_value *argv, mrb_value block) +mcall(mrb_state *mrb, mrb_value self, mrb_value recv) { - mrb_value ret; - mrb_sym orig_mid = mrb->c->ci->mid; + struct RProc *proc = method_extract_proc(mrb, self); + mrb_sym mid = method_extract_mid(mrb, self); + struct RClass *tc = method_extract_owner(mrb, self); - mrb->c->ci->mid = mrb_symbol(name); - if (mrb_nil_p(proc)) { - mrb_value missing_argv = mrb_ary_new_from_values(mrb, argc, argv); - mrb_ary_unshift(mrb, missing_argv, name); - ret = mrb_funcall_argv(mrb, recv, MRB_SYM(method_missing), argc + 1, RARRAY_PTR(missing_argv)); - } - else if (!mrb_nil_p(block)) { - /* - workaround since `mrb_yield_with_class` does not support passing block as parameter - need new API that initializes `mrb->c->stack[argc+1]` with block passed by argument - */ - ret = mrb_funcall_with_block(mrb, recv, mrb_symbol(name), argc, argv, block); + if (mrb_undef_p(recv)) { + recv = method_extract_receiver(mrb, self); } else { - ret = mrb_yield_with_class(mrb, proc, argc, argv, recv, owner); + bind_check(mrb, recv, mrb_obj_value(tc)); } - mrb->c->ci->mid = orig_mid; - return ret; + + if (!proc) { + proc = method_missing_prepare(mrb, &mid, recv, &tc); + } + mrb->c->ci->mid = mid; + mrb->c->ci->u.target_class = tc; + + return mrb_exec_irep(mrb, recv, proc, NULL); } static mrb_value method_call(mrb_state *mrb, mrb_value self) { - mrb_value proc = mrb_iv_get(mrb, self, MRB_SYM(_proc)); - mrb_value name = mrb_iv_get(mrb, self, MRB_SYM(_name)); - mrb_value recv = mrb_iv_get(mrb, self, MRB_SYM(_recv)); - struct RClass *owner = mrb_class_ptr(mrb_iv_get(mrb, self, MRB_SYM(_owner))); - mrb_int argc; - const mrb_value *argv; - mrb_value block; - - mrb_get_args(mrb, "*&", &argv, &argc, &block); - return mcall(mrb, recv, proc, name, owner, argc, argv, block); + return mcall(mrb, self, mrb_undef_value()); } static mrb_value method_bcall(mrb_state *mrb, mrb_value self) { - mrb_value proc = mrb_iv_get(mrb, self, MRB_SYM(_proc)); - mrb_value name = mrb_iv_get(mrb, self, MRB_SYM(_name)); - mrb_value recv = mrb_iv_get(mrb, self, MRB_SYM(_recv)); - mrb_value owner = mrb_iv_get(mrb, self, MRB_SYM(_owner)); - mrb_int argc; - const mrb_value *argv; - mrb_value block; - - mrb_get_args(mrb, "o*&", &recv, &argv, &argc, &block); - bind_check(mrb, recv, owner); - return mcall(mrb, recv, proc, name, mrb_class_ptr(owner), argc, argv, block); + mrb_value recv = args_shift(mrb); + mrb_gc_protect(mrb, recv); + return mcall(mrb, self, recv); } static mrb_value diff --git a/src/class.c b/src/class.c index 09e52d24a..33a65f7d6 100644 --- a/src/class.c +++ b/src/class.c @@ -736,11 +736,17 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_method_ ptr.proc = p; if (p) { - p->flags |= MRB_PROC_SCOPE; - p->c = NULL; - mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)p); - if (!MRB_PROC_ENV_P(p)) { - MRB_PROC_SET_TARGET_CLASS(p, c); + if (p->color != 7 /* GC_RED */) { + p->flags |= MRB_PROC_SCOPE; + p->c = NULL; + mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)p); + if (!MRB_PROC_ENV_P(p)) { + MRB_PROC_SET_TARGET_CLASS(p, c); + } + } + else { + mrb_assert(MRB_FROZEN_P(p) && MRB_PROC_SCOPE_P(p)); + mrb_assert(p->c == NULL && p->upper == NULL && p->e.target_class == NULL); } } } @@ -2199,7 +2205,7 @@ mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b) if (MRB_PROC_ENV_P(p)) { MRB_PROC_ENV(p)->mid = b; } - else { + else if (p->color != 7 /* GC_RED */) { struct RClass *tc = MRB_PROC_TARGET_CLASS(p); struct REnv *e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, NULL); @@ -2812,15 +2818,18 @@ static const mrb_irep new_irep = { sizeof(new_iseq), 0, 2, 0, 0, }; +static const struct RProc new_proc = { + NULL, NULL, MRB_TT_PROC, 7 /* GC_RED */, MRB_FL_OBJ_IS_FROZEN | MRB_PROC_SCOPE | MRB_PROC_STRICT, + { &new_irep }, NULL, { NULL } +}; + static void init_class_new(mrb_state *mrb, struct RClass *cls) { - struct RProc *p; mrb_method_t m; MRB_PRESYM_INIT_SYMBOLS(mrb, new_syms); - p = mrb_proc_new(mrb, &new_irep); - MRB_METHOD_FROM_PROC(m, p); + MRB_METHOD_FROM_PROC(m, &new_proc); mrb_define_method_raw(mrb, cls, MRB_SYM(new), m); } diff --git a/src/proc.c b/src/proc.c index 4a202525c..5419ac002 100644 --- a/src/proc.c +++ b/src/proc.c @@ -35,6 +35,11 @@ static const mrb_irep call_irep = { 0, /* refcnt */ }; +static const struct RProc call_proc = { + NULL, NULL, MRB_TT_PROC, 7 /* GC_RED */, MRB_FL_OBJ_IS_FROZEN | MRB_PROC_SCOPE | MRB_PROC_STRICT, + { &call_irep }, NULL, { NULL } +}; + struct RProc* mrb_proc_new(mrb_state *mrb, const mrb_irep *irep) { @@ -46,7 +51,15 @@ mrb_proc_new(mrb_state *mrb, const mrb_irep *irep) struct RClass *tc = NULL; if (ci->proc) { - tc = MRB_PROC_TARGET_CLASS(ci->proc); + if (ci->proc->color != 7 /* GC_RED */) { + tc = MRB_PROC_TARGET_CLASS(ci->proc); + } + else { + tc = mrb_vm_ci_target_class(ci); + if (tc && tc->tt == MRB_TT_ICLASS) { + tc = tc->c; + } + } } if (tc == NULL) { tc = mrb_vm_ci_target_class(ci); @@ -413,15 +426,13 @@ mrb_proc_merge_lvar(mrb_state *mrb, mrb_irep *irep, struct REnv *env, int num, c void mrb_init_proc(mrb_state *mrb) { - struct RProc *p; mrb_method_t m; mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_NONE()|MRB_ARGS_BLOCK()); mrb_define_method(mrb, mrb->proc_class, "initialize_copy", mrb_proc_init_copy, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mrb->proc_class, "arity", proc_arity, MRB_ARGS_NONE()); - p = mrb_proc_new(mrb, &call_irep); - MRB_METHOD_FROM_PROC(m, p); + MRB_METHOD_FROM_PROC(m, &call_proc); mrb_define_method_raw(mrb, mrb->proc_class, MRB_SYM(call), m); mrb_define_method_raw(mrb, mrb->proc_class, MRB_OPSYM(aref), m); @@ -543,8 +543,8 @@ mrb_exec_irep_prepare_posthook(mrb_state *mrb, mrb_callinfo *ci, int nregs, mrb_ * * However, if `proc` is a C function, it will be ignored. */ -mrb_value -mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook) +static mrb_value +mrb_exec_irep_vm(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook) { mrb_callinfo *ci = mrb->c->ci; int keep, nregs; @@ -575,6 +575,31 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t postho return self; } +mrb_value +mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook) +{ + mrb_callinfo *ci = mrb->c->ci; + if (ci->acc >= 0) { + return mrb_exec_irep_vm(mrb, self, p, posthook); + } + else { + mrb_value ret; + if (MRB_PROC_CFUNC_P(p)) { + cipush(mrb, 0, CI_ACC_DIRECT, mrb_vm_ci_target_class(ci), p, ci->mid, ci->argc); + ret = MRB_PROC_CFUNC(p)(mrb, self); + cipop(mrb); + } + else { + int keep = (ci->argc < 0 ? 1 : ci->argc) + 2 /* receiver + block */; + ret = mrb_top_run(mrb, p, self, keep); + } + if (mrb->exc && mrb->jmp) { + mrb_exc_raise(mrb, mrb_obj_value(mrb->exc)); + } + return ret; + } +} + /* 15.3.1.3.4 */ /* 15.3.1.3.44 */ /* @@ -638,7 +663,7 @@ mrb_f_send(mrb_state *mrb, mrb_value self) } return MRB_METHOD_CFUNC(m)(mrb, self); } - return mrb_exec_irep(mrb, self, MRB_METHOD_PROC(m), NULL); + return mrb_exec_irep_vm(mrb, self, MRB_METHOD_PROC(m), NULL); } static mrb_value @@ -826,7 +851,7 @@ mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const mrb->c->ci->stack[1] = mrb_ary_new_from_values(mrb, argc, argv); mrb->c->ci->stack[2] = mrb_nil_value(); ci->argc = -1; - return mrb_exec_irep(mrb, self, p, NULL); + return mrb_exec_irep_vm(mrb, self, p, NULL); } static struct RBreak* diff --git a/tasks/libmruby.rake b/tasks/libmruby.rake index 8cdb4ca2e..9a7a57ff7 100644 --- a/tasks/libmruby.rake +++ b/tasks/libmruby.rake @@ -16,6 +16,9 @@ MRuby.each_target do open(t.name, 'w') do |f| f.puts "MRUBY_CFLAGS = #{cc.all_flags}" + f.puts "MRUBY_CC = #{cc.command}" + f.puts "MRUBY_LD = #{linker.command}" + libgems = gems.reject{|g| g.bin?} gem_flags = libgems.map {|g| g.linker.flags } gem_library_paths = libgems.map {|g| g.linker.library_paths } |
