Project

General

Profile

Feature #13265 ยป 0001-Add-TracePoint-for-basic-operation-redefinition.patch

Patch for feature - magaudet (Matthew Gaudet), 03/01/2017 02:40 PM

View differences:

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);
    (1-1/1)