diff --git a/Makefile.in b/Makefile.in index a55a738fea2452..eeda81b0b373ab 100644 --- a/Makefile.in +++ b/Makefile.in @@ -538,7 +538,7 @@ un-runnable: mjit_config.h: $(ECHO) making $@ @{ \ - $(Q:@=:) set -x; \ + test "$(Q)" = @ || set -x; \ echo '#ifndef RUBY_MJIT_CONFIG_H'; \ echo '#define RUBY_MJIT_CONFIG_H 1'; \ \ diff --git a/array.c b/array.c index 2789acd56f3fe5..a821575676d87e 100644 --- a/array.c +++ b/array.c @@ -2804,6 +2804,34 @@ rb_get_values_at(VALUE obj, long olen, int argc, const VALUE *argv, VALUE (*func return result; } +static VALUE +append_values_at_single(VALUE result, VALUE ary, long olen, VALUE idx) +{ + long beg, len; + if (FIXNUM_P(idx)) { + beg = FIX2LONG(idx); + } + /* check if idx is Range */ + else if (rb_range_beg_len(idx, &beg, &len, olen, 1)) { + if (len > 0) { + const VALUE *const src = RARRAY_CONST_PTR(ary); + const long end = beg + len; + const long prevlen = RARRAY_LEN(result); + if (beg < olen) { + rb_ary_cat(result, src + beg, end > olen ? olen-beg : len); + } + if (end > olen) { + rb_ary_store(result, prevlen + len - 1, Qnil); + } + } + return result; + } + else { + beg = NUM2LONG(idx); + } + return rb_ary_push(result, rb_ary_entry(ary, beg)); +} + /* * call-seq: * ary.values_at(selector, ...) -> new_ary @@ -2825,7 +2853,13 @@ rb_get_values_at(VALUE obj, long olen, int argc, const VALUE *argv, VALUE (*func static VALUE rb_ary_values_at(int argc, VALUE *argv, VALUE ary) { - return rb_get_values_at(ary, RARRAY_LEN(ary), argc, argv, rb_ary_entry); + long i, olen = RARRAY_LEN(ary); + VALUE result = rb_ary_new_capa(argc); + for (i = 0; i < argc; ++i) { + append_values_at_single(result, ary, olen, argv[i]); + } + RB_GC_GUARD(ary); + return result; } diff --git a/benchmark/bm_array_values_at_int.rb b/benchmark/bm_array_values_at_int.rb new file mode 100644 index 00000000000000..6cb394cb9fd8f7 --- /dev/null +++ b/benchmark/bm_array_values_at_int.rb @@ -0,0 +1,2 @@ +ary = Array.new(10000) {|i| i} +100000.times { ary.values_at(500) } diff --git a/benchmark/bm_array_values_at_range.rb b/benchmark/bm_array_values_at_range.rb new file mode 100644 index 00000000000000..5b53806d1ca974 --- /dev/null +++ b/benchmark/bm_array_values_at_range.rb @@ -0,0 +1,2 @@ +ary = Array.new(10000) {|i| i} +100000.times { ary.values_at(1..2000) } diff --git a/compile.c b/compile.c index 5bca0dca994129..2610836e78b2e7 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; @@ -2027,6 +2018,7 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) rb_hash_rehash(map); freeze_hide_obj(map); generated_iseq[code_index + 1 + j] = map; + FL_SET(iseq, ISEQ_MARKABLE_ISEQ); break; } case TS_LINDEX: @@ -2037,6 +2029,9 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) { VALUE v = operands[j]; generated_iseq[code_index + 1 + j] = v; + if (!SPECIAL_CONST_P(v)) { + FL_SET(iseq, ISEQ_MARKABLE_ISEQ); + } break; } case TS_VALUE: /* VALUE */ @@ -2044,7 +2039,9 @@ 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); + if (!SPECIAL_CONST_P(v)) { + FL_SET(iseq, ISEQ_MARKABLE_ISEQ); + } break; } case TS_IC: /* inline cache */ @@ -2057,6 +2054,17 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) generated_iseq[code_index + 1 + j] = (VALUE)ic; break; } + case TS_ISE: /* inline storage entry */ + { + unsigned int ic_index = FIX2UINT(operands[j]); + IC ic = (IC)&iseq->body->is_entries[ic_index]; + if (UNLIKELY(ic_index >= iseq->body->is_size)) { + rb_bug("iseq_set_sequence: ic_index overflow: index: %d, size: %d", ic_index, iseq->body->is_size); + } + generated_iseq[code_index + 1 + j] = (VALUE)ic; + FL_SET(iseq, ISEQ_MARKABLE_ISEQ); + break; + } case TS_CALLINFO: /* call info */ { struct rb_call_info *base_ci = (struct rb_call_info *)operands[j]; @@ -2209,11 +2217,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); @@ -2851,11 +2854,11 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(niobj, 0); /* * freezestring debug_info - * send <:+@, 0, ARG_SIMPLE> + * send <:+@, 0, ARG_SIMPLE> # :-@, too * => - * send <:+@, 0, ARG_SIMPLE> + * send <:+@, 0, ARG_SIMPLE> # :-@, too */ - if (ci->mid == idUPlus && + if ((ci->mid == idUPlus || ci->mid == idUMinus) && (ci->flag & VM_CALL_ARGS_SIMPLE) && ci->orig_argc == 0) { ELEM_REMOVE(list); @@ -4827,7 +4830,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); @@ -7304,6 +7307,7 @@ insn_data_to_s_detail(INSN *iobj) break; } case TS_IC: /* inline cache */ + case TS_ISE: /* inline storage entry */ rb_str_catf(str, "", FIX2INT(OPERAND_AT(iobj, j))); break; case TS_CALLINFO: /* call info */ @@ -7543,7 +7547,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; } @@ -7674,7 +7677,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: { @@ -7691,6 +7693,7 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, argv[j] = (VALUE)rb_global_entry(SYM2ID(op)); break; case TS_IC: + case TS_ISE: argv[j] = op; if (NUM2UINT(op) >= iseq->body->is_size) { iseq->body->is_size = NUM2INT(op) + 1; @@ -7721,7 +7724,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: @@ -8297,6 +8299,7 @@ ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq) code[code_index] = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op); break; case TS_IC: + case TS_ISE: { unsigned int i; for (i=0; ibody->is_size; i++) { @@ -8362,6 +8365,7 @@ ibf_load_code(const struct ibf_load *load, const rb_iseq_t *iseq, const struct r code[code_index] = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op); break; case TS_IC: + case TS_ISE: code[code_index] = (VALUE)&is_entries[(int)op]; break; case TS_CALLINFO: @@ -8662,7 +8666,8 @@ ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq) dump_body.is_entries = NULL; dump_body.ci_entries = ibf_dump_ci_entries(dump, iseq); dump_body.cc_entries = NULL; - dump_body.mark_ary = ISEQ_FLIP_CNT(iseq); + dump_body.variable.coverage = Qnil; + dump_body.variable.original_iseq = Qnil; return ibf_dump_write(dump, &dump_body, sizeof(dump_body)); } @@ -8694,7 +8699,7 @@ ibf_load_iseq_each(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t of load_body->ci_kw_size = body->ci_kw_size; load_body->insns_info.size = body->insns_info.size; - RB_OBJ_WRITE(iseq, &load_body->mark_ary, iseq_mark_ary_create((int)body->mark_ary)); + iseq_mark_ary_create(iseq, (int)body->variable.flip_count); { VALUE realpath = Qnil, path = ibf_load_object(load, body->location.pathobj); @@ -9325,7 +9330,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; } } @@ -9512,9 +9516,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/configure.ac b/configure.ac index 800e44ae89d77a..19b41971165887 100644 --- a/configure.ac +++ b/configure.ac @@ -2256,7 +2256,7 @@ AS_IF([test "${universal_binary-no}" = yes ], [ AS_IF([test x"$enable_pthread" = xyes], [ for pthread_lib in thr pthread pthreads c c_r root; do - AC_CHECK_LIB($pthread_lib, pthread_kill, + AC_CHECK_LIB($pthread_lib, pthread_create, rb_with_pthread=yes, rb_with_pthread=no) AS_IF([test "$rb_with_pthread" = "yes"], [ break; fi done @@ -2290,7 +2290,7 @@ AS_IF([test x"$enable_pthread" = xyes], [ AC_DEFINE(NON_SCALAR_THREAD_ID) ]) AC_CHECK_FUNCS(sched_yield pthread_attr_setinheritsched \ - pthread_attr_get_np pthread_attr_getstack \ + pthread_attr_get_np pthread_attr_getstack pthread_attr_getguardsize \ pthread_get_stackaddr_np pthread_get_stacksize_np \ thr_stksegment pthread_stackseg_np pthread_getthrds_np \ pthread_condattr_setclock \ diff --git a/gc.c b/gc.c index a1e6bc4bc23e86..ad4cd55b2a392d 100644 --- a/gc.c +++ b/gc.c @@ -3996,6 +3996,11 @@ init_mark_stack(mark_stack_t *stack) #define STACK_END (ec->machine.stack_end) #define STACK_LEVEL_MAX (ec->machine.stack_maxsize/sizeof(VALUE)) +#ifdef __EMSCRIPTEN__ +#undef STACK_GROW_DIRECTION +#define STACK_GROW_DIRECTION 1 +#endif + #if STACK_GROW_DIRECTION < 0 # define STACK_LENGTH (size_t)(STACK_START - STACK_END) #elif STACK_GROW_DIRECTION > 0 diff --git a/insns.def b/insns.def index d06368466ed1db..4f791ed16b801c 100644 --- a/insns.def +++ b/insns.def @@ -971,11 +971,11 @@ setinlinecache /* run iseq only once */ DEFINE_INSN once -(ISEQ iseq, IC ic) +(ISEQ iseq, ISE ise) () (VALUE val) { - val = vm_once_dispatch(ec, iseq, ic); + val = vm_once_dispatch(ec, iseq, ise); } /* case dispatcher, jump by table if possible */ diff --git a/iseq.c b/iseq.c index b703baa2c4b53d..fcac257fb3701a 100644 --- a/iseq.c +++ b/iseq.c @@ -115,6 +115,100 @@ 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; + } + case TS_ISE: + { + 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); + } + 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) { @@ -123,13 +217,31 @@ rb_iseq_mark(const rb_iseq_t *iseq) if (iseq->body) { const struct rb_iseq_constant_body *body = iseq->body; - RUBY_MARK_UNLESS_NULL(body->mark_ary); + if(FL_TEST(iseq, ISEQ_MARKABLE_ISEQ)) { + rb_iseq_each_value(iseq, each_insn_value, NULL); + } + + rb_gc_mark(body->variable.coverage); + rb_gc_mark(body->variable.original_iseq); 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); } @@ -299,13 +411,6 @@ set_relation(rb_iseq_t *iseq, const rb_iseq_t *piseq) } } -void -rb_iseq_add_mark_object(const rb_iseq_t *iseq, VALUE obj) -{ - /* TODO: check dedup */ - rb_ary_push(ISEQ_MARK_ARY(iseq), obj); -} - static VALUE prepare_iseq_build(rb_iseq_t *iseq, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_code_location_t *code_location, @@ -326,7 +431,7 @@ prepare_iseq_build(rb_iseq_t *iseq, if (iseq != iseq->body->local_iseq) { RB_OBJ_WRITE(iseq, &iseq->body->location.base_label, iseq->body->local_iseq->body->location.label); } - RB_OBJ_WRITE(iseq, &iseq->body->mark_ary, iseq_mark_ary_create(0)); + iseq_mark_ary_create(iseq, 0); ISEQ_COMPILE_DATA_ALLOC(iseq); RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err_info); @@ -1612,6 +1717,7 @@ rb_insn_operand_intern(const rb_iseq_t *iseq, break; case TS_IC: + case TS_ISE: ret = rb_sprintf("", (union iseq_inline_storage_entry *)op - iseq->body->is_entries); break; @@ -2355,6 +2461,7 @@ iseq_data_to_ary(const rb_iseq_t *iseq) } break; case TS_IC: + case TS_ISE: { union iseq_inline_storage_entry *is = (union iseq_inline_storage_entry *)*seq; rb_ary_push(ary, INT2FIX(is - iseq->body->is_entries)); diff --git a/iseq.h b/iseq.h index 0c316e2cb2863c..31a3232e3be1f7 100644 --- a/iseq.h +++ b/iseq.h @@ -28,44 +28,33 @@ rb_call_info_kw_arg_bytes(int keyword_len) return sizeof(struct rb_call_info_kw_arg) + sizeof(VALUE) * (keyword_len - 1); } -enum iseq_mark_ary_index { - ISEQ_MARK_ARY_COVERAGE, - ISEQ_MARK_ARY_FLIP_CNT, - ISEQ_MARK_ARY_ORIGINAL_ISEQ, - ISEQ_MARK_ARY_INITIAL_SIZE -}; - -static inline VALUE -iseq_mark_ary_create(int flip_cnt) +static inline void +iseq_mark_ary_create(rb_iseq_t *iseq, int flip_cnt) { - VALUE ary = rb_ary_tmp_new(ISEQ_MARK_ARY_INITIAL_SIZE); - rb_ary_push(ary, Qnil); /* ISEQ_MARK_ARY_COVERAGE */ - rb_ary_push(ary, INT2FIX(flip_cnt)); /* ISEQ_MARK_ARY_FLIP_CNT */ - rb_ary_push(ary, Qnil); /* ISEQ_MARK_ARY_ORIGINAL_ISEQ */ - return ary; + RB_OBJ_WRITE(iseq, &iseq->body->variable.coverage, Qnil); + RB_OBJ_WRITE(iseq, &iseq->body->variable.original_iseq, Qnil); + iseq->body->variable.flip_count = flip_cnt; } -#define ISEQ_MARK_ARY(iseq) (iseq)->body->mark_ary - -#define ISEQ_COVERAGE(iseq) RARRAY_AREF(ISEQ_MARK_ARY(iseq), ISEQ_MARK_ARY_COVERAGE) -#define ISEQ_COVERAGE_SET(iseq, cov) RARRAY_ASET(ISEQ_MARK_ARY(iseq), ISEQ_MARK_ARY_COVERAGE, cov) +#define ISEQ_COVERAGE(iseq) iseq->body->variable.coverage +#define ISEQ_COVERAGE_SET(iseq, cov) RB_OBJ_WRITE(iseq, &iseq->body->variable.coverage, cov) #define ISEQ_LINE_COVERAGE(iseq) RARRAY_AREF(ISEQ_COVERAGE(iseq), COVERAGE_INDEX_LINES) #define ISEQ_BRANCH_COVERAGE(iseq) RARRAY_AREF(ISEQ_COVERAGE(iseq), COVERAGE_INDEX_BRANCHES) -#define ISEQ_FLIP_CNT(iseq) FIX2INT(RARRAY_AREF(ISEQ_MARK_ARY(iseq), ISEQ_MARK_ARY_FLIP_CNT)) +#define ISEQ_FLIP_CNT(iseq) (iseq)->body->variable.flip_count static inline int ISEQ_FLIP_CNT_INCREMENT(const rb_iseq_t *iseq) { - int cnt = ISEQ_FLIP_CNT(iseq); - RARRAY_ASET(ISEQ_MARK_ARY(iseq), ISEQ_MARK_ARY_FLIP_CNT, INT2FIX(cnt+1)); + int cnt = iseq->body->variable.flip_count; + iseq->body->variable.flip_count += 1; return cnt; } static inline VALUE * ISEQ_ORIGINAL_ISEQ(const rb_iseq_t *iseq) { - VALUE str = RARRAY_AREF(ISEQ_MARK_ARY(iseq), ISEQ_MARK_ARY_ORIGINAL_ISEQ); + VALUE str = iseq->body->variable.original_iseq; if (RTEST(str)) return (VALUE *)RSTRING_PTR(str); return NULL; } @@ -73,14 +62,14 @@ ISEQ_ORIGINAL_ISEQ(const rb_iseq_t *iseq) static inline void ISEQ_ORIGINAL_ISEQ_CLEAR(const rb_iseq_t *iseq) { - RARRAY_ASET(ISEQ_MARK_ARY(iseq), ISEQ_MARK_ARY_ORIGINAL_ISEQ, Qnil); + RB_OBJ_WRITE(iseq, &iseq->body->variable.original_iseq, Qnil); } static inline VALUE * ISEQ_ORIGINAL_ISEQ_ALLOC(const rb_iseq_t *iseq, long size) { VALUE str = rb_str_tmp_new(size * sizeof(VALUE)); - RARRAY_ASET(ISEQ_MARK_ARY(iseq), ISEQ_MARK_ARY_ORIGINAL_ISEQ, str); + RB_OBJ_WRITE(iseq, &iseq->body->variable.original_iseq, str); return (VALUE *)RSTRING_PTR(str); } @@ -94,6 +83,8 @@ 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 +#define ISEQ_MARKABLE_ISEQ IMEMO_FL_USER4 struct iseq_compile_data { /* GC is needed */ @@ -173,7 +164,6 @@ void rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE exception, VALUE body); /* iseq.c */ -void rb_iseq_add_mark_object(const rb_iseq_t *iseq, VALUE obj); VALUE rb_iseq_load(VALUE data, VALUE parent, VALUE opt); VALUE rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc); struct st_table *ruby_insn_make_insn_table(void); diff --git a/test/io/console/test_io_console.rb b/test/io/console/test_io_console.rb index 764c5e1a61360a..1368502b042d60 100644 --- a/test/io/console/test_io_console.rb +++ b/test/io/console/test_io_console.rb @@ -212,6 +212,7 @@ def test_oflush s.oflush # oflush may be issued after "a" is already sent. s.print "b" s.flush + sleep 0.1 assert_include(["b", "ab"], m.readpartial(10)) } end diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb index 6e463e18639a9c..8aa5c39323a9d6 100644 --- a/test/ruby/test_optimization.rb +++ b/test/ruby/test_optimization.rb @@ -557,8 +557,9 @@ def test_peephole_string_literal_range when "1.8.0"..."1.8.8" then :bar end end; - [ nil, { frozen_string_literal: true } ].each do |opt| - iseq = RubyVM::InstructionSequence.compile(code, nil, nil, opt) + [ true, false ].each do |opt| + iseq = RubyVM::InstructionSequence.compile(code, + frozen_string_literal: opt) insn = iseq.disasm assert_match %r{putobject\s+#{Regexp.quote('"1.8.0"..."1.8.8"')}}, insn assert_match %r{putobject\s+#{Regexp.quote('"2.0.0".."2.3.2"')}}, insn @@ -567,6 +568,21 @@ def test_peephole_string_literal_range end end + def test_peephole_dstr + code = "#{<<~'begin;'}\n#{<<~'end;'}" + begin; + exp = (-'a').object_id + z = 'a' + exp == (-"#{z}").object_id + end; + [ false, true ].each do |fsl| + iseq = RubyVM::InstructionSequence.compile(code, + frozen_string_literal: fsl) + assert_equal(true, iseq.eval, + "[ruby-core:85542] [Bug #14475] fsl: #{fsl}") + end + end + def test_branch_condition_backquote bug = '[ruby-core:80740] [Bug #13444] redefined backquote should be called' class << self diff --git a/thread_pthread.c b/thread_pthread.c index 381114d1ce0083..d36c1494830c1b 100644 --- a/thread_pthread.c +++ b/thread_pthread.c @@ -561,8 +561,12 @@ get_stack(void **addr, size_t *size) CHECK_ERR(pthread_attr_getstackaddr(&attr, addr)); CHECK_ERR(pthread_attr_getstacksize(&attr, size)); # endif +# ifdef HAVE_PTHREAD_ATTR_GETGUARDSIZE CHECK_ERR(pthread_attr_getguardsize(&attr, &guard)); *size -= guard; +# else + *size -= getpagesize(); +# endif pthread_attr_destroy(&attr); #elif defined HAVE_PTHREAD_ATTR_GET_NP /* FreeBSD, DragonFly BSD, NetBSD */ pthread_attr_t attr; diff --git a/tool/ruby_vm/models/typemap.rb b/tool/ruby_vm/models/typemap.rb index d818ce9878bb30..7c5c872d7cb104 100644 --- a/tool/ruby_vm/models/typemap.rb +++ b/tool/ruby_vm/models/typemap.rb @@ -18,6 +18,7 @@ "GENTRY" => %w[G TS_GENTRY], "IC" => %w[K TS_IC], "ID" => %w[I TS_ID], + "ISE" => %w[T TS_ISE], "ISEQ" => %w[S TS_ISEQ], "OFFSET" => %w[O TS_OFFSET], "VALUE" => %w[V TS_VALUE], diff --git a/vm_core.h b/vm_core.h index 0a62b66db82b1d..4b8f2474f1e2f4 100644 --- a/vm_core.h +++ b/vm_core.h @@ -411,7 +411,11 @@ struct rb_iseq_constant_body { */ struct rb_call_cache *cc_entries; /* size is ci_size = ci_kw_size */ - VALUE mark_ary; /* Array: includes operands which should be GC marked */ + struct { + rb_num_t flip_count; + VALUE coverage; + VALUE original_iseq; + } variable; unsigned int local_table_size; unsigned int is_size; @@ -1009,6 +1013,7 @@ enum vm_svar_index { /* inline cache */ typedef struct iseq_inline_cache_entry *IC; +typedef union iseq_inline_storage_entry *ISE; typedef struct rb_call_info *CALL_INFO; typedef struct rb_call_cache *CALL_CACHE; diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 5567c6b20f0d84..cd17a129c3fe62 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -3285,11 +3285,10 @@ vm_ic_update(IC ic, VALUE val, const VALUE *reg_ep) } static VALUE -vm_once_dispatch(rb_execution_context_t *ec, ISEQ iseq, IC ic) +vm_once_dispatch(rb_execution_context_t *ec, ISEQ iseq, ISE is) { rb_thread_t *th = rb_ec_thread_ptr(ec); rb_thread_t *const RUNNING_THREAD_ONCE_DONE = (rb_thread_t *)(0x1); - union iseq_inline_storage_entry *const is = (union iseq_inline_storage_entry *)ic; again: if (is->once.running_thread == RUNNING_THREAD_ONCE_DONE) { @@ -3298,10 +3297,10 @@ vm_once_dispatch(rb_execution_context_t *ec, ISEQ iseq, IC ic) else if (is->once.running_thread == NULL) { VALUE val; is->once.running_thread = th; - val = is->once.value = rb_ensure(vm_once_exec, (VALUE)iseq, vm_once_clear, (VALUE)is); + val = rb_ensure(vm_once_exec, (VALUE)iseq, vm_once_clear, (VALUE)is); + RB_OBJ_WRITE(ec->cfp->iseq, &is->once.value, val); /* is->once.running_thread is cleared by vm_once_clear() */ is->once.running_thread = RUNNING_THREAD_ONCE_DONE; /* success */ - rb_iseq_add_mark_object(ec->cfp->iseq, val); return val; } else if (is->once.running_thread == th) {