summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--iseq.c86
-rw-r--r--iseq.h4
-rw-r--r--test/ruby/test_iseq.rb23
-rw-r--r--vm.c2
-rw-r--r--vm_core.h12
-rw-r--r--vm_insnhelper.c2
6 files changed, 87 insertions, 42 deletions
diff --git a/iseq.c b/iseq.c
index 8e890d4a67..36568f0ce0 100644
--- a/iseq.c
+++ b/iseq.c
@@ -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;) {
diff --git a/iseq.h b/iseq.h
index abf93ff594..ef245b2d93 100644
--- a/iseq.h
+++ b/iseq.h
@@ -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
diff --git a/vm.c b/vm.c
index 2c69498c13..7b79ca9890 100644
--- a/vm.c
+++ b/vm.c
@@ -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:
diff --git a/vm_core.h b/vm_core.h
index fd47aed804..b40ef4c2cd 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -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;