diff options
author | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-08-08 07:52:19 +0000 |
---|---|---|
committer | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-08-08 07:52:19 +0000 |
commit | 93b6f8d6195564d0884ee00f536a951f4c26288c (patch) | |
tree | ab922f8c850c7dda9d155e52b078026b6006dcb3 | |
parent | 8637eac4066dedd2c716f385e22a9d31100b68c7 (diff) | |
download | ruby-93b6f8d6195564d0884ee00f536a951f4c26288c.tar.gz |
* compile.c, insns.def (checkmatch):
remove checkincludearray instruction and
add new instruction checkmatch.
This change is to solve
[Bug #4438] "rescue args type check omitted".
* iseq.c: increment ISEQ_MAJOR_VERSION because removal of
checkincludearray instruction.
* vm_core.h: add several definitions for
the checkmatch instruction.
* vm_insnhelper.c (check_match): added.
* bootstraptest/test_exception.rb: add a test.
* test/ruby/test_exception.rb: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36658 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 20 | ||||
-rw-r--r-- | bootstraptest/test_exception.rb | 15 | ||||
-rw-r--r-- | compile.c | 25 | ||||
-rw-r--r-- | insns.def | 74 | ||||
-rw-r--r-- | iseq.c | 4 | ||||
-rw-r--r-- | test/ruby/test_exception.rb | 20 | ||||
-rw-r--r-- | vm_core.h | 10 | ||||
-rw-r--r-- | vm_insnhelper.c | 19 |
8 files changed, 132 insertions, 55 deletions
@@ -1,3 +1,23 @@ +Wed Aug 8 16:27:58 2012 Koichi Sasada <ko1@atdot.net> + + * compile.c, insns.def (checkmatch): + remove checkincludearray instruction and + add new instruction checkmatch. + This change is to solve + [Bug #4438] "rescue args type check omitted". + + * iseq.c: increment ISEQ_MAJOR_VERSION because removal of + checkincludearray instruction. + + * vm_core.h: add several definitions for + the checkmatch instruction. + + * vm_insnhelper.c (check_match): added. + + * bootstraptest/test_exception.rb: add a test. + + * test/ruby/test_exception.rb: ditto. + Wed Aug 8 05:51:20 2012 Eric Hodel <drbrain@segment7.net> * proc.c (method_clone): Added documentation. Patch by Robin Dupret. diff --git a/bootstraptest/test_exception.rb b/bootstraptest/test_exception.rb index f7d5eeaa07..b0d37234b8 100644 --- a/bootstraptest/test_exception.rb +++ b/bootstraptest/test_exception.rb @@ -414,3 +414,18 @@ assert_equal 'exception class/object expected', %q{ e.message end }, '[ruby-core:24767]' + +assert_equal 'ok', %q{ + class C + def ===(o) + true + end + end + begin + begin + rescue C.new + end + rescue TypeError + :ok + end +} @@ -2458,6 +2458,8 @@ when_vals(rb_iseq_t *iseq, LINK_ANCHOR *cond_seq, NODE *vals, LABEL *l1, int onl } } + ADD_INSN(cond_seq, nd_line(val), dup); /* dup target */ + if (nd_type(val) == NODE_STR) { debugp_param("nd_lit", val->nd_lit); OBJ_FREEZE(val->nd_lit); @@ -2466,8 +2468,8 @@ when_vals(rb_iseq_t *iseq, LINK_ANCHOR *cond_seq, NODE *vals, LABEL *l1, int onl else { COMPILE(cond_seq, "when cond", val); } - ADD_INSN1(cond_seq, nd_line(val), topn, INT2FIX(1)); - ADD_SEND(cond_seq, nd_line(val), ID2SYM(idEqq), INT2FIX(1)); + + ADD_INSN1(cond_seq, nd_line(vals), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); ADD_INSNL(cond_seq, nd_line(val), branchif, l1); vals = vals->nd_next; } @@ -3207,8 +3209,9 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) case NODE_ARGSCAT: case NODE_ARGSPUSH: only_special_literals = 0; + ADD_INSN (cond_seq, nd_line(vals), dup); COMPILE(cond_seq, "when/cond splat", vals); - ADD_INSN1(cond_seq, nd_line(vals), checkincludearray, Qtrue); + ADD_INSN1(cond_seq, nd_line(vals), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY)); ADD_INSNL(cond_seq, nd_line(vals), branchif, l1); break; default: @@ -3289,8 +3292,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) case NODE_ARGSPUSH: ADD_INSN(ret, nd_line(vals), putnil); COMPILE(ret, "when2/cond splat", vals); - ADD_INSN1(ret, nd_line(vals), checkincludearray, Qfalse); - ADD_INSN(ret, nd_line(vals), pop); + ADD_INSN1(ret, nd_line(vals), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY)); ADD_INSNL(ret, nd_line(vals), branchif, l1); break; default: @@ -3687,9 +3689,9 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) switch (nd_type(narg)) { case NODE_ARRAY: while (narg) { - COMPILE(ret, "rescue arg", narg->nd_head); ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(0)); - ADD_SEND(ret, nd_line(node), ID2SYM(idEqq), INT2FIX(1)); + COMPILE(ret, "rescue arg", narg->nd_head); + ADD_INSN1(ret, nd_line(node), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE)); ADD_INSNL(ret, nd_line(node), branchif, label_hit); narg = narg->nd_next; } @@ -3699,9 +3701,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) case NODE_ARGSPUSH: ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(0)); COMPILE(ret, "rescue/cond splat", narg); - ADD_INSN1(ret, nd_line(node), checkincludearray, Qtrue); - ADD_INSN(ret, nd_line(node), swap); - ADD_INSN(ret, nd_line(node), pop); + ADD_INSN1(ret, nd_line(node), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY)); ADD_INSNL(ret, nd_line(node), branchif, label_hit); break; default: @@ -3710,10 +3710,9 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) } } else { - ADD_INSN1(ret, nd_line(node), putobject, - rb_eStandardError); ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(0)); - ADD_SEND(ret, nd_line(node), ID2SYM(idEqq), INT2FIX(1)); + ADD_INSN1(ret, nd_line(node), putobject, rb_eStandardError); + ADD_INSN1(ret, nd_line(node), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE)); ADD_INSNL(ret, nd_line(node), branchif, label_hit); } ADD_INSNL(ret, nd_line(node), jump, label_miss); @@ -541,46 +541,6 @@ splatarray /** @c put - @e check value is included in ary - @j 配列 ary に要素 obj が入っているかどうかチェック。case/when で利用する。 - */ -DEFINE_INSN -checkincludearray -(VALUE flag) -(VALUE obj, VALUE ary) -(VALUE obj, VALUE result) -{ - int i; - result = Qfalse; - - if (!RB_TYPE_P(ary, T_ARRAY)) { - ary = rb_Array(ary); - } - - if (flag == Qtrue) { - /* NODE_CASE */ - for (i = 0; i < RARRAY_LEN(ary); i++) { - /* TODO: fix me (use another method dispatch) */ - if (RTEST(rb_funcall2(RARRAY_PTR(ary)[i], idEqq, 1, &obj))) { - result = Qtrue; - break; - } - } - } - else { - obj = Qfalse; - /* NODE_WHEN */ - for (i = 0; i < RARRAY_LEN(ary); i++) { - if (RTEST(RARRAY_PTR(ary)[i])) { - obj = result = Qtrue; - break; - } - } - } -} - -/** - @c put @e put new Hash. @j 新しいハッシュをスタックトップの n 個を初期値として生成する。 n はキーと値のペアなので 2 の倍数でなければならない。 @@ -859,6 +819,40 @@ defined /** @c setting + @e check `target' matches `pattern'. + `flag & VM_CHECKMATCH_TYPE_MASK' describe how to check pattern. + VM_CHECKMATCH_TYPE_WHEN: ignore target and check pattern is truthy. + VM_CHECKMATCH_TYPE_CASE: check `patten === target'. + VM_CHECKMATCH_TYPE_RESCUE: check `pattern.kind_op?(Module) && pattern == target'. + if `flag & VM_CHECKMATCH_ARRAY' is not 0, then `patten' is array of patterns. + @j see above comments. + */ +DEFINE_INSN +checkmatch +(rb_num_t flag) +(VALUE target, VALUE pattern) +(VALUE result) +{ + result = Qfalse; + + if (flag & VM_CHECKMATCH_ARRAY) { + int i; + for (i = 0; i < RARRAY_LEN(pattern); i++) { + if (RTEST(check_match(RARRAY_PTR(pattern)[i], target, flag & VM_CHECKMATCH_TYPE_MASK))) { + result = Qtrue; + break; + } + } + } + else { + if (RTEST(check_match(pattern, target, flag & VM_CHECKMATCH_TYPE_MASK))) { + result = Qtrue; + } + } +} + +/** + @c setting @e trace @j trace 用の命令。 */ @@ -21,8 +21,8 @@ #include "insns.inc" #include "insns_info.inc" -#define ISEQ_MAJOR_VERSION 1 -#define ISEQ_MINOR_VERSION 2 +#define ISEQ_MAJOR_VERSION 2 +#define ISEQ_MINOR_VERSION 0 VALUE rb_cISeq; diff --git a/test/ruby/test_exception.rb b/test/ruby/test_exception.rb index c49bd51064..93b24bbdd5 100644 --- a/test/ruby/test_exception.rb +++ b/test/ruby/test_exception.rb @@ -431,4 +431,24 @@ end.join ensure t.close(true) if t end + + Bug4438 = '[ruby-core:35364]' + + def test_rescue_single_argument + assert_raise(TypeError, Bug4438) do + begin + raise + rescue 1 + end + end + end + + def test_rescue_splat_argument + assert_raise(TypeError, Bug4438) do + begin + raise + rescue *Array(1) + end + end + end end @@ -598,6 +598,16 @@ typedef struct { } rb_binding_t; /* used by compile time and send insn */ + +enum vm_check_match_type { + VM_CHECKMATCH_TYPE_WHEN = 1, + VM_CHECKMATCH_TYPE_CASE = 2, + VM_CHECKMATCH_TYPE_RESCUE = 3 +}; + +#define VM_CHECKMATCH_TYPE_MASK 0x03 +#define VM_CHECKMATCH_ARRAY 0x04 + #define VM_CALL_ARGS_SPLAT_BIT (0x01 << 1) #define VM_CALL_ARGS_BLOCKARG_BIT (0x01 << 2) #define VM_CALL_FCALL_BIT (0x01 << 3) diff --git a/vm_insnhelper.c b/vm_insnhelper.c index b9c5e115c1..bb39b848cf 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1848,3 +1848,22 @@ rb_vm_using_modules(NODE *cref, VALUE klass) } } +static VALUE +check_match(VALUE pattern, VALUE target, enum vm_check_match_type type) +{ + switch (type) { + case VM_CHECKMATCH_TYPE_WHEN: + return pattern; + case VM_CHECKMATCH_TYPE_CASE: + return rb_funcall2(pattern, idEqq, 1, &target); + case VM_CHECKMATCH_TYPE_RESCUE: { + if (!rb_obj_is_kind_of(pattern, rb_cModule)) { + rb_raise(rb_eTypeError, "class or module required for rescue clause"); + } + return RTEST(rb_funcall2(pattern, idEqq, 1, &target)); + } + default: + rb_bug("check_match: unreachable"); + } +} + |