summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-12-06 10:52:27 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-12-06 10:52:27 +0000
commitd3aad1592213ed2c6ade84b09119c9fce46d185e (patch)
tree5c15f5ba159d11a06b18fd49a5c229ffb8c84fc2
parente39a83a150dba2021f519186b3908edd65a7cba6 (diff)
Return same ISeq object for one src.
* iseq.c: before this patch, RubyVM::InstructionSequence.of(src) (ISeq in short) returns different ISeq (wrapper) objects point to one ISeq internal object. This patch changes this behavior to cache created ISeq (wrapper) objects and return same ISeq object for an internal ISeq object. * iseq.h (ISEQ_EXECUTABLE_P): introduced to check executable ISeq objects. * iseq.h (ISEQ_COMPILE_DATA_ALLOC): reordr setting flag line to avoid ISEQ_USE_COMPILE_DATA but compiled_data == NULL case. * vm_core.h (rb_iseq_t): introduce `rb_iseq_t::wrapper` and `rb_iseq_t::aux::exec`. Move `rb_iseq_t::local_hooks` to `rb_iseq_t::aux::exec::local_hooks`. * test/ruby/test_iseq.rb: add ISeq.of() tests. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66246 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-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;