summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backtrace.c223
-rw-r--r--src/error.c87
-rw-r--r--src/gc.c26
-rw-r--r--src/hash.c6
-rw-r--r--src/load.c8
-rw-r--r--src/state.c3
-rw-r--r--src/string.c19
-rw-r--r--src/symbol.c4
-rw-r--r--src/vm.c108
9 files changed, 402 insertions, 82 deletions
diff --git a/src/backtrace.c b/src/backtrace.c
index 80a5e2935..2fce6645d 100644
--- a/src/backtrace.c
+++ b/src/backtrace.c
@@ -14,6 +14,15 @@
#include <mruby/error.h>
#include <mruby/numeric.h>
+struct backtrace_location_raw {
+ int i;
+ int lineno;
+ const char *filename;
+ mrb_sym method_id;
+ const char *sep;
+ struct RClass *klass;
+};
+
struct backtrace_location {
int i;
int lineno;
@@ -23,6 +32,7 @@ struct backtrace_location {
const char *class_name;
};
+typedef void (*each_backtrace_func)(mrb_state*, struct backtrace_location_raw*, void*);
typedef void (*output_stream_func)(mrb_state*, struct backtrace_location*, void*);
#ifndef MRB_DISABLE_STDIO
@@ -89,7 +99,7 @@ get_backtrace_i(mrb_state *mrb, struct backtrace_location *loc, void *data)
}
static void
-output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_func func, void *data)
+each_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, each_backtrace_func func, void *data)
{
int i;
@@ -97,7 +107,7 @@ output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_fun
ciidx = 10; /* ciidx is broken... */
for (i = ciidx; i >= 0; i--) {
- struct backtrace_location loc;
+ struct backtrace_location_raw loc;
mrb_callinfo *ci;
mrb_irep *irep;
mrb_code *pc;
@@ -134,13 +144,43 @@ output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_fun
loc.filename = "(unknown)";
}
- loc.method = mrb_sym2name(mrb, ci->mid);
- loc.class_name = mrb_class_name(mrb, ci->proc->target_class);
+ loc.method_id = ci->mid;
+ loc.klass = ci->proc->target_class;
loc.i = i;
func(mrb, &loc, data);
}
}
+struct output_backtrace_args {
+ output_stream_func func;
+ void *data;
+};
+
+static void
+output_backtrace_i(mrb_state *mrb, struct backtrace_location_raw *loc_raw, void *data)
+{
+ struct backtrace_location loc;
+ struct output_backtrace_args *args = data;
+
+ loc.i = loc_raw->i;
+ loc.lineno = loc_raw->lineno;
+ loc.filename = loc_raw->filename;
+ loc.method = mrb_sym2name(mrb, loc_raw->method_id);
+ loc.sep = loc_raw->sep;
+ loc.class_name = mrb_class_name(mrb, loc_raw->klass);
+
+ args->func(mrb, &loc, args->data);
+}
+
+static void
+output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_func func, void *data)
+{
+ struct output_backtrace_args args;
+ args.func = func;
+ args.data = data;
+ each_backtrace(mrb, ciidx, pc0, output_backtrace_i, &args);
+}
+
static void
exc_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func func, void *stream)
{
@@ -167,18 +207,76 @@ exc_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func fun
#ifndef MRB_DISABLE_STDIO
+static void
+print_backtrace(mrb_state *mrb, mrb_value backtrace)
+{
+ int i, n;
+ FILE *stream = stderr;
+
+ fprintf(stream, "trace:\n");
+
+ n = RARRAY_LEN(backtrace);
+ for (i = 0; i < n; i++) {
+ mrb_value entry = RARRAY_PTR(backtrace)[i];
+
+ fprintf(stream, "\t[%d] %.*s\n", i, (int)RSTRING_LEN(entry), RSTRING_PTR(entry));
+ }
+}
+
+static void
+print_backtrace_saved(mrb_state *mrb)
+{
+ int i;
+ FILE *stream = stderr;
+
+ fprintf(stream, "trace:\n");
+ for (i = 0; i < mrb->backtrace.n; i++) {
+ mrb_backtrace_entry *entry;
+
+ entry = &(mrb->backtrace.entries[i]);
+ fprintf(stream, "\t[%d] %s:%d", i, entry->filename, entry->lineno);
+
+ if (entry->method_id != 0) {
+ const char *method_name;
+
+ method_name = mrb_sym2name(mrb, entry->method_id);
+ if (entry->klass) {
+ fprintf(stream, ":in %s%s%s",
+ mrb_class_name(mrb, entry->klass),
+ entry->sep,
+ method_name);
+ }
+ else {
+ fprintf(stream, ":in %s", method_name);
+ }
+ }
+
+ fprintf(stream, "\n");
+ }
+}
+
MRB_API void
mrb_print_backtrace(mrb_state *mrb)
{
- struct print_backtrace_args args;
+ mrb_value backtrace;
if (!mrb->exc || mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), E_SYSSTACK_ERROR)) {
return;
}
- args.stream = stderr;
- args.tracehead = TRUE;
- exc_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)&args);
+ backtrace = mrb_obj_iv_get(mrb, mrb->exc, mrb_intern_lit(mrb, "backtrace"));
+ if (!mrb_nil_p(backtrace)) {
+ print_backtrace(mrb, backtrace);
+ }
+ else if (mrb->backtrace.n > 0) {
+ print_backtrace_saved(mrb);
+ }
+ else {
+ struct print_backtrace_args args;
+ args.stream = stderr;
+ args.tracehead = TRUE;
+ exc_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)&args);
+ }
}
#else
@@ -215,3 +313,112 @@ mrb_get_backtrace(mrb_state *mrb)
return ary;
}
+
+void
+mrb_free_backtrace(mrb_state *mrb)
+{
+ mrb->backtrace.exc = 0;
+ mrb->backtrace.n = 0;
+ mrb->backtrace.n_allocated = 0;
+ mrb_free(mrb, mrb->backtrace.entries);
+}
+
+static void
+save_backtrace_i(mrb_state *mrb,
+ struct backtrace_location_raw *loc_raw,
+ void *data)
+{
+ mrb_backtrace_entry *entry;
+
+ if (loc_raw->i >= mrb->backtrace.n_allocated) {
+ int new_n_allocated;
+ if (mrb->backtrace.n_allocated == 0) {
+ new_n_allocated = 8;
+ }
+ else {
+ new_n_allocated = mrb->backtrace.n_allocated * 2;
+ }
+ mrb->backtrace.entries =
+ mrb_realloc(mrb,
+ mrb->backtrace.entries,
+ sizeof(mrb_backtrace_entry) * new_n_allocated);
+ mrb->backtrace.n_allocated = new_n_allocated;
+ }
+
+ entry = &mrb->backtrace.entries[mrb->backtrace.n];
+ entry->filename = loc_raw->filename;
+ entry->lineno = loc_raw->lineno;
+ entry->klass = loc_raw->klass;
+ entry->sep = loc_raw->sep;
+ entry->method_id = loc_raw->method_id;
+
+ mrb->backtrace.n++;
+}
+
+void
+mrb_save_backtrace(mrb_state *mrb)
+{
+ mrb_value lastpc;
+ mrb_code *code;
+ mrb_int ciidx;
+
+ mrb->backtrace.n = 0;
+ mrb->backtrace.exc = 0;
+
+ if (!mrb->exc)
+ return;
+
+ mrb->backtrace.exc = mrb->exc;
+
+ lastpc = mrb_obj_iv_get(mrb, mrb->exc, mrb_intern_lit(mrb, "lastpc"));
+ if (mrb_nil_p(lastpc)) {
+ code = NULL;
+ }
+ else {
+ code = (mrb_code*)mrb_cptr(lastpc);
+ }
+
+ ciidx = mrb_fixnum(mrb_obj_iv_get(mrb, mrb->exc, mrb_intern_lit(mrb, "ciidx")));
+
+ each_backtrace(mrb, ciidx, code, save_backtrace_i, NULL);
+}
+
+mrb_value
+mrb_restore_backtrace(mrb_state *mrb)
+{
+ int i;
+ mrb_value backtrace;
+
+ backtrace = mrb_ary_new(mrb);
+ for (i = 0; i < mrb->backtrace.n; i++) {
+ int ai;
+ mrb_backtrace_entry *entry;
+ mrb_value mrb_entry;
+
+ ai = mrb_gc_arena_save(mrb);
+ entry = &(mrb->backtrace.entries[i]);
+
+ mrb_entry = mrb_str_new_cstr(mrb, entry->filename);
+ mrb_str_cat_lit(mrb, mrb_entry, ":");
+ mrb_str_concat(mrb, mrb_entry,
+ mrb_fixnum_to_str(mrb,
+ mrb_fixnum_value(entry->lineno),
+ 10));
+ if (entry->method_id != 0) {
+ mrb_str_cat_lit(mrb, mrb_entry, ":in ");
+
+ if (entry->klass) {
+ mrb_str_cat_cstr(mrb, mrb_entry, mrb_class_name(mrb, entry->klass));
+ mrb_str_cat_cstr(mrb, mrb_entry, entry->sep);
+ }
+
+ mrb_str_cat_cstr(mrb, mrb_entry, mrb_sym2name(mrb, entry->method_id));
+ }
+
+ mrb_ary_push(mrb, backtrace, mrb_entry);
+
+ mrb_gc_arena_restore(mrb, ai);
+ }
+
+ return backtrace;
+}
diff --git a/src/error.c b/src/error.c
index 15a969d93..14e4ab4d3 100644
--- a/src/error.c
+++ b/src/error.c
@@ -174,6 +174,42 @@ exc_inspect(mrb_state *mrb, mrb_value exc)
return str;
}
+void mrb_save_backtrace(mrb_state *mrb);
+mrb_value mrb_restore_backtrace(mrb_state *mrb);
+
+static mrb_value
+exc_get_backtrace(mrb_state *mrb, mrb_value exc)
+{
+ mrb_sym attr_name;
+ mrb_value backtrace;
+
+ attr_name = mrb_intern_lit(mrb, "backtrace");
+ backtrace = mrb_iv_get(mrb, exc, attr_name);
+ if (mrb_nil_p(backtrace)) {
+ if (mrb_obj_ptr(exc) == mrb->backtrace.exc && mrb->backtrace.n > 0) {
+ backtrace = mrb_restore_backtrace(mrb);
+ mrb->backtrace.n = 0;
+ mrb->backtrace.exc = 0;
+ }
+ else {
+ backtrace = mrb_exc_backtrace(mrb, exc);
+ }
+ mrb_iv_set(mrb, exc, attr_name, backtrace);
+ }
+
+ return backtrace;
+}
+
+static mrb_value
+exc_set_backtrace(mrb_state *mrb, mrb_value exc)
+{
+ mrb_value backtrace;
+
+ mrb_get_args(mrb, "o", &backtrace);
+ mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "backtrace"), backtrace);
+
+ return backtrace;
+}
static void
exc_debug_info(mrb_state *mrb, struct RObject *exc)
@@ -202,12 +238,52 @@ exc_debug_info(mrb_state *mrb, struct RObject *exc)
}
}
+static void
+set_backtrace(mrb_state *mrb, mrb_value info, mrb_value bt)
+{
+ mrb_funcall(mrb, info, "set_backtrace", 1, bt);
+}
+
+static mrb_bool
+have_backtrace(mrb_state *mrb, struct RObject *exc)
+{
+ return !mrb_nil_p(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "backtrace")));
+}
+
+void
+mrb_exc_set(mrb_state *mrb, mrb_value exc)
+{
+ if (!mrb->gc.out_of_memory && mrb->backtrace.n > 0) {
+ mrb_value target_exc = mrb_nil_value();
+ if ((mrb->exc && !have_backtrace(mrb, mrb->exc))) {
+ target_exc = mrb_obj_value(mrb->exc);
+ }
+ else if (!mrb_nil_p(exc) && mrb_obj_ptr(exc) == mrb->backtrace.exc) {
+ target_exc = exc;
+ }
+ if (!mrb_nil_p(target_exc)) {
+ mrb_value backtrace;
+ backtrace = mrb_restore_backtrace(mrb);
+ set_backtrace(mrb, target_exc, backtrace);
+ }
+ }
+
+ mrb->backtrace.n = 0;
+ if (mrb_nil_p(exc)) {
+ mrb->exc = 0;
+ }
+ else {
+ mrb->exc = mrb_obj_ptr(exc);
+ }
+}
+
MRB_API mrb_noreturn void
mrb_exc_raise(mrb_state *mrb, mrb_value exc)
{
- mrb->exc = mrb_obj_ptr(exc);
+ mrb_exc_set(mrb, exc);
if (!mrb->gc.out_of_memory) {
exc_debug_info(mrb, mrb->exc);
+ mrb_save_backtrace(mrb);
}
if (!mrb->jmp) {
mrb_p(mrb, exc);
@@ -337,12 +413,6 @@ mrb_bug(mrb_state *mrb, const char *fmt, ...)
exit(EXIT_FAILURE);
}
-static void
-set_backtrace(mrb_state *mrb, mrb_value info, mrb_value bt)
-{
- mrb_funcall(mrb, info, "set_backtrace", 1, bt);
-}
-
static mrb_value
make_exception(mrb_state *mrb, int argc, const mrb_value *argv, mrb_bool isstr)
{
@@ -449,7 +519,8 @@ mrb_init_exception(mrb_state *mrb)
mrb_define_method(mrb, exception, "to_s", exc_to_s, MRB_ARGS_NONE());
mrb_define_method(mrb, exception, "message", exc_message, MRB_ARGS_NONE());
mrb_define_method(mrb, exception, "inspect", exc_inspect, MRB_ARGS_NONE());
- mrb_define_method(mrb, exception, "backtrace", mrb_exc_backtrace, MRB_ARGS_NONE());
+ mrb_define_method(mrb, exception, "backtrace", exc_get_backtrace, MRB_ARGS_NONE());
+ mrb_define_method(mrb, exception, "set_backtrace", exc_set_backtrace, MRB_ARGS_REQ(1));
mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */
runtime_error = mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */
diff --git a/src/gc.c b/src/gc.c
index 02e058f88..e31ec2f33 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -613,14 +613,11 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
case MRB_TT_ENV:
{
struct REnv *e = (struct REnv*)obj;
+ mrb_int i, len;
- if (!MRB_ENV_STACK_SHARED_P(e)) {
- mrb_int i, len;
-
- len = MRB_ENV_STACK_LEN(e);
- for (i=0; i<len; i++) {
- mrb_gc_mark_value(mrb, e->stack[i]);
- }
+ len = MRB_ENV_STACK_LEN(e);
+ for (i=0; i<len; i++) {
+ mrb_gc_mark_value(mrb, e->stack[i]);
}
}
break;
@@ -725,9 +722,18 @@ obj_free(mrb_state *mrb, struct RBasic *obj)
case MRB_TT_FIBER:
{
struct mrb_context *c = ((struct RFiber*)obj)->cxt;
-
- if (c != mrb->root_c)
- mrb_free_context(mrb, c);
+ if (c && c != mrb->root_c) {
+ mrb_callinfo *ci = c->ci;
+ mrb_callinfo *ce = c->cibase;
+
+ while (ce <= ci) {
+ struct REnv *e = ci->env;
+ if (e && !is_dead(&mrb->gc, e) && MRB_ENV_STACK_SHARED_P(e)) {
+ mrb_env_unshare(mrb, e);
+ }
+ ci--;
+ }
+ }
}
break;
diff --git a/src/hash.c b/src/hash.c
index ac7256987..7712cd467 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -91,12 +91,6 @@ mrb_hash_ht_hash_equal(mrb_state *mrb, mrb_value a, mrb_value b)
}
}
-typedef struct {
- mrb_value v;
- mrb_int n;
-} mrb_hash_value;
-
-KHASH_DECLARE(ht, mrb_value, mrb_hash_value, TRUE)
KHASH_DEFINE (ht, mrb_value, mrb_hash_value, TRUE, mrb_hash_ht_hash_func, mrb_hash_ht_hash_equal)
static void mrb_hash_modify(mrb_state *mrb, mrb_value hash);
diff --git a/src/load.c b/src/load.c
index da88f0d3a..d3bb281ae 100644
--- a/src/load.c
+++ b/src/load.c
@@ -614,10 +614,12 @@ mrb_read_irep(mrb_state *mrb, const uint8_t *bin)
return read_irep(mrb, bin, flags);
}
+void mrb_exc_set(mrb_state *mrb, mrb_value exc);
+
static void
irep_error(mrb_state *mrb)
{
- mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SCRIPT_ERROR, "irep load error"));
+ mrb_exc_set(mrb, mrb_exc_new_str_lit(mrb, E_SCRIPT_ERROR, "irep load error"));
}
MRB_API mrb_value
@@ -633,7 +635,7 @@ mrb_load_irep_cxt(mrb_state *mrb, const uint8_t *bin, mrbc_context *c)
proc = mrb_proc_new(mrb, irep);
mrb_irep_decref(mrb, irep);
if (c && c->no_exec) return mrb_obj_value(proc);
- return mrb_toplevel_run(mrb, proc);
+ return mrb_top_run(mrb, proc, mrb_top_self(mrb), 0);
}
MRB_API mrb_value
@@ -695,7 +697,7 @@ mrb_load_irep_file_cxt(mrb_state *mrb, FILE* fp, mrbc_context *c)
mrb_irep_decref(mrb, irep);
if (c && c->dump_result) mrb_codedump_all(mrb, proc);
if (c && c->no_exec) return mrb_obj_value(proc);
- val = mrb_toplevel_run(mrb, proc);
+ val = mrb_top_run(mrb, proc, mrb_top_self(mrb), 0);
return val;
}
diff --git a/src/state.c b/src/state.c
index c8c0658e4..898e77336 100644
--- a/src/state.c
+++ b/src/state.c
@@ -215,6 +215,8 @@ mrb_str_pool(mrb_state *mrb, mrb_value str)
return mrb_obj_value(ns);
}
+void mrb_free_backtrace(mrb_state *mrb);
+
MRB_API void
mrb_free_context(mrb_state *mrb, struct mrb_context *c)
{
@@ -242,6 +244,7 @@ mrb_close(mrb_state *mrb)
/* free */
mrb_gc_free_gv(mrb);
+ mrb_free_backtrace(mrb);
mrb_free_context(mrb, mrb->root_c);
mrb_free_symtbl(mrb);
mrb_alloca_free(mrb);
diff --git a/src/string.c b/src/string.c
index 6664eabd6..a3f337d4b 100644
--- a/src/string.c
+++ b/src/string.c
@@ -306,17 +306,20 @@ bytes2chars(char *p, mrb_int bi)
mrb_int i, b, n;
for (b=i=0; b<bi; i++) {
- n = utf8len(p, p+bi);
+ n = utf8len_codepage[(unsigned char)*p];
b += n;
p += n;
}
+ if (b != bi) return -1;
return i;
}
+#define BYTES_ALIGN_CHECK(pos) if (pos < 0) return mrb_nil_value();
#else
#define RSTRING_CHAR_LEN(s) RSTRING_LEN(s)
#define chars2bytes(p, off, ci) (ci)
#define bytes2chars(p, bi) (bi)
+#define BYTES_ALIGN_CHECK(pos)
#endif
static inline mrb_int
@@ -352,12 +355,12 @@ mrb_memsearch(const void *x0, mrb_int m, const void *y0, mrb_int n)
return 0;
}
else if (m == 1) {
- const unsigned char *ys = y, *ye = ys + n;
- for (; y < ye; ++y) {
- if (*x == *y)
- return y - ys;
- }
- return -1;
+ const unsigned char *ys = memchr(y, *x, n);
+
+ if (ys)
+ return ys - y;
+ else
+ return -1;
}
return mrb_memsearch_qs((const unsigned char *)x0, m, (const unsigned char *)y0, n);
}
@@ -1608,6 +1611,7 @@ mrb_str_index(mrb_state *mrb, mrb_value str)
if (pos == -1) return mrb_nil_value();
pos = bytes2chars(RSTRING_PTR(str), pos);
+ BYTES_ALIGN_CHECK(pos);
return mrb_fixnum_value(pos);
}
@@ -1877,6 +1881,7 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str)
pos = str_rindex(mrb, str, sub, pos);
if (pos >= 0) {
pos = bytes2chars(RSTRING_PTR(str), pos);
+ BYTES_ALIGN_CHECK(pos);
return mrb_fixnum_value(pos);
}
break;
diff --git a/src/symbol.c b/src/symbol.c
index c39e88012..25ae132e1 100644
--- a/src/symbol.c
+++ b/src/symbol.c
@@ -354,7 +354,9 @@ symname_p(const char *name)
if (*++m == '*') ++m;
break;
case '!':
- if (*++m == '=') ++m;
+ switch (*++m) {
+ case '=': case '~': ++m;
+ }
break;
case '+': case '-':
if (*++m == '@') ++m;
diff --git a/src/vm.c b/src/vm.c
index 391646017..bcea8a056 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -209,6 +209,7 @@ top_env(mrb_state *mrb, struct RProc *proc)
#define CI_ACC_SKIP -1
#define CI_ACC_DIRECT -2
+#define CI_ACC_RESUMED -3
static mrb_callinfo*
cipush(mrb_state *mrb)
@@ -237,27 +238,34 @@ cipush(mrb_state *mrb)
return ci;
}
+MRB_API void
+mrb_env_unshare(mrb_state *mrb, struct REnv *e)
+{
+ size_t len = (size_t)MRB_ENV_STACK_LEN(e);
+ mrb_value *p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len);
+
+ MRB_ENV_UNSHARE_STACK(e);
+ if (len > 0) {
+ stack_copy(p, e->stack, len);
+ }
+ e->stack = p;
+ mrb_write_barrier(mrb, (struct RBasic *)e);
+}
+
static void
cipop(mrb_state *mrb)
{
struct mrb_context *c = mrb->c;
if (c->ci->env) {
- struct REnv *e = c->ci->env;
- size_t len = (size_t)MRB_ENV_STACK_LEN(e);
- mrb_value *p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len);
-
- MRB_ENV_UNSHARE_STACK(e);
- if (len > 0) {
- stack_copy(p, e->stack, len);
- }
- e->stack = p;
- mrb_write_barrier(mrb, (struct RBasic *)e);
+ mrb_env_unshare(mrb, c->ci->env);
}
c->ci--;
}
+void mrb_exc_set(mrb_state *mrb, mrb_value exc);
+
static void
ecall(mrb_state *mrb, int i)
{
@@ -496,21 +504,32 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c)
{
struct RProc *p;
mrb_callinfo *ci;
+ mrb_int max = 3;
if (mrb_nil_p(blk)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
}
ci = mrb->c->ci;
if (ci->acc == CI_ACC_DIRECT) {
- return mrb_yield_with_class(mrb, blk, 0, 0, self, c);
+ return mrb_yield_with_class(mrb, blk, 1, &self, self, c);
}
ci->target_class = c;
p = mrb_proc_ptr(blk);
ci->proc = p;
+ ci->argc = 1;
if (MRB_PROC_CFUNC_P(p)) {
+ stack_extend(mrb, 3, 0);
+ mrb->c->stack[0] = self;
+ mrb->c->stack[1] = self;
+ mrb->c->stack[2] = mrb_nil_value();
return p->body.func(mrb, self);
}
ci->nregs = p->body.irep->nregs;
+ if (max < ci->nregs) max = ci->nregs;
+ stack_extend(mrb, max, 0);
+ mrb->c->stack[0] = self;
+ mrb->c->stack[1] = self;
+ mrb->c->stack[2] = mrb_nil_value();
ci = cipush(mrb);
ci->nregs = 0;
ci->target_class = 0;
@@ -669,7 +688,7 @@ localjump_error(mrb_state *mrb, localjump_error_kind kind)
mrb_str_cat(mrb, msg, lead, sizeof(lead) - 1);
mrb_str_cat(mrb, msg, kind_str[kind], kind_str_len[kind]);
exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg);
- mrb->exc = mrb_obj_ptr(exc);
+ mrb_exc_set(mrb, exc);
}
static void
@@ -688,7 +707,7 @@ argnum_error(mrb_state *mrb, mrb_int num)
mrb_fixnum_value(mrb->c->ci->argc), mrb_fixnum_value(num));
}
exc = mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str);
- mrb->exc = mrb_obj_ptr(exc);
+ mrb_exc_set(mrb, exc);
}
#define ERR_PC_SET(mrb, pc) mrb->c->ci->err = pc;
@@ -727,11 +746,23 @@ argnum_error(mrb_state *mrb, mrb_int num)
void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args);
MRB_API mrb_value
-mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
+mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
+{
+ mrb_irep *irep = proc->body.irep;
+
+ if (!mrb->c->stack) {
+ stack_init(mrb);
+ }
+ stack_extend(mrb, irep->nregs, stack_keep);
+ mrb->c->stack[0] = self;
+ return mrb_vm_exec(mrb, proc, irep->iseq);
+}
+
+MRB_API mrb_value
+mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc)
{
/* mrb_assert(mrb_proc_cfunc_p(proc)) */
mrb_irep *irep = proc->body.irep;
- mrb_code *pc = irep->iseq;
mrb_value *pool = irep->pool;
mrb_sym *syms = irep->syms;
mrb_value *regs = NULL;
@@ -775,14 +806,9 @@ RETRY_TRY_BLOCK:
goto L_RAISE;
}
mrb->jmp = &c_jmp;
- if (!mrb->c->stack) {
- stack_init(mrb);
- }
- stack_extend(mrb, irep->nregs, stack_keep);
mrb->c->ci->proc = proc;
mrb->c->ci->nregs = irep->nregs;
regs = mrb->c->stack;
- regs[0] = self;
INIT_DISPATCH {
CASE(OP_NOP) {
@@ -1007,7 +1033,7 @@ RETRY_TRY_BLOCK:
CASE(OP_RAISE) {
/* A raise(R(A)) */
- mrb->exc = mrb_obj_ptr(regs[GETARG_A(i)]);
+ mrb_exc_set(mrb, regs[GETARG_A(i)]);
goto L_RAISE;
}
@@ -1124,19 +1150,24 @@ RETRY_TRY_BLOCK:
ci->nregs = n + 2;
}
result = m->body.func(mrb, recv);
- mrb->c->stack[0] = result;
mrb_gc_arena_restore(mrb, ai);
if (mrb->exc) goto L_RAISE;
/* pop stackpos */
ci = mrb->c->ci;
if (!ci->target_class) { /* return from context modifying method (resume/yield) */
- if (!MRB_PROC_CFUNC_P(ci[-1].proc)) {
+ if (ci->acc == CI_ACC_RESUMED) {
+ mrb->jmp = prev_jmp;
+ return result;
+ }
+ else {
+ mrb_assert(!MRB_PROC_CFUNC_P(ci[-1].proc));
proc = ci[-1].proc;
irep = proc->body.irep;
pool = irep->pool;
syms = irep->syms;
}
}
+ mrb->c->stack[0] = result;
regs = mrb->c->stack = ci->stackent;
pc = ci->pc;
cipop(mrb);
@@ -1241,7 +1272,7 @@ RETRY_TRY_BLOCK:
mrb_value exc;
exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
- mrb->exc = mrb_obj_ptr(exc);
+ mrb_exc_set(mrb, exc);
goto L_RAISE;
}
recv = regs[0];
@@ -1331,7 +1362,7 @@ RETRY_TRY_BLOCK:
mrb_value exc;
exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
- mrb->exc = mrb_obj_ptr(exc);
+ mrb_exc_set(mrb, exc);
goto L_RAISE;
}
stack = e->stack + 1;
@@ -1561,7 +1592,7 @@ RETRY_TRY_BLOCK:
}
if (mrb->c->prev->ci == mrb->c->prev->cibase) {
mrb_value exc = mrb_exc_new_str_lit(mrb, E_FIBER_ERROR, "double resume");
- mrb->exc = mrb_obj_ptr(exc);
+ mrb_exc_set(mrb, exc);
goto L_RAISE;
}
/* automatic yield at the end */
@@ -1601,14 +1632,19 @@ RETRY_TRY_BLOCK:
while (eidx > mrb->c->ci[-1].eidx) {
ecall(mrb, --eidx);
}
+ if (mrb->c->vmexec && !mrb->c->ci->target_class) {
+ mrb->c->vmexec = FALSE;
+ mrb->jmp = prev_jmp;
+ return v;
+ }
cipop(mrb);
acc = ci->acc;
- pc = ci->pc;
regs = mrb->c->stack = ci->stackent;
if (acc == CI_ACC_SKIP) {
mrb->jmp = prev_jmp;
return v;
}
+ pc = ci->pc;
DEBUG(printf("from :%s\n", mrb_sym2name(mrb, ci->mid)));
proc = mrb->c->ci->proc;
irep = proc->body.irep;
@@ -2323,7 +2359,7 @@ RETRY_TRY_BLOCK:
/* A R(A) := target_class */
if (!mrb->c->ci->target_class) {
mrb_value exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, "no target class or module");
- mrb->exc = mrb_obj_ptr(exc);
+ mrb_exc_set(mrb, exc);
goto L_RAISE;
}
regs[GETARG_A(i)] = mrb_obj_value(mrb->c->ci->target_class);
@@ -2381,7 +2417,7 @@ RETRY_TRY_BLOCK:
else {
exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg);
}
- mrb->exc = mrb_obj_ptr(exc);
+ mrb_exc_set(mrb, exc);
goto L_RAISE;
}
}
@@ -2398,30 +2434,24 @@ RETRY_TRY_BLOCK:
MRB_API mrb_value
mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
{
- return mrb_context_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */
+ return mrb_vm_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */
}
MRB_API mrb_value
-mrb_toplevel_run_keep(mrb_state *mrb, struct RProc *proc, unsigned int stack_keep)
+mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
{
mrb_callinfo *ci;
mrb_value v;
if (!mrb->c->cibase || mrb->c->ci == mrb->c->cibase) {
- return mrb_context_run(mrb, proc, mrb_top_self(mrb), stack_keep);
+ return mrb_vm_run(mrb, proc, self, stack_keep);
}
ci = cipush(mrb);
ci->nregs = 1; /* protect the receiver */
ci->acc = CI_ACC_SKIP;
ci->target_class = mrb->object_class;
- v = mrb_context_run(mrb, proc, mrb_top_self(mrb), stack_keep);
+ v = mrb_vm_run(mrb, proc, self, stack_keep);
cipop(mrb);
return v;
}
-
-MRB_API mrb_value
-mrb_toplevel_run(mrb_state *mrb, struct RProc *proc)
-{
- return mrb_toplevel_run_keep(mrb, proc, 0);
-}