mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Merge pull request #6103 from dearblue/RBreak-ci
RBreak remembers the CI location
This commit is contained in:
+18
-9
@@ -37,19 +37,30 @@ MRB_API mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value st
|
||||
MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, const char *fmt, ...);
|
||||
|
||||
#if defined(MRB_64BIT) || defined(MRB_USE_FLOAT32) || defined(MRB_NAN_BOXING) || defined(MRB_WORD_BOXING)
|
||||
#undef MRB_USE_RBREAK_VALUE_UNION
|
||||
#else
|
||||
#define MRB_USE_RBREAK_VALUE_UNION 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* flags:
|
||||
* 0..7: enum mrb_vtype (only when defined MRB_USE_RBREAK_VALUE_UNION)
|
||||
* 8..10: RBREAK_TAGs in src/vm.c (otherwise, set to 0)
|
||||
*/
|
||||
struct RBreak {
|
||||
MRB_OBJECT_HEADER;
|
||||
const struct RProc *proc;
|
||||
uintptr_t ci_break_index; // The top-level ci index to break. One before the return destination.
|
||||
#ifndef MRB_USE_RBREAK_VALUE_UNION
|
||||
mrb_value val;
|
||||
#else
|
||||
union mrb_value_union value;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef MRB_USE_RBREAK_VALUE_UNION
|
||||
#define mrb_break_value_get(brk) ((brk)->val)
|
||||
#define mrb_break_value_set(brk, v) ((brk)->val = v)
|
||||
#else
|
||||
struct RBreak {
|
||||
MRB_OBJECT_HEADER;
|
||||
const struct RProc *proc;
|
||||
union mrb_value_union value;
|
||||
};
|
||||
#define RBREAK_VALUE_TT_MASK ((1 << 8) - 1)
|
||||
static inline mrb_value
|
||||
mrb_break_value_get(struct RBreak *brk)
|
||||
@@ -66,9 +77,7 @@ mrb_break_value_set(struct RBreak *brk, mrb_value val)
|
||||
brk->flags &= ~RBREAK_VALUE_TT_MASK;
|
||||
brk->flags |= val.tt;
|
||||
}
|
||||
#endif /* MRB_64BIT || MRB_USE_FLOAT32 || MRB_NAN_BOXING || MRB_WORD_BOXING */
|
||||
#define mrb_break_proc_get(brk) ((brk)->proc)
|
||||
#define mrb_break_proc_set(brk, p) ((brk)->proc = p)
|
||||
#endif /* MRB_USE_RBREAK_VALUE_UNION */
|
||||
|
||||
/**
|
||||
* Error check
|
||||
|
||||
@@ -6,81 +6,56 @@
|
||||
#include <mruby/opcode.h>
|
||||
#include <mruby/presym.h>
|
||||
|
||||
MRB_PRESYM_DEFINE_VAR_AND_INITER(catch_syms_3, 1, MRB_SYM(call))
|
||||
static const mrb_code catch_iseq_3[18] = {
|
||||
OP_ENTER, 0x00, 0x00, 0x00, // 000 ENTER 0:0:0:0:0:0:0 (0x0)
|
||||
OP_GETUPVAR, 0x02, 0x02, 0x01, // 004 GETUPVAR R2 2 1
|
||||
OP_GETUPVAR, 0x03, 0x01, 0x01, // 008 GETUPVAR R3 1 1
|
||||
OP_SEND, 0x02, 0x00, 0x01, // 012 SEND R2 :call n=1
|
||||
OP_RETURN, 0x02, // 016 RETURN R2
|
||||
};
|
||||
static const mrb_irep catch_irep_3 = {
|
||||
2,5,0,
|
||||
MRB_IREP_STATIC,catch_iseq_3,
|
||||
NULL,catch_syms_3,NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
18,0,1,0,0
|
||||
};
|
||||
static const mrb_irep *catch_reps_2[1] = {
|
||||
&catch_irep_3,
|
||||
};
|
||||
static const mrb_code catch_iseq_2[13] = {
|
||||
OP_ENTER, 0x00, 0x00, 0x00, // 000 ENTER 0:0:0:0:0:0:0 (0x0)
|
||||
OP_LAMBDA, 0x02, 0x00, // 004 LAMBDA R2 I[0]
|
||||
OP_SEND, 0x02, 0x00, 0x00, // 007 SEND R2 :call n=0
|
||||
OP_RETURN, 0x02, // 011 RETURN R2
|
||||
};
|
||||
static const mrb_irep catch_irep_2 = {
|
||||
2,4,0,
|
||||
MRB_IREP_STATIC,catch_iseq_2,
|
||||
NULL,catch_syms_3,catch_reps_2,
|
||||
NULL,
|
||||
NULL,
|
||||
13,0,1,1,0
|
||||
};
|
||||
static const mrb_irep *catch_reps_1[1] = {
|
||||
&catch_irep_2,
|
||||
};
|
||||
MRB_PRESYM_DEFINE_VAR_AND_INITER(catch_syms_1, 3, MRB_SYM(Object), MRB_SYM(new), MRB_SYM(call))
|
||||
static const mrb_code catch_iseq_1[29] = {
|
||||
MRB_PRESYM_DEFINE_VAR_AND_INITER(catch_syms, 3, MRB_SYM(Object), MRB_SYM(new), MRB_SYM(call))
|
||||
/*
|
||||
* def catch(r1 = Object.new, &r2)
|
||||
* r2.call(r1)
|
||||
* end
|
||||
*/
|
||||
static const mrb_code catch_iseq[] = {
|
||||
OP_ENTER, 0x00, 0x20, 0x01, // 000 ENTER 0:1:0:0:0:0:1 (0x2001)
|
||||
OP_JMP, 0x00, 0x03, // 004 JMP 010
|
||||
OP_JMP, 0x00, 0x0a, // 007 JMP 020
|
||||
OP_GETCONST, 0x03, 0x00, // 010 GETCONST R3 Object
|
||||
OP_SEND, 0x03, 0x01, 0x00, // 013 SEND R3 :new n=0
|
||||
OP_MOVE, 0x01, 0x03, // 017 MOVE R1 R3
|
||||
OP_LAMBDA, 0x03, 0x00, // 020 LAMBDA R3 I[0]
|
||||
OP_SEND, 0x03, 0x02, 0x00, // 023 SEND R3 :call n=0
|
||||
OP_RETURN, 0x03, // 027 RETURN R3
|
||||
OP_JMP, 0x00, 0x06, // 004 JMP 013
|
||||
|
||||
// copy for block parameter "tag" when method argument are given
|
||||
OP_MOVE, 0x03, 0x01, // 007 MOVE R3 R1
|
||||
OP_JMP, 0x00, 0x0a, // 010 JMP 023
|
||||
|
||||
// create a tag for default parameter
|
||||
OP_GETCONST, 0x03, 0x00, // 013 GETCONST R3 Object
|
||||
OP_SEND, 0x03, 0x01, 0x00, // 016 SEND R3 :new n=0
|
||||
OP_MOVE, 0x01, 0x03, // 020 MOVE R1 R3
|
||||
|
||||
// to save on the stack, block variables are used as is
|
||||
OP_SEND, 0x02, 0x02, 0x01, // 023 SEND R2 :call n=1
|
||||
OP_RETURN, 0x02, // 027 RETURN R2
|
||||
};
|
||||
static const mrb_irep catch_irep = {
|
||||
3,5,0,
|
||||
MRB_IREP_STATIC,catch_iseq_1,
|
||||
NULL,catch_syms_1,catch_reps_1,
|
||||
MRB_IREP_STATIC,catch_iseq,
|
||||
NULL,catch_syms,NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
29,0,3,1,0
|
||||
sizeof(catch_iseq),0,3,0,0
|
||||
};
|
||||
static const struct RProc catch_proc = {
|
||||
NULL, NULL, MRB_TT_PROC, MRB_GC_RED, MRB_FL_OBJ_IS_FROZEN | MRB_PROC_SCOPE | MRB_PROC_STRICT,
|
||||
{ &catch_irep }, NULL, { NULL }
|
||||
};
|
||||
|
||||
static const mrb_callinfo *
|
||||
static uintptr_t
|
||||
find_catcher(mrb_state *mrb, mrb_value tag)
|
||||
{
|
||||
const mrb_callinfo *ci = mrb->c->ci;
|
||||
size_t n = ci - mrb->c->cibase;
|
||||
ci--;
|
||||
const mrb_callinfo *ci = mrb->c->ci - 1; // skip ownself throw
|
||||
ptrdiff_t n = ci - mrb->c->cibase;
|
||||
|
||||
for (; n > 0; n--, ci--) {
|
||||
const mrb_value *arg1 = ci->stack + 1;
|
||||
if (ci->proc == &catch_proc && mrb_obj_eq(mrb, *arg1, tag)) {
|
||||
return ci;
|
||||
return (uintptr_t)n;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
@@ -91,11 +66,11 @@ throw_m(mrb_state *mrb, mrb_value self)
|
||||
obj = mrb_nil_value();
|
||||
}
|
||||
|
||||
const mrb_callinfo *ci = find_catcher(mrb, tag);
|
||||
if (ci) {
|
||||
uintptr_t ci_index = find_catcher(mrb, tag);
|
||||
if (ci_index > 0) {
|
||||
struct RBreak *b = MRB_OBJ_ALLOC(mrb, MRB_TT_BREAK, NULL);
|
||||
mrb_break_value_set(b, obj);
|
||||
mrb_break_proc_set(b, ci[2].proc); /* Back to the closure in `catch` method */
|
||||
b->ci_break_index = ci_index; /* Back to the caller directly */
|
||||
mrb_exc_raise(mrb, mrb_obj_value(b));
|
||||
}
|
||||
else {
|
||||
@@ -111,8 +86,7 @@ mrb_mruby_catch_gem_init(mrb_state *mrb)
|
||||
{
|
||||
mrb_method_t m;
|
||||
|
||||
MRB_PRESYM_INIT_SYMBOLS(mrb, catch_syms_3);
|
||||
MRB_PRESYM_INIT_SYMBOLS(mrb, catch_syms_1);
|
||||
MRB_PRESYM_INIT_SYMBOLS(mrb, catch_syms);
|
||||
MRB_METHOD_FROM_PROC(m, &catch_proc);
|
||||
mrb_define_method_raw(mrb, mrb->kernel_module, MRB_SYM(catch), m);
|
||||
|
||||
|
||||
@@ -677,7 +677,6 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
|
||||
case MRB_TT_BREAK:
|
||||
{
|
||||
struct RBreak *brk = (struct RBreak*)obj;
|
||||
mrb_gc_mark(mrb, (struct RBasic*)mrb_break_proc_get(brk));
|
||||
mrb_gc_mark_value(mrb, mrb_break_value_get(brk));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1104,12 +1104,12 @@ mrb_break_tag_set(struct RBreak *brk, uint32_t tag)
|
||||
}
|
||||
|
||||
static struct RBreak*
|
||||
break_new(mrb_state *mrb, uint32_t tag, const struct RProc *p, mrb_value val)
|
||||
break_new(mrb_state *mrb, uint32_t tag, const mrb_callinfo *return_ci, mrb_value val)
|
||||
{
|
||||
struct RBreak *brk;
|
||||
mrb_assert((size_t)(return_ci - mrb->c->cibase) <= (size_t)(mrb->c->ci - mrb->c->cibase));
|
||||
|
||||
brk = MRB_OBJ_ALLOC(mrb, MRB_TT_BREAK, NULL);
|
||||
mrb_break_proc_set(brk, p);
|
||||
struct RBreak *brk = MRB_OBJ_ALLOC(mrb, MRB_TT_BREAK, NULL);
|
||||
brk->ci_break_index = return_ci - mrb->c->cibase;
|
||||
mrb_break_value_set(brk, val);
|
||||
mrb_break_tag_set(brk, tag);
|
||||
|
||||
@@ -1213,27 +1213,27 @@ break_tag_p(struct RBreak *brk, uint32_t tag)
|
||||
}
|
||||
|
||||
static void
|
||||
prepare_tagged_break(mrb_state *mrb, uint32_t tag, const struct RProc *proc, mrb_value val)
|
||||
prepare_tagged_break(mrb_state *mrb, uint32_t tag, const mrb_callinfo *return_ci, mrb_value val)
|
||||
{
|
||||
if (break_tag_p((struct RBreak*)mrb->exc, tag)) {
|
||||
mrb_break_tag_set((struct RBreak*)mrb->exc, tag);
|
||||
}
|
||||
else {
|
||||
mrb->exc = (struct RObject*)break_new(mrb, tag, proc, val);
|
||||
mrb->exc = (struct RObject*)break_new(mrb, tag, return_ci, val);
|
||||
}
|
||||
}
|
||||
|
||||
#define THROW_TAGGED_BREAK(mrb, tag, proc, val) \
|
||||
#define THROW_TAGGED_BREAK(mrb, tag, return_ci, val) \
|
||||
do { \
|
||||
prepare_tagged_break(mrb, tag, proc, val); \
|
||||
prepare_tagged_break(mrb, tag, return_ci, val); \
|
||||
goto L_CATCH_TAGGED_BREAK; \
|
||||
} while (0)
|
||||
|
||||
#define UNWIND_ENSURE(mrb, ci, pc, tag, proc, val) \
|
||||
#define UNWIND_ENSURE(mrb, ci, pc, tag, return_ci, val) \
|
||||
do { \
|
||||
ch = catch_handler_find(mrb, ci, pc, MRB_CATCH_FILTER_ENSURE); \
|
||||
if (ch) { \
|
||||
THROW_TAGGED_BREAK(mrb, tag, proc, val); \
|
||||
THROW_TAGGED_BREAK(mrb, tag, return_ci, val); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
@@ -1696,7 +1696,7 @@ RETRY_TRY_BLOCK:
|
||||
if (ch) {
|
||||
/* avoiding a jump from a catch handler into the same handler */
|
||||
if (a < mrb_irep_catch_handler_unpack(ch->begin) || a >= mrb_irep_catch_handler_unpack(ch->end)) {
|
||||
THROW_TAGGED_BREAK(mrb, RBREAK_TAG_JUMP, proc, mrb_fixnum_value(a));
|
||||
THROW_TAGGED_BREAK(mrb, RBREAK_TAG_JUMP, mrb->c->ci, mrb_fixnum_value(a));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2295,7 +2295,6 @@ RETRY_TRY_BLOCK:
|
||||
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
|
||||
goto L_RAISE;
|
||||
}
|
||||
proc = dst;
|
||||
break;
|
||||
}
|
||||
/* fallthrough */
|
||||
@@ -2348,18 +2347,14 @@ RETRY_TRY_BLOCK:
|
||||
if (ci == mrb->c->cibase) {
|
||||
goto L_BREAK_ERROR;
|
||||
}
|
||||
proc = ci->proc;
|
||||
if (FALSE) {
|
||||
struct RBreak *brk;
|
||||
|
||||
L_BREAK:
|
||||
brk = (struct RBreak*)mrb->exc;
|
||||
proc = mrb_break_proc_get(brk);
|
||||
ci = &mrb->c->cibase[brk->ci_break_index];
|
||||
proc = ci->proc;
|
||||
v = mrb_break_value_get(brk);
|
||||
ci = mrb->c->ci;
|
||||
while (mrb->c->cibase < ci && ci->proc != proc) {
|
||||
ci--;
|
||||
}
|
||||
pc = ci->pc;
|
||||
|
||||
switch (mrb_break_tag_get(brk)) {
|
||||
@@ -2379,16 +2374,12 @@ RETRY_TRY_BLOCK:
|
||||
for (;;) {
|
||||
CHECKPOINT_RESTORE(RBREAK_TAG_BREAK) {
|
||||
struct RBreak *brk = (struct RBreak*)mrb->exc;
|
||||
proc = mrb_break_proc_get(brk);
|
||||
ci = mrb->c->ci;
|
||||
while (mrb->c->cibase <= ci && ci->proc != proc) {
|
||||
ci--;
|
||||
}
|
||||
ci = &mrb->c->cibase[brk->ci_break_index];
|
||||
v = mrb_break_value_get(brk);
|
||||
mrb_gc_protect(mrb, v);
|
||||
}
|
||||
CHECKPOINT_MAIN(RBREAK_TAG_BREAK) {
|
||||
UNWIND_ENSURE(mrb, mrb->c->ci, mrb->c->ci->pc, RBREAK_TAG_BREAK, proc, v);
|
||||
UNWIND_ENSURE(mrb, mrb->c->ci, mrb->c->ci->pc, RBREAK_TAG_BREAK, ci, v);
|
||||
}
|
||||
CHECKPOINT_END(RBREAK_TAG_BREAK);
|
||||
|
||||
@@ -2397,7 +2388,7 @@ RETRY_TRY_BLOCK:
|
||||
}
|
||||
cipop(mrb);
|
||||
if (mrb->c->ci[1].cci != CINFO_NONE) {
|
||||
mrb->exc = (struct RObject*)break_new(mrb, RBREAK_TAG_BREAK, proc, v);
|
||||
mrb->exc = (struct RObject*)break_new(mrb, RBREAK_TAG_BREAK, ci, v);
|
||||
mrb_gc_arena_restore(mrb, ai);
|
||||
mrb->c->vmexec = FALSE;
|
||||
mrb->jmp = prev_jmp;
|
||||
@@ -3092,7 +3083,7 @@ RETRY_TRY_BLOCK:
|
||||
/* do nothing */
|
||||
}
|
||||
CHECKPOINT_MAIN(RBREAK_TAG_STOP) {
|
||||
UNWIND_ENSURE(mrb, mrb->c->ci, pc, RBREAK_TAG_STOP, proc, mrb_nil_value());
|
||||
UNWIND_ENSURE(mrb, mrb->c->ci, mrb->c->ci->pc, RBREAK_TAG_STOP, mrb->c->ci, mrb_nil_value());
|
||||
}
|
||||
CHECKPOINT_END(RBREAK_TAG_STOP);
|
||||
L_STOP:
|
||||
|
||||
Reference in New Issue
Block a user