Created
January 6, 2010 23:21
-
-
Save methodmissing/270794 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/eval.c b/eval.c | |
| index 057afd9..aa50cb5 100644 | |
| --- a/eval.c | |
| +++ b/eval.c | |
| @@ -371,69 +371,10 @@ struct cache_entry { /* method hash table. */ | |
| static struct cache_entry cache[CACHE_SIZE]; | |
| static int ruby_running = 0; | |
| -void | |
| -rb_clear_cache() | |
| -{ | |
| - struct cache_entry *ent, *end; | |
| - | |
| - if (!ruby_running) return; | |
| - ent = cache; end = ent + CACHE_SIZE; | |
| - while (ent < end) { | |
| - ent->mid = 0; | |
| - ent++; | |
| - } | |
| -} | |
| - | |
| -static void | |
| -rb_clear_cache_for_undef(klass, id) | |
| - VALUE klass; | |
| - ID id; | |
| -{ | |
| - struct cache_entry *ent, *end; | |
| - | |
| - if (!ruby_running) return; | |
| - ent = cache; end = ent + CACHE_SIZE; | |
| - while (ent < end) { | |
| - if (ent->mid == id && | |
| - (ent->klass == klass || | |
| - RCLASS(ent->origin)->m_tbl == RCLASS(klass)->m_tbl)) { | |
| - ent->mid = 0; | |
| - } | |
| - ent++; | |
| - } | |
| -} | |
| - | |
| -static void | |
| -rb_clear_cache_by_id(id) | |
| - ID id; | |
| -{ | |
| - struct cache_entry *ent, *end; | |
| - | |
| - if (!ruby_running) return; | |
| - ent = cache; end = ent + CACHE_SIZE; | |
| - while (ent < end) { | |
| - if (ent->mid == id) { | |
| - ent->mid = 0; | |
| - } | |
| - ent++; | |
| - } | |
| -} | |
| - | |
| -void | |
| -rb_clear_cache_by_class(klass) | |
| - VALUE klass; | |
| -{ | |
| - struct cache_entry *ent, *end; | |
| - | |
| - if (!ruby_running) return; | |
| - ent = cache; end = ent + CACHE_SIZE; | |
| - while (ent < end) { | |
| - if (ent->klass == klass || ent->origin == klass) { | |
| - ent->mid = 0; | |
| - } | |
| - ent++; | |
| - } | |
| -} | |
| +void rb_clear_cache(); | |
| +static void rb_clear_cache_for_undef(VALUE klass, ID id); | |
| +static void rb_clear_cache_by_id(ID id); | |
| +void rb_clear_cache_by_class(VALUE klass); | |
| static ID init, eqq, each, aref, aset, match, missing; | |
| static ID added, singleton_added; | |
| @@ -1213,6 +1154,73 @@ static VALUE trace_func = 0; | |
| static int tracing = 0; | |
| static void call_trace_func _((rb_event_t,NODE*,VALUE,ID,VALUE)); | |
| +void | |
| +rb_clear_cache() | |
| +{ | |
| + struct cache_entry *ent, *end; | |
| + if (!ruby_running) return; | |
| + EXEC_EVENT_HOOK(RUBY_EVENT_METHOD_CACHE_CLEARED, ruby_current_node, | |
| + ruby_frame->self, | |
| + ruby_frame->last_func, | |
| + ruby_frame->last_class); | |
| + ent = cache; end = ent + CACHE_SIZE; | |
| + while (ent < end) { | |
| + ent->mid = 0; | |
| + ent++; | |
| + } | |
| +} | |
| + | |
| +static void | |
| +rb_clear_cache_for_undef(klass, id) | |
| + VALUE klass; | |
| + ID id; | |
| +{ | |
| + struct cache_entry *ent, *end; | |
| + | |
| + if (!ruby_running) return; | |
| + ent = cache; end = ent + CACHE_SIZE; | |
| + while (ent < end) { | |
| + if (ent->mid == id && | |
| + (ent->klass == klass || | |
| + RCLASS(ent->origin)->m_tbl == RCLASS(klass)->m_tbl)) { | |
| + ent->mid = 0; | |
| + } | |
| + ent++; | |
| + } | |
| +} | |
| + | |
| +static void | |
| +rb_clear_cache_by_id(id) | |
| + ID id; | |
| +{ | |
| + struct cache_entry *ent, *end; | |
| + | |
| + if (!ruby_running) return; | |
| + ent = cache; end = ent + CACHE_SIZE; | |
| + while (ent < end) { | |
| + if (ent->mid == id) { | |
| + ent->mid = 0; | |
| + } | |
| + ent++; | |
| + } | |
| +} | |
| + | |
| +void | |
| +rb_clear_cache_by_class(klass) | |
| + VALUE klass; | |
| +{ | |
| + struct cache_entry *ent, *end; | |
| + | |
| + if (!ruby_running) return; | |
| + ent = cache; end = ent + CACHE_SIZE; | |
| + while (ent < end) { | |
| + if (ent->klass == klass || ent->origin == klass) { | |
| + ent->mid = 0; | |
| + } | |
| + ent++; | |
| + } | |
| +} | |
| + | |
| static void | |
| #ifdef HAVE_STDARG_PROTOTYPES | |
| warn_printf(const char *fmt, ...) | |
| @@ -2740,6 +2748,8 @@ get_event_name(rb_event_t event) | |
| return "c-return"; | |
| case RUBY_EVENT_RAISE: | |
| return "raise"; | |
| + case RUBY_EVENT_METHOD_CACHE_CLEARED: | |
| + return "method-cache-cleared"; | |
| default: | |
| return "unknown"; | |
| } | |
| diff --git a/node.h b/node.h | |
| index 1242be5..d7edbdb 100644 | |
| --- a/node.h | |
| +++ b/node.h | |
| @@ -359,16 +359,17 @@ VALUE rb_gvar_defined _((struct global_entry *)); | |
| typedef unsigned int rb_event_t; | |
| -#define RUBY_EVENT_NONE 0x00 | |
| -#define RUBY_EVENT_LINE 0x01 | |
| -#define RUBY_EVENT_CLASS 0x02 | |
| -#define RUBY_EVENT_END 0x04 | |
| -#define RUBY_EVENT_CALL 0x08 | |
| -#define RUBY_EVENT_RETURN 0x10 | |
| -#define RUBY_EVENT_C_CALL 0x20 | |
| -#define RUBY_EVENT_C_RETURN 0x40 | |
| -#define RUBY_EVENT_RAISE 0x80 | |
| -#define RUBY_EVENT_ALL 0xff | |
| +#define RUBY_EVENT_NONE 0x00 | |
| +#define RUBY_EVENT_LINE 0x01 | |
| +#define RUBY_EVENT_CLASS 0x02 | |
| +#define RUBY_EVENT_END 0x04 | |
| +#define RUBY_EVENT_CALL 0x08 | |
| +#define RUBY_EVENT_RETURN 0x10 | |
| +#define RUBY_EVENT_C_CALL 0x20 | |
| +#define RUBY_EVENT_C_RETURN 0x40 | |
| +#define RUBY_EVENT_RAISE 0x80 | |
| +#define RUBY_EVENT_METHOD_CACHE_CLEARED 0x81 | |
| +#define RUBY_EVENT_ALL 0xff | |
| typedef void (*rb_event_hook_func_t) _((rb_event_t,NODE*,VALUE,ID,VALUE)); | |
| NODE *rb_copy_node_scope _((NODE *, NODE *)); | |
| diff --git a/test/ruby/test_settracefunc.rb b/test/ruby/test_settracefunc.rb | |
| index 14d6679..a5bd3cc 100644 | |
| --- a/test/ruby/test_settracefunc.rb | |
| +++ b/test/ruby/test_settracefunc.rb | |
| @@ -33,6 +33,7 @@ class TestSetTraceFunc < Test::Unit::TestCase | |
| rescue | |
| end | |
| eval("class Foo; end") | |
| + Foo.__send__ :include, Comparable | |
| set_trace_func nil | |
| assert_equal(["line", 19, :test_event, TestSetTraceFunc], | |
| @@ -122,8 +123,28 @@ class TestSetTraceFunc < Test::Unit::TestCase | |
| assert_equal(["c-return", 35, :eval, Kernel], | |
| events.shift) # eval(<<EOF) | |
| assert_equal(["line", 36, :test_event, TestSetTraceFunc], | |
| + events.shift) # Foo.__send__ :include, Comparable | |
| + assert_equal(["c-call", 36, :__send__, Kernel], | |
| + events.shift) # Foo.__send__ :include, Comparable | |
| + assert_equal(["c-call", 36, :include, Module], | |
| + events.shift) # Foo.__send__ :include, Comparable | |
| + assert_equal(["c-call", 36, :append_features, Module], | |
| + events.shift) # Foo.__send__ :include, Comparable | |
| + assert_equal(["method-cache-cleared", 36, :append_features, Module], | |
| + events.shift) # Foo.__send__ :include, Comparable | |
| + assert_equal(["c-return", 36, :append_features, Module], | |
| + events.shift) # Foo.__send__ :include, Comparable | |
| + assert_equal(["c-call", 36, :included, Module], | |
| + events.shift) # Foo.__send__ :include, Comparable | |
| + assert_equal(["c-return", 36, :included, Module], | |
| + events.shift) # Foo.__send__ :include, Comparable | |
| + assert_equal(["c-return", 36, :include, Module], | |
| + events.shift) # Foo.__send__ :include, Comparable | |
| + assert_equal(["c-return", 36, :__send__, Kernel], | |
| + events.shift) # Foo.__send__ :include, Comparable | |
| + assert_equal(["line", 37, :test_event, TestSetTraceFunc], | |
| events.shift) # set_trace_func nil | |
| - assert_equal(["c-call", 36, :set_trace_func, Kernel], | |
| + assert_equal(["c-call", 37, :set_trace_func, Kernel], | |
| events.shift) # set_trace_func nil | |
| assert_equal([], events) | |
| @@ -131,8 +152,8 @@ class TestSetTraceFunc < Test::Unit::TestCase | |
| set_trace_func(nil) | |
| assert_equal(["line", 11, :bar, TestSetTraceFunc], events.shift) | |
| assert_equal(["return", 11, :bar, TestSetTraceFunc], events.shift) | |
| - assert_equal(["line", 131, :test_event, TestSetTraceFunc], events.shift) | |
| - assert_equal(["c-call", 131, :set_trace_func, Kernel], events.shift) | |
| + assert_equal(["line", 152, :test_event, TestSetTraceFunc], events.shift) | |
| + assert_equal(["c-call", 152, :set_trace_func, Kernel], events.shift) | |
| assert_equal([], events) | |
| end | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| methodmissing:rubyenterpriseedition187-248 lourens$ ./miniruby subject.rb | |
| ["subject.rb:15 Module#append_features", "subject.rb:20 Module#extend_object"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| invalidations = [] | |
| set_trace_func(Proc.new { |event, file, lineno, mid, bidning, klass| | |
| invalidations << "#{file}:#{lineno} #{klass}##{mid}" if event == 'method-cache-cleared' | |
| }) | |
| module A | |
| def to_s; 'A'; end | |
| end | |
| module B | |
| def to_s; 'B'; end | |
| end | |
| class Test | |
| include A | |
| undef to_s | |
| end | |
| t = Test.new | |
| t.extend B | |
| t.to_s | |
| set_trace_func(nil) | |
| puts invalidations.inspect |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment