summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/codeql-analysis.yml5
-rw-r--r--.github/workflows/oss-fuzz.yml2
-rw-r--r--build_config/dreamcast_shelf.rb73
-rw-r--r--doc/guides/compile.md2
-rw-r--r--doc/guides/link.md83
-rw-r--r--mrbgems/mruby-bin-config/mruby-config4
-rw-r--r--mrbgems/mruby-bin-config/mruby-config.bat12
-rw-r--r--mrbgems/mruby-catch/src/catch.c16
-rw-r--r--mrbgems/mruby-eval/src/eval.c9
-rw-r--r--mrbgems/mruby-method/src/method.c173
-rw-r--r--src/class.c27
-rw-r--r--src/proc.c19
-rw-r--r--src/vm.c33
-rw-r--r--tasks/libmruby.rake3
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);
diff --git a/src/vm.c b/src/vm.c
index edfb55586..dbc8bd88a 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -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 }