summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornagachika <nagachika@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-08-05 02:43:08 +0000
committernagachika <nagachika@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-08-05 02:43:08 +0000
commit5cf363247595a43e58c919f11c5fc5883871b8a9 (patch)
tree4df1c04377c181df1cdca4dc1e1d0a0b182394d6
parentf177c73edb16a62a3e1a06368ede687c5a5c53ff (diff)
merge revision(s) 58810,58894: [Backport #13578]
compile.c: fix catch-table labels optimization * compile.c (remove_unreachable_chunk): do not eliminate chunks followed by labels in catch-table entries. compile.c: fix possible use of uninitialized value LABEL::unremovable added by r58810 is not initialized by new_label_body(), making the optimization unstable. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_4@59514 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--compile.c44
-rw-r--r--test/ruby/test_optimization.rb8
-rw-r--r--version.h2
3 files changed, 40 insertions, 14 deletions
diff --git a/compile.c b/compile.c
index 20466d01f9..0883cea78b 100644
--- a/compile.c
+++ b/compile.c
@@ -66,6 +66,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 {
@@ -290,13 +291,15 @@ r_value(VALUE value)
#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)
@@ -1034,7 +1037,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;
}
@@ -2015,9 +2018,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);
@@ -2035,15 +2059,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
diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb
index 1ac02ec7e5..eebbc45e57 100644
--- a/test/ruby/test_optimization.rb
+++ b/test/ruby/test_optimization.rb
@@ -533,4 +533,12 @@ EOS
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
diff --git a/version.h b/version.h
index 5fd749fada..188351d07e 100644
--- a/version.h
+++ b/version.h
@@ -1,6 +1,6 @@
#define RUBY_VERSION "2.4.2"
#define RUBY_RELEASE_DATE "2017-08-05"
-#define RUBY_PATCHLEVEL 177
+#define RUBY_PATCHLEVEL 178
#define RUBY_RELEASE_YEAR 2017
#define RUBY_RELEASE_MONTH 8