summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2024-06-12 19:03:33 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2024-06-12 19:57:50 +0900
commit32a555ea532fb15721ad403e6dce0a2ffc346f12 (patch)
tree4a75bb367995945d452b083655c0422e5c7b14cd
parent278a7cb057cd7fed2a6284f727c38a1182a31668 (diff)
[Bug #20572] Abandon if replacing destination is the same
-rw-r--r--compile.c18
-rw-r--r--test/ruby/test_iseq.rb8
2 files changed, 18 insertions, 8 deletions
diff --git a/compile.c b/compile.c
index 24b90826cd..5e7c4289d5 100644
--- a/compile.c
+++ b/compile.c
@@ -2972,16 +2972,18 @@ unref_destination(INSN *iobj, int pos)
if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
}
-static void
+static bool
replace_destination(INSN *dobj, INSN *nobj)
{
VALUE n = OPERAND_AT(nobj, 0);
LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
LABEL *nl = (LABEL *)n;
+ if (dl == nl) return false;
--dl->refcnt;
++nl->refcnt;
OPERAND_AT(dobj, 0) = n;
if (!dl->refcnt) ELEM_REMOVE(&dl->link);
+ return true;
}
static LABEL*
@@ -3263,9 +3265,10 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
* => in this case, first jump instruction should jump to
* LABEL2 directly
*/
- replace_destination(iobj, diobj);
- remove_unreachable_chunk(iseq, iobj->link.next);
- goto again;
+ if (replace_destination(iobj, diobj)) {
+ remove_unreachable_chunk(iseq, iobj->link.next);
+ goto again;
+ }
}
else if (IS_INSN_ID(diobj, leave)) {
/*
@@ -3310,8 +3313,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
*/
piobj->insn_id = (IS_INSN_ID(piobj, branchif))
? BIN(branchunless) : BIN(branchif);
- replace_destination(piobj, iobj);
- if (refcnt <= 1) {
+ if (replace_destination(piobj, iobj) && refcnt <= 1) {
ELEM_REMOVE(&iobj->link);
}
else {
@@ -3440,7 +3442,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
for (;;) {
if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
- replace_destination(iobj, nobj);
+ if (!replace_destination(iobj, nobj)) break;
}
else if (prev_dup && IS_INSN_ID(nobj, dup) &&
!!(nobj = (INSN *)nobj->link.next) &&
@@ -3461,7 +3463,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
* dup
* if L2
*/
- replace_destination(iobj, nobj);
+ if (!replace_destination(iobj, nobj)) break;
}
else if (pobj) {
/*
diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb
index 1c7de5bb2b..267c0c83dc 100644
--- a/test/ruby/test_iseq.rb
+++ b/test/ruby/test_iseq.rb
@@ -871,4 +871,12 @@ class TestISeq < Test::Unit::TestCase
RubyVM::InstructionSequence.load_from_binary(var_0)
end
end
+
+ def test_while_in_until_condition
+ assert_in_out_err(["--dump=i", "-e", "until while 1; end; end"]) do |stdout, stderr, status|
+ assert_include(stdout.shift, "== disasm:")
+ assert_include(stdout.pop, "leave")
+ assert_predicate(status, :success?)
+ end
+ end
end