diff --git a/compile.c b/compile.c index 1dfbef52e3..f854d71c9b 100644 --- a/compile.c +++ b/compile.c @@ -562,15 +562,6 @@ APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LI #define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem)) #endif -static int -iseq_add_mark_object(const rb_iseq_t *iseq, VALUE v) -{ - if (!SPECIAL_CONST_P(v)) { - rb_iseq_add_mark_object(iseq, v); - } - return COMPILE_OK; -} - static int iseq_add_mark_object_compile_time(const rb_iseq_t *iseq, VALUE v) { @@ -749,6 +740,7 @@ rb_iseq_translate_threaded_code(rb_iseq_t *iseq) encoded[i] = (VALUE)table[insn]; i += len; } + FL_SET(iseq, ISEQ_TRANSLATED); #endif return COMPILE_OK; } @@ -1235,7 +1227,7 @@ new_child_iseq(rb_iseq_t *iseq, const NODE *const node, rb_iseq_path(iseq), rb_iseq_realpath(iseq), INT2FIX(line_no), parent, type, ISEQ_COMPILE_DATA(iseq)->option); debugs("[new_child_iseq]< ---------------------------------------\n"); - iseq_add_mark_object(iseq, (VALUE)ret_iseq); + iseq_add_mark_object_compile_time(iseq, (VALUE)ret_iseq); return ret_iseq; } @@ -1250,7 +1242,7 @@ new_child_iseq_ifunc(rb_iseq_t *iseq, const struct vm_ifunc *ifunc, rb_iseq_path(iseq), rb_iseq_realpath(iseq), INT2FIX(line_no), parent, type, ISEQ_COMPILE_DATA(iseq)->option); debugs("[new_child_iseq_ifunc]< ---------------------------------------\n"); - iseq_add_mark_object(iseq, (VALUE)ret_iseq); + iseq_add_mark_object_compile_time(iseq, (VALUE)ret_iseq); return ret_iseq; } @@ -1501,7 +1493,6 @@ iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, switch (nd_type(val_node)) { case NODE_LIT: dv = val_node->nd_lit; - iseq_add_mark_object(iseq, dv); break; case NODE_NIL: dv = Qnil; @@ -2044,7 +2035,6 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) VALUE v = operands[j]; generated_iseq[code_index + 1 + j] = v; /* to mark ruby object */ - iseq_add_mark_object(iseq, v); break; } case TS_IC: /* inline cache */ @@ -2209,11 +2199,6 @@ iseq_set_exception_table(rb_iseq_t *iseq) entry->end = label_get_position((LABEL *)(ptr[2] & ~1)); entry->iseq = (rb_iseq_t *)ptr[3]; - /* register iseq as mark object */ - if (entry->iseq != 0) { - iseq_add_mark_object(iseq, (VALUE)entry->iseq); - } - /* stack depth */ if (ptr[4]) { LABEL *lobj = (LABEL *)(ptr[4] & ~1); @@ -4790,7 +4775,7 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod } if (only_special_literals) { - iseq_add_mark_object(iseq, literals); + iseq_add_mark_object_compile_time(iseq, literals); ADD_INSN(ret, nd_line(orig_node), dup); ADD_INSN2(ret, nd_line(orig_node), opt_case_dispatch, literals, elselabel); @@ -7505,7 +7490,6 @@ iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op) } loaded_iseq = rb_iseqw_to_iseq(iseqw); - iseq_add_mark_object(iseq, (VALUE)loaded_iseq); return loaded_iseq; } @@ -7636,7 +7620,6 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, break; case TS_VALUE: argv[j] = op; - iseq_add_mark_object(iseq, op); break; case TS_ISEQ: { @@ -7683,7 +7666,6 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, } RB_GC_GUARD(op); argv[j] = map; - rb_iseq_add_mark_object(iseq, map); } break; case TS_FUNCPTR: @@ -9285,7 +9267,6 @@ ibf_load_object(const struct ibf_load *load, VALUE object_index) rb_ary_store(load->obj_list, (long)object_index, obj); } - iseq_add_mark_object(load->iseq, obj); return obj; } } @@ -9470,9 +9451,6 @@ ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq) ibf_load_iseq_complete(iseq); #endif /* !USE_LAZY_LOAD */ - if (load->iseq) { - iseq_add_mark_object(load->iseq, (VALUE)iseq); - } return iseq; } } diff --git a/iseq.c b/iseq.c index e58da59923..631115cce1 100644 --- a/iseq.c +++ b/iseq.c @@ -113,6 +113,92 @@ rb_iseq_free(const rb_iseq_t *iseq) RUBY_FREE_LEAVE("iseq"); } +#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE +static int +rb_vm_insn_addr2insn2(const void *addr) +{ + int insn; + const void * const *table = rb_vm_get_insns_address_table(); + + for (insn = 0; insn < VM_INSTRUCTION_SIZE; insn++) { + if (table[insn] == addr) { + return insn; + } + } + rb_bug("rb_vm_insn_addr2insn: invalid insn address: %p", addr); +} +#endif + +static int +rb_vm_insn_null_translator(const void *addr) +{ + return (int)addr; +} + +typedef void iseq_value_itr_t(void *ctx, VALUE obj); +typedef int 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) +{ + VALUE insn = translator((void *)code[pos]); + int len = insn_len(insn); + int op_no; + const char *types = insn_op_types(insn); + + for (op_no = 0; types[op_no]; op_no++) { + char type = types[op_no]; + switch (type) { + case TS_CDHASH: + case TS_ISEQ: + case TS_VALUE: + { + VALUE op = code[pos + op_no + 1]; + if (!SPECIAL_CONST_P(op)) { + func(data, op); + } + break; + } + default: + break; + } + } + + return len; +} + +static void +rb_iseq_each_value(const rb_iseq_t *iseq, iseq_value_itr_t * func, void *data) +{ + unsigned int size; + const VALUE *code; + size_t n; + rb_vm_insns_translator_t * translator; + + size = iseq->body->iseq_size; + code = iseq->body->iseq_encoded; + +#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE + if (FL_TEST(iseq, ISEQ_TRANSLATED)) { + translator = rb_vm_insn_addr2insn2; + } else { + translator = rb_vm_insn_null_translator; + } +#else + translator = rb_vm_insn_null_translator; +#endif + + for (n = 0; n < size;) { + n += iseq_extract_values(code, n, func, data, translator); + } +} + +static void +each_insn_value(void *ctx, VALUE obj) +{ + rb_gc_mark(obj); +} + void rb_iseq_mark(const rb_iseq_t *iseq) { @@ -121,13 +207,27 @@ rb_iseq_mark(const rb_iseq_t *iseq) if (iseq->body) { const struct rb_iseq_constant_body *body = iseq->body; + rb_iseq_each_value(iseq, each_insn_value, NULL); RUBY_MARK_UNLESS_NULL(body->mark_ary); 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); + + if (body->catch_table) { + const struct iseq_catch_table *table = body->catch_table; + unsigned int i; + for(i = 0; i < table->size; i++) { + const struct iseq_catch_table_entry *entry; + entry = &table->entries[i]; + if (entry->iseq) { + rb_gc_mark((VALUE)entry->iseq); + } + } + } } + if (FL_TEST(iseq, ISEQ_NOT_LOADED_YET)) { rb_gc_mark(iseq->aux.loader.obj); } diff --git a/iseq.h b/iseq.h index 283f5dcdf4..70252efcd9 100644 --- a/iseq.h +++ b/iseq.h @@ -94,6 +94,7 @@ ISEQ_ORIGINAL_ISEQ_ALLOC(const rb_iseq_t *iseq, long size) #define ISEQ_NOT_LOADED_YET IMEMO_FL_USER1 #define ISEQ_USE_COMPILE_DATA IMEMO_FL_USER2 +#define ISEQ_TRANSLATED IMEMO_FL_USER3 struct iseq_compile_data { /* GC is needed */