e$B$J$+$@$G$9!#e(B
At Thu, 23 Aug 2007 00:34:12 +0900,
Tanaka A. wrote in [ruby-dev:31609]:
matzruby e$B$K$"$k!"0z?t$J$7$Ge(B catch e$B$,8F$Y$k5!G=$Oe(B 1.9 e$B$K$OF~e(B
e$B$i$J$$$N$G$7$g$&$+!#e(B
e$B$$$m$$$m$HJQ$o$C$F$k$h$&$G$=$N$^$^$G$OF0$-$^$;$s$G$7$?!#e(B
Index: eval_jump.ci
— eval_jump.ci (revision 13128)
+++ eval_jump.ci (working copy)
@@ -6,5 +6,6 @@
#include “eval_intern.h”
-NORETURN(static VALUE rb_f_throw _((int, VALUE *)));
+NORETURN(static VALUE rb_f_throw(int, VALUE *));
+int rb_vm_catch_p(VALUE dst, VALUE tag);
/*
@@ -24,25 +25,8 @@ rb_f_throw(int argc, VALUE *argv)
{
VALUE tag, value;
-
rb_thread_t *th = GET_THREAD();
-
struct rb_vm_tag *tt = th->tag;
rb_scan_args(argc, argv, “11”, &tag, &value);
-
tag = ID2SYM(rb_to_id(tag));
-
-
while (tt) {
-
if (tt->tag == tag) {
-
tt->retval = value;
-
break;
-
}
-
tt = tt->prev;
-
}
-
if (!tt) {
-
rb_name_error(SYM2ID(tag), “uncaught throw `%s’”,
-
rb_id2name(SYM2ID(tag)));
-
}
-
rb_trap_restore_mask();
-
th->errinfo = tag;
-
JUMP_TAG(TAG_THROW);
- rb_throw_obj(tag, value);
#ifndef GNUC
return Qnil; /* not reached */
@@ -53,14 +37,11 @@ void
rb_throw(const char *tag, VALUE val)
{
- VALUE argv[2];
-
- argv[0] = ID2SYM(rb_intern(tag));
- argv[1] = val;
- rb_f_throw(2, argv);
- rb_throw_obj(ID2SYM(rb_intern(tag)), val);
}
/*
static VALUE
-rb_f_catch(VALUE dmy, VALUE tag)
+rb_f_catch(int argc, VALUE *argv)
{
- int state;
- VALUE val = Qnil; /* OK */
- rb_thread_t *th = GET_THREAD();
-
- tag = ID2SYM(rb_to_id(tag));
- PUSH_TAG();
- th->tag->tag = tag;
-
- if ((state = EXEC_TAG()) == 0) {
- val = rb_yield_0(1, &tag);
- }
- else if (state == TAG_THROW && th->errinfo == tag) {
- val = th->tag->retval;
- th->errinfo = Qnil;
- state = 0;
- rb_scan_args(argc, argv, “01”, &tag);
- if (argc == 0) {
- tag = Qundef;
}
- POP_TAG();
- if (state)
- JUMP_TAG(state);
-
- return val;
-}
-
-static VALUE
-catch_i(VALUE tag)
-{
- return rb_funcall(Qnil, rb_intern(“catch”), 1, tag);
- return rb_catch_obj(tag, rb_yield, Qnil);
}
VALUE
-rb_catch(const char *tag, VALUE (*func)(), VALUE data)
+rb_catch(const char *tag, VALUE (*func)(ANYARGS), VALUE data)
{
- return rb_iterate((VALUE (*)_((VALUE)))catch_i,
ID2SYM(rb_intern(tag)),
-
func, data);
- if (!tag) {
- return rb_catch_obj(Qundef, func, data);
- }
- return rb_catch_obj(ID2SYM(rb_intern(tag)), func, data);
}
@@ -277,5 +239,5 @@ void
Init_jump(void)
{
- rb_define_global_function(“catch”, rb_f_catch, 1);
- rb_define_global_function(“catch”, rb_f_catch, -1);
rb_define_global_function(“throw”, rb_f_throw, -1);
rb_define_global_function(“at_exit”, rb_f_at_exit, 0);
Index: vm.c
===================================================================
— vm.c (revision 13128)
+++ vm.c (working copy)
@@ -982,4 +995,76 @@ rb_iter_break()
}
+static inline int
+catching_p(VALUE dst, VALUE tag)
+{
- if (dst == tag) return Qtrue;
- if (SPECIAL_CONST_P(dst)) return Qfalse;
- if (BUILTIN_TYPE(dst) != T_NODE) return Qfalse;
- if (GET_THROWOBJ_STATE(dst) != TAG_THROW) return Qfalse;
- if (GET_THROWOBJ_VAL(dst) != tag) return Qfalse;
- return Qtrue;
+}
-
+void
+rb_throw_obj(VALUE tag, VALUE value)
+{
- rb_thread_t *th = GET_THREAD();
- struct rb_vm_tag *tt = th->tag;
-
- while (tt) {
- if (catching_p(tt->tag, tag)) {
-
tag = tt->tag;
-
tt->retval = value;
-
break;
- }
- tt = tt->prev;
- }
- if (!tt) {
- VALUE argv[2];
- argv[0] = rb_sprintf(“uncaught throw `%s’”,
RSTRING_PTR(rb_obj_as_string(tag)));
- argv[1] = tag;
- rb_exc_raise(rb_class_new_instance(2, argv, rb_eNameError));
- }
- rb_trap_restore_mask();
- th->errinfo = tag;
- TH_JUMP_TAG(th, TAG_THROW);
+#ifndef GNUC
- return Qnil; /* not reached */
+#endif
+}
-
+VALUE
+rb_catch_obj(VALUE tag, VALUE (*func)(ANYARGS), VALUE data)
+{
- int state;
- VALUE val = Qnil; /* OK */
- VALUE dest = tag;
- rb_thread_t *th = GET_THREAD();
-
- if (tag == Qundef) {
- tag = rb_obj_alloc(rb_cObject);
- dest = (VALUE)NEW_THROW_OBJECT(tag,
GC_GUARDED_PTR_REF(*th->cfp->dfp),
-
TAG_THROW);
- }
-
- TH_PUSH_TAG(th);
-
- th->tag->tag = dest;
-
- if ((state = EXEC_TAG()) == 0) {
- val = (*func)(tag, data);
- }
- else if (state == TAG_THROW && th->errinfo == dest) {
- val = th->tag->retval;
- th->errinfo = Qnil;
- state = 0;
- }
- TH_POP_TAG();
- if (state)
- JUMP_TAG(state);
-
- return val;
+}
-
/* optimization: redefine management */
Index: include/ruby/ruby.h
— include/ruby/ruby.h (revision 13128)
+++ include/ruby/ruby.h (working copy)
@@ -723,5 +723,7 @@ VALUE rb_rescue2(VALUE()(ANYARGS),VALUE
VALUE rb_ensure(VALUE()(ANYARGS),VALUE,VALUE()(ANYARGS),VALUE);
VALUE rb_catch(const char,VALUE()(ANYARGS),VALUE);
+VALUE rb_catch_obj(VALUE,VALUE()(ANYARGS),VALUE);
NORETURN(void rb_throw(const char*,VALUE));
+NORETURN(void rb_throw_obj(VALUE,VALUE));
VALUE rb_require(const char*);