support rescue event for TracePoint

fix [Feature #19572]
This commit is contained in:
Koichi Sasada 2023-08-01 17:25:20 +09:00
parent f11ac06337
commit d68c01fd31
Notes: git 2023-08-01 13:46:38 +00:00
8 changed files with 86 additions and 9 deletions

View File

@ -7748,7 +7748,18 @@ compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
} }
ADD_INSNL(ret, line_node, jump, label_miss); ADD_INSNL(ret, line_node, jump, label_miss);
ADD_LABEL(ret, label_hit); ADD_LABEL(ret, label_hit);
CHECK(COMPILE(ret, "resbody body", resq->nd_body)); ADD_TRACE(ret, RUBY_EVENT_RESCUE);
if (nd_type(resq->nd_body) == NODE_BEGIN && resq->nd_body->nd_body == NULL) {
// empty body
int lineno = nd_line(resq->nd_body);
NODE dummy_line_node = generate_dummy_line_node(lineno, -1);
ADD_INSN(ret, &dummy_line_node, putnil);
}
else {
CHECK(COMPILE(ret, "resbody body", resq->nd_body));
}
if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) { if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
ADD_INSN(ret, line_node, nop); ADD_INSN(ret, line_node, nop);
} }
@ -10406,6 +10417,7 @@ event_name_to_flag(VALUE sym)
CHECK_EVENT(RUBY_EVENT_RETURN); CHECK_EVENT(RUBY_EVENT_RETURN);
CHECK_EVENT(RUBY_EVENT_B_CALL); CHECK_EVENT(RUBY_EVENT_B_CALL);
CHECK_EVENT(RUBY_EVENT_B_RETURN); CHECK_EVENT(RUBY_EVENT_B_RETURN);
CHECK_EVENT(RUBY_EVENT_RESCUE);
#undef CHECK_EVENT #undef CHECK_EVENT
return RUBY_EVENT_NONE; return RUBY_EVENT_NONE;
} }

View File

@ -58,6 +58,7 @@
#define RUBY_EVENT_THREAD_END 0x0800 /**< Encountered an end of a thread. */ #define RUBY_EVENT_THREAD_END 0x0800 /**< Encountered an end of a thread. */
#define RUBY_EVENT_FIBER_SWITCH 0x1000 /**< Encountered a `Fiber#yield`. */ #define RUBY_EVENT_FIBER_SWITCH 0x1000 /**< Encountered a `Fiber#yield`. */
#define RUBY_EVENT_SCRIPT_COMPILED 0x2000 /**< Encountered an `eval`. */ #define RUBY_EVENT_SCRIPT_COMPILED 0x2000 /**< Encountered an `eval`. */
#define RUBY_EVENT_RESCUE 0x4000 /**< Encountered a `rescue` statement. */
#define RUBY_EVENT_TRACEPOINT_ALL 0xffff /**< Bitmask of extended events. */ #define RUBY_EVENT_TRACEPOINT_ALL 0xffff /**< Bitmask of extended events. */
/** @} */ /** @} */

5
iseq.c
View File

@ -2219,7 +2219,7 @@ rb_iseq_disasm_insn(VALUE ret, const VALUE *code, size_t pos,
{ {
rb_event_flag_t events = rb_iseq_event_flags(iseq, pos); rb_event_flag_t events = rb_iseq_event_flags(iseq, pos);
if (events) { if (events) {
str = rb_str_catf(str, "[%s%s%s%s%s%s%s%s%s%s%s]", str = rb_str_catf(str, "[%s%s%s%s%s%s%s%s%s%s%s%s]",
events & RUBY_EVENT_LINE ? "Li" : "", events & RUBY_EVENT_LINE ? "Li" : "",
events & RUBY_EVENT_CLASS ? "Cl" : "", events & RUBY_EVENT_CLASS ? "Cl" : "",
events & RUBY_EVENT_END ? "En" : "", events & RUBY_EVENT_END ? "En" : "",
@ -2229,6 +2229,7 @@ rb_iseq_disasm_insn(VALUE ret, const VALUE *code, size_t pos,
events & RUBY_EVENT_C_RETURN ? "Cr" : "", events & RUBY_EVENT_C_RETURN ? "Cr" : "",
events & RUBY_EVENT_B_CALL ? "Bc" : "", events & RUBY_EVENT_B_CALL ? "Bc" : "",
events & RUBY_EVENT_B_RETURN ? "Br" : "", events & RUBY_EVENT_B_RETURN ? "Br" : "",
events & RUBY_EVENT_RESCUE ? "Rs" : "",
events & RUBY_EVENT_COVERAGE_LINE ? "Cli" : "", events & RUBY_EVENT_COVERAGE_LINE ? "Cli" : "",
events & RUBY_EVENT_COVERAGE_BRANCH ? "Cbr" : ""); events & RUBY_EVENT_COVERAGE_BRANCH ? "Cbr" : "");
} }
@ -2573,6 +2574,7 @@ push_event_info(const rb_iseq_t *iseq, rb_event_flag_t events, int line, VALUE a
C(RUBY_EVENT_END, "end", INT2FIX(line)); C(RUBY_EVENT_END, "end", INT2FIX(line));
C(RUBY_EVENT_RETURN, "return", INT2FIX(line)); C(RUBY_EVENT_RETURN, "return", INT2FIX(line));
C(RUBY_EVENT_B_RETURN, "b_return", INT2FIX(line)); C(RUBY_EVENT_B_RETURN, "b_return", INT2FIX(line));
C(RUBY_EVENT_RESCUE, "rescue", INT2FIX(line));
#undef C #undef C
} }
@ -3090,6 +3092,7 @@ iseq_data_to_ary(const rb_iseq_t *iseq)
CHECK_EVENT(RUBY_EVENT_RETURN); CHECK_EVENT(RUBY_EVENT_RETURN);
CHECK_EVENT(RUBY_EVENT_B_CALL); CHECK_EVENT(RUBY_EVENT_B_CALL);
CHECK_EVENT(RUBY_EVENT_B_RETURN); CHECK_EVENT(RUBY_EVENT_B_RETURN);
CHECK_EVENT(RUBY_EVENT_RESCUE);
#undef CHECK_EVENT #undef CHECK_EVENT
prev_insn_info = info; prev_insn_info = info;
} }

7
iseq.h
View File

@ -83,9 +83,10 @@ ISEQ_ORIGINAL_ISEQ_ALLOC(const rb_iseq_t *iseq, long size)
RUBY_EVENT_CALL | \ RUBY_EVENT_CALL | \
RUBY_EVENT_RETURN| \ RUBY_EVENT_RETURN| \
RUBY_EVENT_C_CALL| \ RUBY_EVENT_C_CALL| \
RUBY_EVENT_C_RETURN| \ RUBY_EVENT_C_RETURN | \
RUBY_EVENT_B_CALL| \ RUBY_EVENT_B_CALL | \
RUBY_EVENT_B_RETURN| \ RUBY_EVENT_B_RETURN | \
RUBY_EVENT_RESCUE | \
RUBY_EVENT_COVERAGE_LINE| \ RUBY_EVENT_COVERAGE_LINE| \
RUBY_EVENT_COVERAGE_BRANCH) RUBY_EVENT_COVERAGE_BRANCH)

View File

@ -497,7 +497,8 @@ class TestISeq < Test::Unit::TestCase
[7, :line], [7, :line],
[9, :return]]], [9, :return]]],
[["ensure in foo@2", [[7, :line]]]], [["ensure in foo@2", [[7, :line]]]],
[["rescue in foo@4", [[5, :line]]]]]], [["rescue in foo@4", [[5, :line],
[5, :rescue]]]]]],
[["<class:D>@17", [[17, :class], [["<class:D>@17", [[17, :class],
[18, :end]]]]], collect_iseq.call(sample_iseq) [18, :end]]]]], collect_iseq.call(sample_iseq)
end end

View File

@ -2749,4 +2749,51 @@ CODE
raise_line = lines.shift raise_line = lines.shift
assert_equal [], lines assert_equal [], lines
end end
def helper_can_rescue
begin
raise __LINE__.to_s
rescue SyntaxError
:ng
rescue
:ok
end
end
def helper_can_rescue_empty_body
begin
raise __LINE__.to_s
rescue SyntaxError
:ng
rescue
end
end
def test_tp_rescue_event
lines = []
TracePoint.new(:rescue){|tp|
next unless target_thread?
lines << [tp.lineno, tp.raised_exception]
}.enable{
helper_can_rescue
}
line, err, = lines.pop
assert_equal [], lines
assert err.kind_of?(RuntimeError)
assert_equal err.message.to_i + 4, line
lines = []
TracePoint.new(:rescue){|tp|
next unless target_thread?
lines << [tp.lineno, tp.raised_exception]
}.enable{
helper_can_rescue_empty_body
}
line, err, = lines.pop
assert_equal [], lines
assert err.kind_of?(RuntimeError)
assert_equal err.message.to_i + 3, line
end
end end

View File

@ -6483,6 +6483,14 @@ rb_vm_opt_cfunc_p(CALL_CACHE cc, int insn)
} \ } \
} while (0) } while (0)
static VALUE
rescue_errinfo(rb_execution_context_t *ec, rb_control_frame_t *cfp)
{
VM_ASSERT(VM_FRAME_RUBYFRAME_P(cfp));
VM_ASSERT(ISEQ_BODY(cfp->iseq)->type == ISEQ_TYPE_RESCUE);
return cfp->ep[VM_ENV_INDEX_LAST_LVAR];
}
static void static void
vm_trace(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp) vm_trace(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp)
{ {
@ -6559,6 +6567,7 @@ vm_trace(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp)
vm_trace_hook(ec, reg_cfp, pc, RUBY_EVENT_CALL, RUBY_EVENT_CALL, global_hooks, bmethod_local_hooks_ptr, Qundef); vm_trace_hook(ec, reg_cfp, pc, RUBY_EVENT_CALL, RUBY_EVENT_CALL, global_hooks, bmethod_local_hooks_ptr, Qundef);
} }
VM_TRACE_HOOK(RUBY_EVENT_CLASS | RUBY_EVENT_CALL | RUBY_EVENT_B_CALL, Qundef); VM_TRACE_HOOK(RUBY_EVENT_CLASS | RUBY_EVENT_CALL | RUBY_EVENT_B_CALL, Qundef);
VM_TRACE_HOOK(RUBY_EVENT_RESCUE, rescue_errinfo(ec, reg_cfp));
VM_TRACE_HOOK(RUBY_EVENT_LINE, Qundef); VM_TRACE_HOOK(RUBY_EVENT_LINE, Qundef);
VM_TRACE_HOOK(RUBY_EVENT_COVERAGE_LINE, Qundef); VM_TRACE_HOOK(RUBY_EVENT_COVERAGE_LINE, Qundef);
VM_TRACE_HOOK(RUBY_EVENT_COVERAGE_BRANCH, Qundef); VM_TRACE_HOOK(RUBY_EVENT_COVERAGE_BRANCH, Qundef);

View File

@ -681,6 +681,7 @@ get_event_id(rb_event_flag_t event)
C(thread_end, THREAD_END); C(thread_end, THREAD_END);
C(fiber_switch, FIBER_SWITCH); C(fiber_switch, FIBER_SWITCH);
C(script_compiled, SCRIPT_COMPILED); C(script_compiled, SCRIPT_COMPILED);
C(rescue, RESCUE);
#undef C #undef C
default: default:
return 0; return 0;
@ -697,8 +698,8 @@ get_path_and_lineno(const rb_execution_context_t *ec, const rb_control_frame_t *
*pathp = rb_iseq_path(iseq); *pathp = rb_iseq_path(iseq);
if (event & (RUBY_EVENT_CLASS | if (event & (RUBY_EVENT_CLASS |
RUBY_EVENT_CALL | RUBY_EVENT_CALL |
RUBY_EVENT_B_CALL)) { RUBY_EVENT_B_CALL)) {
*linep = FIX2INT(rb_iseq_first_lineno(iseq)); *linep = FIX2INT(rb_iseq_first_lineno(iseq));
} }
else { else {
@ -823,6 +824,7 @@ symbol2event_flag(VALUE v)
C(thread_end, THREAD_END); C(thread_end, THREAD_END);
C(fiber_switch, FIBER_SWITCH); C(fiber_switch, FIBER_SWITCH);
C(script_compiled, SCRIPT_COMPILED); C(script_compiled, SCRIPT_COMPILED);
C(rescue, RESCUE);
/* joke */ /* joke */
C(a_call, A_CALL); C(a_call, A_CALL);
@ -943,6 +945,7 @@ rb_tracearg_parameters(rb_trace_arg_t *trace_arg)
case RUBY_EVENT_CLASS: case RUBY_EVENT_CLASS:
case RUBY_EVENT_END: case RUBY_EVENT_END:
case RUBY_EVENT_SCRIPT_COMPILED: case RUBY_EVENT_SCRIPT_COMPILED:
case RUBY_EVENT_RESCUE:
rb_raise(rb_eRuntimeError, "not supported by this event"); rb_raise(rb_eRuntimeError, "not supported by this event");
break; break;
} }
@ -1013,7 +1016,7 @@ rb_tracearg_return_value(rb_trace_arg_t *trace_arg)
VALUE VALUE
rb_tracearg_raised_exception(rb_trace_arg_t *trace_arg) rb_tracearg_raised_exception(rb_trace_arg_t *trace_arg)
{ {
if (trace_arg->event & (RUBY_EVENT_RAISE)) { if (trace_arg->event & (RUBY_EVENT_RAISE | RUBY_EVENT_RESCUE)) {
/* ok */ /* ok */
} }
else { else {