diff --git a/compile.c b/compile.c index 7b784b8560..2c388b8a8c 100644 --- a/compile.c +++ b/compile.c @@ -1246,6 +1246,15 @@ new_child_iseq_ifunc(rb_iseq_t *iseq, const struct vm_ifunc *ifunc, return ret_iseq; } +static void +set_catch_except_p(struct rb_iseq_constant_body *body) +{ + body->catch_except_p = TRUE; + if (body->parent_iseq != NULL) { + set_catch_except_p(body->parent_iseq->body); + } +} + /* Set body->catch_except_p to TRUE if the ISeq may catch an exception. If it is FALSE, JIT-ed code may be optimized. If we are extremely conservative, we should set TRUE if catch table exists. But we want to optimize while loop, which always has catch @@ -1273,7 +1282,7 @@ update_catch_except_flags(struct rb_iseq_constant_body *body) #endif if (insn == BIN(throw)) { struct rb_iseq_constant_body *parent_body = body->parent_iseq->body; - parent_body->catch_except_p = TRUE; + set_catch_except_p(parent_body); } pos += insn_len(insn); } diff --git a/test/ruby/test_jit.rb b/test/ruby/test_jit.rb index 5af79bc76e..a53f89bd66 100644 --- a/test/ruby/test_jit.rb +++ b/test/ruby/test_jit.rb @@ -510,6 +510,25 @@ class TestJIT < Test::Unit::TestCase end; end + def test_catching_deep_exception + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '1', success_count: 4) + begin; + def catch_true(paths, prefixes) # catch_except_p: TRUE + prefixes.each do |prefix| # catch_except_p: TRUE + paths.each do |path| # catch_except_p: FALSE + return path + end + end + end + + def wrapper(paths, prefixes) + catch_true(paths, prefixes) + end + + print wrapper(['1'], ['2']) + end; + end + private # The shortest way to test one proc