diff options
author | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-05-20 02:11:24 +0000 |
---|---|---|
committer | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-05-20 02:11:24 +0000 |
commit | 35c54a11b30342b3ffa72b476347c5b9998f2d79 (patch) | |
tree | bd1dea94fc7b39ba9927618044418657f367ee1d | |
parent | 68354c350a278a565bc3b2b3ba793b8a9dcd2712 (diff) | |
download | ruby-35c54a11b30342b3ffa72b476347c5b9998f2d79.tar.gz |
compile.c: fix catch-table labels optimization
* compile.c (remove_unreachable_chunk): do not eliminate chunks
followed by labels in catch-table entries.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58810 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | compile.c | 46 | ||||
-rw-r--r-- | test/ruby/test_optimization.rb | 8 |
2 files changed, 40 insertions, 14 deletions
@@ -64,6 +64,7 @@ typedef struct iseq_label_data { int refcnt; unsigned int set: 1; unsigned int rescued: 2; + unsigned int unremovable: 1; } LABEL; typedef struct iseq_insn_data { @@ -276,13 +277,15 @@ struct iseq_compile_data_ensure_node_stack { #define ADD_ADJUST_RESTORE(seq, label) \ ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1)) +#define LABEL_UNREMOVABLE(label) \ + ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0) #define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \ VALUE _e = rb_ary_new3(5, (type), \ (VALUE)(ls) | 1, (VALUE)(le) | 1, \ (VALUE)(iseqv), (VALUE)(lc) | 1); \ - if (ls) LABEL_REF(ls); \ - if (le) LABEL_REF(le); \ - if (lc) LABEL_REF(lc); \ + LABEL_UNREMOVABLE(ls); \ + LABEL_UNREMOVABLE(le); \ + LABEL_UNREMOVABLE(lc); \ rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \ } while (0) @@ -1026,7 +1029,7 @@ new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line) adjust->link.next = 0; adjust->label = label; adjust->line_no = line; - if (label) LABEL_REF(label); + LABEL_UNREMOVABLE(label); return adjust; } @@ -2016,9 +2019,30 @@ replace_destination(INSN *dobj, INSN *nobj) static int remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i) { - int removed = 0; + LINK_ELEMENT *first = i, *end; + + if (!i) return 0; while (i) { if (IS_INSN(i)) { + if (IS_INSN_ID(i, jump) || IS_INSN_ID(i, leave)) { + break; + } + } + else if (IS_LABEL(i)) { + if (((LABEL *)i)->unremovable) return 0; + if (((LABEL *)i)->refcnt > 0) { + if (i == first) return 0; + i = i->prev; + break; + } + } + else return 0; + i = i->next; + } + end = i; + i = first; + do { + if (IS_INSN(i)) { struct rb_iseq_constant_body *body = iseq->body; VALUE insn = INSN_OF(i); int pos, len = insn_len(insn); @@ -2036,15 +2060,9 @@ remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i) } } } - else if (IS_LABEL(i)) { - if (((LABEL *)i)->refcnt > 0) break; - } - else break; REMOVE_ELEM(i); - removed = 1; - i = i->next; - } - return removed; + } while ((i != end) && (i = i->next) != 0); + return 1; } static int @@ -6511,7 +6529,7 @@ dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr) printf("-- raw disasm--------\n"); while (link) { - if (curr) putc(curr == link ? '*' : ' ', stdout); + if (curr) printf(curr == link ? "*" : " "); switch (link->type) { case ISEQ_ELEMENT_INSN: { diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb index 910dc30c35..2d0eec02fd 100644 --- a/test/ruby/test_optimization.rb +++ b/test/ruby/test_optimization.rb @@ -567,4 +567,12 @@ class TestRubyOptimization < Test::Unit::TestCase assert_equal(:ok, t) end end + + def test_retry_label_in_unreachable_chunk + bug = '[ruby-core:81272] [Bug #13578]' + assert_valid_syntax("#{<<-"begin;"}\n#{<<-"end;"}", bug) + begin; + def t; if false; case 42; when s {}; end; end; end + end; + end end |