Skip to content
This repository has been archived by the owner on Jul 25, 2022. It is now read-only.

Commit

Permalink
Add constant redefinition tracepoint.
Browse files Browse the repository at this point in the history
Allow an interested party (like a JIT compiler) to be notified if/when a
constant is redefined.

The added tracepoint returns the class, variable, and new value of the
constant.

(cherry picked from commit 93bcbc3)
  • Loading branch information
Matthew Gaudet committed Mar 3, 2017
1 parent c5c64fb commit 6180c8e
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 0 deletions.
1 change: 1 addition & 0 deletions include/ruby/ruby.h
Expand Up @@ -2065,6 +2065,7 @@ int ruby_native_thread_p(void);
#define RUBY_EVENT_THREAD_END 0x0800
#define RUBY_EVENT_FIBER_SWITCH 0x1000
#define RUBY_EVENT_BASIC_OP_REDEFINED 0x2000
#define RUBY_EVENT_CONSTANT_REDEFINED 0x4000
#define RUBY_EVENT_TRACEPOINT_ALL 0xffff

/* special events */
Expand Down
16 changes: 16 additions & 0 deletions test/ruby/test_settracefunc.rb
@@ -1,6 +1,10 @@
# frozen_string_literal: false
require 'test/unit'

module ModuleForConst
P = 0
end

class TestSetTraceFunc < Test::Unit::TestCase
def setup
@original_compile_option = RubyVM::InstructionSequence.compile_option
Expand Down Expand Up @@ -1617,4 +1621,16 @@ def +(s)
assert_equal events[0][1][:klass], String
assert_equal events[0][1][:bop], :BOP_PLUS
end

def test_constant_redefinition_tracepoint
events = []
TracePoint.new(:constant_redefined) { |tp|
next if !target_thread?
events << [tp.event, tp.constant_redefined ]
}.enable {
ModuleForConst.const_set('P', 1)
}
assert_equal events.length, 1, "Events #{events}"
assert_equal events[0][0], :constant_redefined
end
end
2 changes: 2 additions & 0 deletions variable.c
Expand Up @@ -19,6 +19,7 @@
#include "id.h"
#include "ccan/list/list.h"
#include "id_table.h"
#include "vm_core.h"

struct rb_id_table *rb_global_tbl;
static ID autoload, classpath, tmp_classpath, classid;
Expand Down Expand Up @@ -2653,6 +2654,7 @@ const_tbl_update(struct autoload_const_set_args *args)
rb_compile_warn(RSTRING_PTR(ce->file), ce->line,
"previous definition of %"PRIsVALUE" was here", name);
}
EXEC_EVENT_HOOK(GET_THREAD(), RUBY_EVENT_CONSTANT_REDEFINED, klass, 0, 0, ID2SYM(id), val);
}
rb_clear_constant_cache();
setup_const_entry(ce, klass, val, visibility);
Expand Down
33 changes: 33 additions & 0 deletions vm_trace.c
Expand Up @@ -599,6 +599,7 @@ get_event_id(rb_event_flag_t event)
C(fiber_switch, FIBER_SWITCH);
C(specified_line, SPECIFIED_LINE);
C(basic_op_redefined, BASIC_OP_REDEFINED);
C(constant_redefined, CONSTANT_REDEFINED);
case RUBY_EVENT_LINE | RUBY_EVENT_SPECIFIED_LINE: CONST_ID(id, "line"); return id;
#undef C
default:
Expand Down Expand Up @@ -708,6 +709,7 @@ symbol2event_flag(VALUE v)
C(a_call, A_CALL);
C(a_return, A_RETURN);
C(basic_op_redefined, BASIC_OP_REDEFINED);
C(constant_redefined, CONSTANT_REDEFINED);
#undef C
rb_raise(rb_eArgError, "unknown event: %"PRIsVALUE, rb_sym2str(sym));
}
Expand Down Expand Up @@ -909,6 +911,26 @@ rb_tracearg_basic_op_redefined(rb_trace_arg_t *trace_arg)
return hash;
}

VALUE
rb_tracearg_constant_redefined(rb_trace_arg_t *trace_arg)
{
VALUE hash;
if (trace_arg->event & (RUBY_EVENT_CONSTANT_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");
}

hash = rb_hash_new();
rb_hash_aset(hash, ID2SYM(rb_intern("klass")), trace_arg->self);
rb_hash_aset(hash, ID2SYM(rb_intern("variable")), trace_arg->klass);
rb_hash_aset(hash, ID2SYM(rb_intern("value")), trace_arg->data);
return hash;
}

VALUE
rb_tracearg_raised_exception(rb_trace_arg_t *trace_arg)
Expand Down Expand Up @@ -1075,6 +1097,16 @@ tracepoint_basic_operation_redefined(VALUE tpval)
return rb_tracearg_basic_op_redefined(get_trace_arg());
}

/*
* klass and constant redefined on :basic_op_redefinition event.
*/
static VALUE
tracepoint_constant_redefined(VALUE tpval)
{
return rb_tracearg_constant_redefined(get_trace_arg());
}


static void
tp_call_trace(VALUE tpval, rb_trace_arg_t *trace_arg)
{
Expand Down Expand Up @@ -1569,6 +1601,7 @@ Init_vm_trace(void)
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_method(rb_cTracePoint, "constant_redefined", tracepoint_constant_redefined, 0);

rb_define_singleton_method(rb_cTracePoint, "stat", tracepoint_stat_s, 0);

Expand Down

0 comments on commit 6180c8e

Please sign in to comment.