summaryrefslogtreecommitdiff
path: root/iseq.c
diff options
context:
space:
mode:
authortenderlove <tenderlove@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2019-04-09 20:32:04 +0000
committertenderlove <tenderlove@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2019-04-09 20:32:04 +0000
commit3ef4db15e95740839a0ed6d0224b2c9562bb2544 (patch)
tree18c23ed1b2e3c7b55860c27238a98cafafe63d9f /iseq.c
parentc09e35d7bbb5c18124d7ab54740bef966e145529 (diff)
Adding `GC.compact` and compacting GC support.
This commit adds the new method `GC.compact` and compacting GC support. Please see this issue for caveats: https://bugs.ruby-lang.org/issues/15626 [Feature #15626] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@67479 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'iseq.c')
-rw-r--r--iseq.c102
1 files changed, 84 insertions, 18 deletions
diff --git a/iseq.c b/iseq.c
index 0ec48da585..cce3b9cb39 100644
--- a/iseq.c
+++ b/iseq.c
@@ -136,11 +136,11 @@ rb_vm_insn_null_translator(const void *addr)
return (VALUE)addr;
}
-typedef void iseq_value_itr_t(void *ctx, VALUE obj);
+typedef VALUE iseq_value_itr_t(void *ctx, VALUE obj);
typedef VALUE rb_vm_insns_translator_t(const void *addr);
static int
-iseq_extract_values(const VALUE *code, size_t pos, iseq_value_itr_t * func, void *data, rb_vm_insns_translator_t * translator)
+iseq_extract_values(VALUE *code, size_t pos, iseq_value_itr_t * func, void *data, rb_vm_insns_translator_t * translator)
{
VALUE insn = translator((void *)code[pos]);
int len = insn_len(insn);
@@ -156,7 +156,10 @@ iseq_extract_values(const VALUE *code, size_t pos, iseq_value_itr_t * func, void
{
VALUE op = code[pos + op_no + 1];
if (!SPECIAL_CONST_P(op)) {
- func(data, op);
+ VALUE newop = func(data, op);
+ if (newop != op) {
+ code[pos + op_no + 1] = newop;
+ }
}
break;
}
@@ -164,7 +167,10 @@ iseq_extract_values(const VALUE *code, size_t pos, iseq_value_itr_t * func, void
{
union iseq_inline_storage_entry *const is = (union iseq_inline_storage_entry *)code[pos + op_no + 1];
if (is->once.value) {
- func(data, is->once.value);
+ VALUE nv = func(data, is->once.value);
+ if (is->once.value != nv) {
+ is->once.value = nv;
+ }
}
break;
}
@@ -180,7 +186,7 @@ static void
rb_iseq_each_value(const rb_iseq_t *iseq, iseq_value_itr_t * func, void *data)
{
unsigned int size;
- const VALUE *code;
+ VALUE *code;
size_t n;
rb_vm_insns_translator_t * translator;
const struct rb_iseq_constant_body *const body = iseq->body;
@@ -204,10 +210,65 @@ rb_iseq_each_value(const rb_iseq_t *iseq, iseq_value_itr_t * func, void *data)
}
}
-static void
+static VALUE
+update_each_insn_value(void *ctx, VALUE obj)
+{
+ return rb_gc_new_location(obj);
+}
+
+void
+rb_iseq_update_references(rb_iseq_t *iseq)
+{
+ if (iseq->body) {
+ struct rb_iseq_constant_body *body = iseq->body;
+
+ body->variable.coverage = rb_gc_new_location(body->variable.coverage);
+ body->variable.pc2branchindex = rb_gc_new_location(body->variable.pc2branchindex);
+ body->location.label = rb_gc_new_location(body->location.label);
+ body->location.base_label = rb_gc_new_location(body->location.base_label);
+ body->location.pathobj = rb_gc_new_location(body->location.pathobj);
+ if (body->local_iseq) {
+ body->local_iseq = (struct rb_iseq_struct *)rb_gc_new_location((VALUE)body->local_iseq);
+ }
+ if (body->parent_iseq) {
+ body->parent_iseq = (struct rb_iseq_struct *)rb_gc_new_location((VALUE)body->parent_iseq);
+ }
+ if(FL_TEST(iseq, ISEQ_MARKABLE_ISEQ)) {
+ rb_iseq_each_value(iseq, update_each_insn_value, NULL);
+ }
+
+ if (body->param.flags.has_kw && ISEQ_COMPILE_DATA(iseq) == NULL) {
+ int i, j;
+
+ i = body->param.keyword->required_num;
+
+ for (j = 0; i < body->param.keyword->num; i++, j++) {
+ VALUE obj = body->param.keyword->default_values[j];
+ if (obj != Qundef) {
+ body->param.keyword->default_values[j] = rb_gc_new_location(obj);
+ }
+ }
+ }
+
+ if (body->catch_table) {
+ struct iseq_catch_table *table = body->catch_table;
+ unsigned int i;
+ for(i = 0; i < table->size; i++) {
+ struct iseq_catch_table_entry *entry;
+ entry = &table->entries[i];
+ if (entry->iseq) {
+ entry->iseq = (rb_iseq_t *)rb_gc_new_location((VALUE)entry->iseq);
+ }
+ }
+ }
+ }
+}
+
+static VALUE
each_insn_value(void *ctx, VALUE obj)
{
- rb_gc_mark(obj);
+ rb_gc_mark_no_pin(obj);
+ return obj;
}
void
@@ -224,12 +285,12 @@ rb_iseq_mark(const rb_iseq_t *iseq)
rb_iseq_each_value(iseq, each_insn_value, NULL);
}
- rb_gc_mark(body->variable.coverage);
- rb_gc_mark(body->variable.pc2branchindex);
- rb_gc_mark(body->location.label);
- rb_gc_mark(body->location.base_label);
- rb_gc_mark(body->location.pathobj);
- RUBY_MARK_UNLESS_NULL((VALUE)body->parent_iseq);
+ rb_gc_mark_no_pin(body->variable.coverage);
+ rb_gc_mark_no_pin(body->variable.pc2branchindex);
+ rb_gc_mark_no_pin(body->location.label);
+ rb_gc_mark_no_pin(body->location.base_label);
+ rb_gc_mark_no_pin(body->location.pathobj);
+ RUBY_MARK_NO_PIN_UNLESS_NULL((VALUE)body->parent_iseq);
if (body->param.flags.has_kw && ISEQ_COMPILE_DATA(iseq) == NULL) {
const struct rb_iseq_param_keyword *const keyword = body->param.keyword;
@@ -252,7 +313,7 @@ rb_iseq_mark(const rb_iseq_t *iseq)
const struct iseq_catch_table_entry *entry;
entry = &table->entries[i];
if (entry->iseq) {
- rb_gc_mark((VALUE)entry->iseq);
+ rb_gc_mark_no_pin((VALUE)entry->iseq);
}
}
}
@@ -263,11 +324,16 @@ rb_iseq_mark(const rb_iseq_t *iseq)
}
else if (FL_TEST_RAW(iseq, ISEQ_USE_COMPILE_DATA)) {
const struct iseq_compile_data *const compile_data = ISEQ_COMPILE_DATA(iseq);
- VM_ASSERT(compile_data != NULL);
-
- RUBY_MARK_UNLESS_NULL(compile_data->mark_ary);
+ if (RTEST(compile_data->mark_ary)) {
+ rb_gc_mark(compile_data->mark_ary);
+ rb_gc_mark_values(RARRAY_LEN(compile_data->mark_ary), RARRAY_CONST_PTR(compile_data->mark_ary));
+ }
RUBY_MARK_UNLESS_NULL(compile_data->err_info);
- RUBY_MARK_UNLESS_NULL(compile_data->catch_table_ary);
+ if (RTEST(compile_data->catch_table_ary)) {
+ rb_gc_mark(compile_data->catch_table_ary);
+ rb_gc_mark_values(RARRAY_LEN(compile_data->catch_table_ary), RARRAY_CONST_PTR(compile_data->catch_table_ary));
+ }
+ VM_ASSERT(compile_data != NULL);
}
else {
/* executable */