Skip to content

Commit

Permalink
support rescue event for TracePoint
Browse files Browse the repository at this point in the history
fix [Feature #19572]
  • Loading branch information
ko1 committed Aug 1, 2023
1 parent 7254c3c commit 899c58b
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 9 deletions.
14 changes: 13 additions & 1 deletion compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -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_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) {
ADD_INSN(ret, line_node, nop);
}
Expand Down Expand Up @@ -10406,6 +10417,7 @@ event_name_to_flag(VALUE sym)
CHECK_EVENT(RUBY_EVENT_RETURN);
CHECK_EVENT(RUBY_EVENT_B_CALL);
CHECK_EVENT(RUBY_EVENT_B_RETURN);
CHECK_EVENT(RUBY_EVENT_RESCUE);
#undef CHECK_EVENT
return RUBY_EVENT_NONE;
}
Expand Down
1 change: 1 addition & 0 deletions include/ruby/internal/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
#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_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. */

/** @} */
Expand Down
5 changes: 4 additions & 1 deletion iseq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
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_CLASS ? "Cl" : "",
events & RUBY_EVENT_END ? "En" : "",
Expand All @@ -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_B_CALL ? "Bc" : "",
events & RUBY_EVENT_B_RETURN ? "Br" : "",
events & RUBY_EVENT_RESCUE ? "Rs" : "",
events & RUBY_EVENT_COVERAGE_LINE ? "Cli" : "",
events & RUBY_EVENT_COVERAGE_BRANCH ? "Cbr" : "");
}
Expand Down Expand Up @@ -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_RETURN, "return", INT2FIX(line));
C(RUBY_EVENT_B_RETURN, "b_return", INT2FIX(line));
C(RUBY_EVENT_RESCUE, "rescue", INT2FIX(line));
#undef C
}

Expand Down Expand Up @@ -3090,6 +3092,7 @@ iseq_data_to_ary(const rb_iseq_t *iseq)
CHECK_EVENT(RUBY_EVENT_RETURN);
CHECK_EVENT(RUBY_EVENT_B_CALL);
CHECK_EVENT(RUBY_EVENT_B_RETURN);
CHECK_EVENT(RUBY_EVENT_RESCUE);
#undef CHECK_EVENT
prev_insn_info = info;
}
Expand Down
7 changes: 4 additions & 3 deletions iseq.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,10 @@ ISEQ_ORIGINAL_ISEQ_ALLOC(const rb_iseq_t *iseq, long size)
RUBY_EVENT_CALL | \
RUBY_EVENT_RETURN| \
RUBY_EVENT_C_CALL| \
RUBY_EVENT_C_RETURN| \
RUBY_EVENT_B_CALL| \
RUBY_EVENT_B_RETURN| \
RUBY_EVENT_C_RETURN | \
RUBY_EVENT_B_CALL | \
RUBY_EVENT_B_RETURN | \
RUBY_EVENT_RESCUE | \
RUBY_EVENT_COVERAGE_LINE| \
RUBY_EVENT_COVERAGE_BRANCH)

Expand Down
3 changes: 2 additions & 1 deletion test/ruby/test_iseq.rb
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,8 @@ def test_trace_points
[7, :line],
[9, :return]]],
[["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],
[18, :end]]]]], collect_iseq.call(sample_iseq)
end
Expand Down
47 changes: 47 additions & 0 deletions test/ruby/test_settracefunc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2749,4 +2749,51 @@ def test_tp_rescue
raise_line = lines.shift
assert_equal [], lines
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
9 changes: 9 additions & 0 deletions vm_insnhelper.c
Original file line number Diff line number Diff line change
Expand Up @@ -6483,6 +6483,14 @@ rb_vm_opt_cfunc_p(CALL_CACHE cc, int insn)
} \
} 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
vm_trace(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp)
{
Expand Down Expand Up @@ -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(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_COVERAGE_LINE, Qundef);
VM_TRACE_HOOK(RUBY_EVENT_COVERAGE_BRANCH, Qundef);
Expand Down
9 changes: 6 additions & 3 deletions vm_trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,7 @@ get_event_id(rb_event_flag_t event)
C(thread_end, THREAD_END);
C(fiber_switch, FIBER_SWITCH);
C(script_compiled, SCRIPT_COMPILED);
C(rescue, RESCUE);
#undef C
default:
return 0;
Expand All @@ -697,8 +698,8 @@ get_path_and_lineno(const rb_execution_context_t *ec, const rb_control_frame_t *
*pathp = rb_iseq_path(iseq);

if (event & (RUBY_EVENT_CLASS |
RUBY_EVENT_CALL |
RUBY_EVENT_B_CALL)) {
RUBY_EVENT_CALL |
RUBY_EVENT_B_CALL)) {
*linep = FIX2INT(rb_iseq_first_lineno(iseq));
}
else {
Expand Down Expand Up @@ -823,6 +824,7 @@ symbol2event_flag(VALUE v)
C(thread_end, THREAD_END);
C(fiber_switch, FIBER_SWITCH);
C(script_compiled, SCRIPT_COMPILED);
C(rescue, RESCUE);

/* joke */
C(a_call, A_CALL);
Expand Down Expand Up @@ -943,6 +945,7 @@ rb_tracearg_parameters(rb_trace_arg_t *trace_arg)
case RUBY_EVENT_CLASS:
case RUBY_EVENT_END:
case RUBY_EVENT_SCRIPT_COMPILED:
case RUBY_EVENT_RESCUE:
rb_raise(rb_eRuntimeError, "not supported by this event");
break;
}
Expand Down Expand Up @@ -1013,7 +1016,7 @@ rb_tracearg_return_value(rb_trace_arg_t *trace_arg)
VALUE
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 */
}
else {
Expand Down

0 comments on commit 899c58b

Please sign in to comment.