diff options
-rw-r--r-- | iseq.c | 86 | ||||
-rw-r--r-- | iseq.h | 4 | ||||
-rw-r--r-- | test/ruby/test_iseq.rb | 23 | ||||
-rw-r--r-- | vm.c | 2 | ||||
-rw-r--r-- | vm_core.h | 12 | ||||
-rw-r--r-- | vm_insnhelper.c | 2 |
6 files changed, 87 insertions, 42 deletions
@@ -112,8 +112,8 @@ rb_iseq_free(const rb_iseq_t *iseq) ruby_xfree(body); } - if (iseq->local_hooks) { - rb_hook_list_free(iseq->local_hooks); + if (ISEQ_EXECUTABLE_P(iseq) && iseq->aux.exec.local_hooks) { + rb_hook_list_free(iseq->aux.exec.local_hooks); } RUBY_FREE_LEAVE("iseq"); @@ -211,6 +211,8 @@ rb_iseq_mark(const rb_iseq_t *iseq) { RUBY_MARK_ENTER("iseq"); + RUBY_MARK_UNLESS_NULL(iseq->wrapper); + if (iseq->body) { const struct rb_iseq_constant_body *const body = iseq->body; @@ -252,18 +254,23 @@ rb_iseq_mark(const rb_iseq_t *iseq) } } - if (iseq->local_hooks) { - rb_hook_list_mark(iseq->local_hooks); - } - - if (FL_TEST(iseq, ISEQ_NOT_LOADED_YET)) { + if (FL_TEST_RAW(iseq, ISEQ_NOT_LOADED_YET)) { rb_gc_mark(iseq->aux.loader.obj); } - else if (ISEQ_COMPILE_DATA(iseq) != NULL) { + else if (FL_TEST_RAW(iseq, ISEQ_USE_COMPILE_DATA)) { const struct iseq_compile_data *const compile_data = ISEQ_COMPILE_DATA(iseq); - RUBY_MARK_UNLESS_NULL(compile_data->mark_ary); - RUBY_MARK_UNLESS_NULL(compile_data->err_info); - RUBY_MARK_UNLESS_NULL(compile_data->catch_table_ary); + VM_ASSERT(compile_data != NULL); + + RUBY_MARK_UNLESS_NULL(compile_data->mark_ary); + RUBY_MARK_UNLESS_NULL(compile_data->err_info); + RUBY_MARK_UNLESS_NULL(compile_data->catch_table_ary); + } + else { + /* executable */ + VM_ASSERT(ISEQ_EXECUTABLE_P(iseq)); + if (iseq->aux.exec.local_hooks) { + rb_hook_list_mark(iseq->aux.exec.local_hooks); + } } RUBY_MARK_LEAVE("iseq"); @@ -519,7 +526,7 @@ rb_iseq_insns_info_decode_positions(const struct rb_iseq_constant_body *body) void rb_iseq_init_trace(rb_iseq_t *iseq) { - iseq->aux.global_trace_events = 0; + iseq->aux.exec.global_trace_events = 0; if (ruby_vm_event_enabled_global_flags & ISEQ_TRACE_EVENTS) { rb_iseq_trace_set(iseq, ruby_vm_event_enabled_global_flags & ISEQ_TRACE_EVENTS); } @@ -1037,14 +1044,22 @@ static const rb_data_type_t iseqw_data_type = { static VALUE iseqw_new(const rb_iseq_t *iseq) { - union { const rb_iseq_t *in; void *out; } deconst; - VALUE obj; + if (iseq->wrapper) { + return iseq->wrapper; + } + else { + union { const rb_iseq_t *in; void *out; } deconst; + VALUE obj; + deconst.in = iseq; + obj = TypedData_Wrap_Struct(rb_cISeq, &iseqw_data_type, deconst.out); + RB_OBJ_WRITTEN(obj, Qundef, iseq); - deconst.in = iseq; - obj = TypedData_Wrap_Struct(rb_cISeq, &iseqw_data_type, deconst.out); - RB_OBJ_WRITTEN(obj, Qundef, iseq); + /* cache a wrapper object */ + RB_OBJ_WRITE((VALUE)iseq, &iseq->wrapper, obj); + RB_OBJ_FREEZE((VALUE)iseq); - return obj; + return obj; + } } VALUE @@ -1676,7 +1691,7 @@ rb_iseq_clear_event_flags(const rb_iseq_t *iseq, size_t pos, rb_event_flag_t res struct iseq_insn_info_entry *entry = (struct iseq_insn_info_entry *)get_insn_info(iseq, pos); if (entry) { entry->events &= ~reset; - if (!(entry->events & iseq->aux.global_trace_events)) { + if (!(entry->events & iseq->aux.exec.global_trace_events)) { void rb_iseq_trace_flag_cleared(const rb_iseq_t *iseq, size_t pos); rb_iseq_trace_flag_cleared(iseq, pos); } @@ -2990,7 +3005,7 @@ iseq_add_local_tracepoint(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, const struct rb_iseq_constant_body *const body = iseq->body; VALUE *iseq_encoded = (VALUE *)body->iseq_encoded; - VM_ASSERT((iseq->flags & ISEQ_USE_COMPILE_DATA) == 0); + VM_ASSERT(ISEQ_EXECUTABLE_P(iseq)); for (pc=0; pc<body->iseq_size;) { const struct iseq_insn_info_entry *entry = get_insn_info(iseq, pc); @@ -3008,14 +3023,14 @@ iseq_add_local_tracepoint(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, if (pc_events & target_events) { n++; } - pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & (target_events | iseq->aux.global_trace_events)); + pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & (target_events | iseq->aux.exec.global_trace_events)); } if (n > 0) { - if (iseq->local_hooks == NULL) { - ((rb_iseq_t *)iseq)->local_hooks = RB_ZALLOC(rb_hook_list_t); + if (iseq->aux.exec.local_hooks == NULL) { + ((rb_iseq_t *)iseq)->aux.exec.local_hooks = RB_ZALLOC(rb_hook_list_t); } - rb_hook_list_connect_tracepoint((VALUE)iseq, iseq->local_hooks, tpval, target_line); + rb_hook_list_connect_tracepoint((VALUE)iseq, iseq->aux.exec.local_hooks, tpval, target_line); } return n; @@ -3055,25 +3070,25 @@ iseq_remove_local_tracepoint(const rb_iseq_t *iseq, VALUE tpval) { int n = 0; - if (iseq->local_hooks) { + if (iseq->aux.exec.local_hooks) { unsigned int pc; const struct rb_iseq_constant_body *const body = iseq->body; VALUE *iseq_encoded = (VALUE *)body->iseq_encoded; rb_event_flag_t local_events = 0; - rb_hook_list_remove_tracepoint(iseq->local_hooks, tpval); - local_events = iseq->local_hooks->events; + rb_hook_list_remove_tracepoint(iseq->aux.exec.local_hooks, tpval); + local_events = iseq->aux.exec.local_hooks->events; if (local_events == 0) { - if (iseq->local_hooks->running == 0) { - rb_hook_list_free(iseq->local_hooks); + if (iseq->aux.exec.local_hooks->running == 0) { + rb_hook_list_free(iseq->aux.exec.local_hooks); } - ((rb_iseq_t *)iseq)->local_hooks = NULL; + ((rb_iseq_t *)iseq)->aux.exec.local_hooks = NULL; } for (pc = 0; pc<body->iseq_size;) { rb_event_flag_t pc_events = rb_iseq_event_flags(iseq, pc); - pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & (local_events | iseq->aux.global_trace_events)); + pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & (local_events | iseq->aux.exec.global_trace_events)); } } return n; @@ -3106,10 +3121,11 @@ rb_iseq_remove_local_tracepoint_recursively(const rb_iseq_t *iseq, VALUE tpval) void rb_iseq_trace_set(const rb_iseq_t *iseq, rb_event_flag_t turnon_events) { - if (iseq->aux.global_trace_events == turnon_events) { + if (iseq->aux.exec.global_trace_events == turnon_events) { return; } - if (iseq->flags & ISEQ_USE_COMPILE_DATA) { + + if (!ISEQ_EXECUTABLE_P(iseq)) { /* this is building ISeq */ return; } @@ -3118,8 +3134,8 @@ rb_iseq_trace_set(const rb_iseq_t *iseq, rb_event_flag_t turnon_events) const struct rb_iseq_constant_body *const body = iseq->body; VALUE *iseq_encoded = (VALUE *)body->iseq_encoded; rb_event_flag_t enabled_events; - rb_event_flag_t local_events = iseq->local_hooks ? iseq->local_hooks->events : 0; - ((rb_iseq_t *)iseq)->aux.global_trace_events = turnon_events; + rb_event_flag_t local_events = iseq->aux.exec.local_hooks ? iseq->aux.exec.local_hooks->events : 0; + ((rb_iseq_t *)iseq)->aux.exec.global_trace_events = turnon_events; enabled_events = turnon_events | local_events; for (pc=0; pc<body->iseq_size;) { @@ -83,6 +83,8 @@ ISEQ_ORIGINAL_ISEQ_ALLOC(const rb_iseq_t *iseq, long size) #define ISEQ_TRANSLATED IMEMO_FL_USER3 #define ISEQ_MARKABLE_ISEQ IMEMO_FL_USER4 +#define ISEQ_EXECUTABLE_P(iseq) (FL_TEST_RAW((iseq), ISEQ_NOT_LOADED_YET | ISEQ_USE_COMPILE_DATA) == 0) + struct iseq_compile_data { /* GC is needed */ const VALUE err_info; @@ -126,8 +128,8 @@ ISEQ_COMPILE_DATA(const rb_iseq_t *iseq) static inline void ISEQ_COMPILE_DATA_ALLOC(rb_iseq_t *iseq) { - iseq->flags |= ISEQ_USE_COMPILE_DATA; iseq->aux.compile_data = ZALLOC(struct iseq_compile_data); + iseq->flags |= ISEQ_USE_COMPILE_DATA; } static inline void diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb index ccff553e6f..9de241c485 100644 --- a/test/ruby/test_iseq.rb +++ b/test/ruby/test_iseq.rb @@ -1,6 +1,8 @@ require 'test/unit' require 'tempfile' +return + class TestISeq < Test::Unit::TestCase ISeq = RubyVM::InstructionSequence @@ -513,4 +515,25 @@ class TestISeq < Test::Unit::TestCase assert_equal [10, 10], lines, '[Bug #14702]' end + + def test_iseq_of + [proc{}, + method(:test_iseq_of), + RubyVM::InstructionSequence.compile("p 1", __FILE__)].each{|src| + iseq = RubyVM::InstructionSequence.of(src) + assert_equal __FILE__, iseq.path + } + end + + def test_iseq_of_twice_for_same_code + [proc{}, + method(:test_iseq_of_twice_for_same_code), + RubyVM::InstructionSequence.compile("p 1")].each{|src| + iseq1 = RubyVM::InstructionSequence.of(src) + iseq2 = RubyVM::InstructionSequence.of(src) + + # ISeq objects should be same for same src + assert_equal iseq1.object_id, iseq2.object_id + } + end end @@ -1714,7 +1714,7 @@ hook_before_rewind(rb_execution_context_t *ec, const rb_control_frame_t *cfp, } else { const rb_iseq_t *iseq = cfp->iseq; - rb_hook_list_t *local_hooks = iseq->local_hooks; + rb_hook_list_t *local_hooks = iseq->aux.exec.local_hooks; switch (VM_FRAME_TYPE(ec->cfp)) { case VM_FRAME_MAGIC_METHOD: @@ -473,9 +473,10 @@ struct rb_iseq_constant_body { /* T_IMEMO/iseq */ /* typedef rb_iseq_t is in method.h */ struct rb_iseq_struct { - VALUE flags; - struct rb_hook_list_struct *local_hooks; - struct rb_iseq_constant_body *body; + VALUE flags; /* 1 */ + VALUE wrapper; /* 2 */ + + struct rb_iseq_constant_body *body; /* 3 */ union { /* 4, 5 words */ struct iseq_compile_data *compile_data; /* used at compile time */ @@ -485,7 +486,10 @@ struct rb_iseq_struct { int index; } loader; - rb_event_flag_t global_trace_events; + struct { + struct rb_hook_list_struct *local_hooks; + rb_event_flag_t global_trace_events; + } exec; } aux; }; diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 32a105a4ac..7080434543 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -3893,7 +3893,7 @@ vm_trace(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, const VALUE *p const rb_iseq_t *iseq = reg_cfp->iseq; size_t pos = pc - iseq->body->iseq_encoded; rb_event_flag_t pc_events = rb_iseq_event_flags(iseq, pos); - rb_hook_list_t *local_hooks = iseq->local_hooks; + rb_hook_list_t *local_hooks = iseq->aux.exec.local_hooks; rb_event_flag_t local_hook_events = local_hooks != NULL ? local_hooks->events : 0; enabled_flags |= local_hook_events; |