Feature #13265 ยป 0001-Add-TracePoint-for-basic-operation-redefinition.patch
include/ruby/ruby.h | ||
---|---|---|
#define RUBY_EVENT_ALL 0x00ff
|
||
/* for TracePoint extended events */
|
||
#define RUBY_EVENT_B_CALL 0x0100
|
||
#define RUBY_EVENT_B_RETURN 0x0200
|
||
#define RUBY_EVENT_THREAD_BEGIN 0x0400
|
||
#define RUBY_EVENT_THREAD_END 0x0800
|
||
#define RUBY_EVENT_FIBER_SWITCH 0x1000
|
||
#define RUBY_EVENT_TRACEPOINT_ALL 0xffff
|
||
#define RUBY_EVENT_B_CALL 0x0100
|
||
#define RUBY_EVENT_B_RETURN 0x0200
|
||
#define RUBY_EVENT_THREAD_BEGIN 0x0400
|
||
#define RUBY_EVENT_THREAD_END 0x0800
|
||
#define RUBY_EVENT_FIBER_SWITCH 0x1000
|
||
#define RUBY_EVENT_BASIC_OP_REDEFINED 0x2000
|
||
#define RUBY_EVENT_TRACEPOINT_ALL 0xffff
|
||
/* special events */
|
||
#define RUBY_EVENT_SPECIFIED_LINE 0x010000
|
test/ruby/test_settracefunc.rb | ||
---|---|---|
assert_equal [[:c_call, :itself, :alias_itself], [:c_return, :itself, :alias_itself]], events
|
||
events.clear
|
||
end
|
||
def test_basic_op_redefinition_tracepoint
|
||
events = []
|
||
TracePoint.new(:basic_op_redefined) { |tp|
|
||
next if !target_thread?
|
||
events << [tp.event, tp.basic_operation_redefined ]
|
||
}.enable {
|
||
String.class_eval do
|
||
def +(s)
|
||
self.concat(s)
|
||
end
|
||
end
|
||
}
|
||
assert_equal events.length, 1, "Events #{events}"
|
||
assert_equal events[0][0], :basic_op_redefined
|
||
assert_equal events[0][1][:klass], String
|
||
assert_equal events[0][1][:bop], :BOP_PLUS
|
||
end
|
||
end
|
vm.c | ||
---|---|---|
int flag = vm_redefinition_check_flag(klass);
|
||
ruby_vm_redefined_flag[bop] |= flag;
|
||
EXEC_EVENT_HOOK(GET_THREAD(), RUBY_EVENT_BASIC_OP_REDEFINED, GET_THREAD()->cfp->self, 0, 0, klass, bop);
|
||
}
|
||
}
|
||
}
|
vm_trace.c | ||
---|---|---|
C(thread_end, THREAD_END);
|
||
C(fiber_switch, FIBER_SWITCH);
|
||
C(specified_line, SPECIFIED_LINE);
|
||
C(basic_op_redefined, BASIC_OP_REDEFINED);
|
||
case RUBY_EVENT_LINE | RUBY_EVENT_SPECIFIED_LINE: CONST_ID(id, "line"); return id;
|
||
#undef C
|
||
default:
|
||
... | ... | |
C(specified_line, SPECIFIED_LINE);
|
||
C(a_call, A_CALL);
|
||
C(a_return, A_RETURN);
|
||
C(basic_op_redefined, BASIC_OP_REDEFINED);
|
||
#undef C
|
||
rb_raise(rb_eArgError, "unknown event: %"PRIsVALUE, rb_sym2str(sym));
|
||
}
|
||
... | ... | |
}
|
||
VALUE
|
||
rb_tracearg_basic_op_redefined(rb_trace_arg_t *trace_arg)
|
||
{
|
||
const char * basic_operator_names[] = {
|
||
"BOP_PLUS",
|
||
"BOP_MINUS",
|
||
"BOP_MULT",
|
||
"BOP_DIV",
|
||
"BOP_MOD",
|
||
"BOP_EQ",
|
||
"BOP_EQQ",
|
||
"BOP_LT",
|
||
"BOP_LE",
|
||
"BOP_LTLT",
|
||
"BOP_AREF",
|
||
"BOP_ASET",
|
||
"BOP_LENGTH",
|
||
"BOP_SIZE",
|
||
"BOP_EMPTY_P",
|
||
"BOP_SUCC",
|
||
"BOP_GT",
|
||
"BOP_GE",
|
||
"BOP_NOT",
|
||
"BOP_NEQ",
|
||
"BOP_MATCH",
|
||
"BOP_FREEZE",
|
||
"BOP_MAX",
|
||
"BOP_MIN",
|
||
NULL
|
||
};
|
||
VALUE bop, klass, hash;
|
||
if (trace_arg->event & (RUBY_EVENT_BASIC_OP_REDEFINED)) {
|
||
/* ok */
|
||
}
|
||
else {
|
||
rb_raise(rb_eRuntimeError, "not supported by this event");
|
||
}
|
||
if (trace_arg->data == Qundef) {
|
||
rb_bug("tp_basic_op_redefined_m: unreachable");
|
||
}
|
||
bop = trace_arg->data;
|
||
klass = trace_arg->klass;
|
||
if (bop > BOP_LAST_) {
|
||
rb_bug("rb_tracearg_basic_op_redefined: Invalid bop %d", bop);
|
||
}
|
||
hash = rb_hash_new();
|
||
rb_hash_aset(hash, ID2SYM(rb_intern("klass")),klass);
|
||
rb_hash_aset(hash, ID2SYM(rb_intern("bop")), ID2SYM(rb_intern(basic_operator_names[bop])));
|
||
return hash;
|
||
}
|
||
VALUE
|
||
rb_tracearg_raised_exception(rb_trace_arg_t *trace_arg)
|
||
{
|
||
if (trace_arg->event & (RUBY_EVENT_RAISE)) {
|
||
... | ... | |
return rb_tracearg_raised_exception(get_trace_arg());
|
||
}
|
||
/*
|
||
* klass and basic operation redefined on :basic_op_redefinition event.
|
||
*/
|
||
static VALUE
|
||
tracepoint_basic_operation_redefined(VALUE tpval)
|
||
{
|
||
return rb_tracearg_basic_op_redefined(get_trace_arg());
|
||
}
|
||
static void
|
||
tp_call_trace(VALUE tpval, rb_trace_arg_t *trace_arg)
|
||
{
|
||
... | ... | |
rb_define_method(rb_cTracePoint, "self", tracepoint_attr_self, 0);
|
||
rb_define_method(rb_cTracePoint, "return_value", tracepoint_attr_return_value, 0);
|
||
rb_define_method(rb_cTracePoint, "raised_exception", tracepoint_attr_raised_exception, 0);
|
||
rb_define_method(rb_cTracePoint, "basic_operation_redefined", tracepoint_basic_operation_redefined, 0);
|
||
rb_define_singleton_method(rb_cTracePoint, "stat", tracepoint_stat_s, 0);
|
||