diff options
| -rw-r--r-- | array.c | 17 | ||||
| -rw-r--r-- | class.c | 2 | ||||
| -rw-r--r-- | compile.c | 99 | ||||
| -rw-r--r-- | depend | 4 | ||||
| -rw-r--r-- | encoding.c | 4 | ||||
| -rw-r--r-- | gc.c | 18 | ||||
| -rw-r--r-- | gc/default/default.c | 12 | ||||
| -rw-r--r-- | hash.c | 4 | ||||
| -rw-r--r-- | id_table.c | 1 | ||||
| -rw-r--r-- | imemo.c | 80 | ||||
| -rw-r--r-- | internal/class.h | 4 | ||||
| -rw-r--r-- | internal/gc.h | 1 | ||||
| -rw-r--r-- | internal/imemo.h | 11 | ||||
| -rw-r--r-- | iseq.c | 27 | ||||
| -rw-r--r-- | iseq.h | 2 | ||||
| -rw-r--r-- | prism_compile.c | 48 | ||||
| -rw-r--r-- | ractor.c | 41 | ||||
| -rw-r--r-- | re.c | 7 | ||||
| -rw-r--r-- | string.c | 26 | ||||
| -rw-r--r-- | symbol.c | 4 | ||||
| -rw-r--r-- | variable.c | 16 | ||||
| -rw-r--r-- | vm.c | 34 | ||||
| -rw-r--r-- | vm_callinfo.h | 2 | ||||
| -rw-r--r-- | vm_insnhelper.c | 17 | ||||
| -rw-r--r-- | vm_method.c | 8 |
25 files changed, 347 insertions, 142 deletions
@@ -29,6 +29,7 @@ #include "ruby/st.h" #include "ruby/thread.h" #include "ruby/util.h" +#include "ruby/ractor.h" #include "vm_core.h" #include "builtin.h" @@ -107,10 +108,12 @@ should_be_T_ARRAY(VALUE ary) } while (0) #define FL_UNSET_SHARED(ary) FL_UNSET((ary), RARRAY_SHARED_FLAG) +#define ARY_SET_PTR_FORCE(ary, p) \ + RARRAY(ary)->as.heap.ptr = (p); #define ARY_SET_PTR(ary, p) do { \ RUBY_ASSERT(!ARY_EMBED_P(ary)); \ RUBY_ASSERT(!OBJ_FROZEN(ary)); \ - RARRAY(ary)->as.heap.ptr = (p); \ + ARY_SET_PTR_FORCE(ary, p); \ } while (0) #define ARY_SET_EMBED_LEN(ary, n) do { \ long tmp_n = (n); \ @@ -148,11 +151,13 @@ should_be_T_ARRAY(VALUE ary) #define ARY_CAPA(ary) (ARY_EMBED_P(ary) ? ary_embed_capa(ary) : \ ARY_SHARED_ROOT_P(ary) ? RARRAY_LEN(ary) : ARY_HEAP_CAPA(ary)) +#define ARY_SET_CAPA_FORCE(ary, n) \ + RARRAY(ary)->as.heap.aux.capa = (n); #define ARY_SET_CAPA(ary, n) do { \ RUBY_ASSERT(!ARY_EMBED_P(ary)); \ RUBY_ASSERT(!ARY_SHARED_P(ary)); \ RUBY_ASSERT(!OBJ_FROZEN(ary)); \ - RARRAY(ary)->as.heap.aux.capa = (n); \ + ARY_SET_CAPA_FORCE(ary, n); \ } while (0) #define ARY_SHARED_ROOT_OCCUPIED(ary) (!OBJ_FROZEN(ary) && ARY_SHARED_ROOT_REFCNT(ary) == 1) @@ -560,8 +565,8 @@ rb_ary_cancel_sharing(VALUE ary) VALUE *ptr = ary_heap_alloc_buffer(len); MEMCPY(ptr, ARY_HEAP_PTR(ary), VALUE, len); rb_ary_unshare(ary); - ARY_SET_CAPA(ary, len); - ARY_SET_PTR(ary, ptr); + ARY_SET_CAPA_FORCE(ary, len); + ARY_SET_PTR_FORCE(ary, ptr); } rb_gc_writebarrier_remember(ary); @@ -4729,6 +4734,8 @@ rb_ary_replace(VALUE copy, VALUE orig) ARY_SET_PTR(copy, ARY_HEAP_PTR(orig)); ARY_SET_LEN(copy, ARY_HEAP_LEN(orig)); rb_ary_set_shared(copy, shared_root); + + RUBY_ASSERT(RB_OBJ_SHAREABLE_P(copy) ? RB_OBJ_SHAREABLE_P(shared_root) : 1); } ary_verify(copy); return copy; @@ -8883,7 +8890,7 @@ Init_Array(void) rb_define_method(rb_cArray, "deconstruct", rb_ary_deconstruct, 0); - rb_cArray_empty_frozen = rb_ary_freeze(rb_ary_new()); + rb_cArray_empty_frozen = RB_OBJ_SET_SHAREABLE(rb_ary_freeze(rb_ary_new())); rb_vm_register_global_object(rb_cArray_empty_frozen); } @@ -775,7 +775,7 @@ class_alloc0(enum ruby_value_type type, VALUE klass, bool namespaceable) RUBY_ASSERT(type == T_CLASS || type == T_ICLASS || type == T_MODULE); - VALUE flags = type; + VALUE flags = type | FL_SHAREABLE; if (RGENGC_WB_PROTECTED_CLASS) flags |= FL_WB_PROTECTED; if (namespaceable) flags |= RCLASS_NAMESPACEABLE; @@ -838,9 +838,9 @@ get_string_value(const NODE *node) { switch (nd_type(node)) { case NODE_STR: - return rb_node_str_string_val(node); + return RB_OBJ_SET_SHAREABLE(rb_node_str_string_val(node)); case NODE_FILE: - return rb_node_file_path_val(node); + return RB_OBJ_SET_SHAREABLE(rb_node_file_path_val(node)); default: rb_bug("unexpected node: %s", ruby_node_name(nd_type(node))); } @@ -1400,6 +1400,9 @@ static void iseq_insn_each_object_write_barrier(VALUE * obj, VALUE iseq) { RB_OBJ_WRITTEN(iseq, Qundef, *obj); + RUBY_ASSERT(SPECIAL_CONST_P(*obj) || + RBASIC_CLASS(*obj) == 0 || // hidden + RB_OBJ_SHAREABLE_P(*obj)); } static INSN * @@ -2063,6 +2066,7 @@ iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, for (i = 0; i < RARRAY_LEN(default_values); i++) { VALUE dv = RARRAY_AREF(default_values, i); if (dv == complex_mark) dv = Qundef; + if (!SPECIAL_CONST_P(dv)) rb_ractor_make_shareable(dv); RB_OBJ_WRITE(iseq, &dvs[i], dv); } @@ -2749,6 +2753,7 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) rb_hash_rehash(map); freeze_hide_obj(map); + rb_ractor_make_shareable(map); generated_iseq[code_index + 1 + j] = map; ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j); RB_OBJ_WRITTEN(iseq, Qundef, map); @@ -3489,7 +3494,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal is_frozen_putstring(beg, &str_beg) && !(insn_has_label_before(&beg->link) || insn_has_label_before(&end->link))) { int excl = FIX2INT(OPERAND_AT(range, 0)); - VALUE lit_range = rb_range_new(str_beg, str_end, excl); + VALUE lit_range = RB_OBJ_SET_SHAREABLE(rb_range_new(str_beg, str_end, excl)); ELEM_REMOVE(&beg->link); ELEM_REMOVE(&end->link); @@ -3556,6 +3561,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) { VALUE hash = iobj->operands[0]; rb_obj_reveal(hash, rb_cHash); + RB_OBJ_SET_SHAREABLE(hash); insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, hash, (VALUE)ci); ELEM_REMOVE(next); @@ -3929,6 +3935,9 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal rb_set_errinfo(errinfo); COMPILE_ERROR(iseq, line, "%" PRIsVALUE, message); } + else { + RB_OBJ_SET_SHAREABLE(re); + } RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re); ELEM_REMOVE(iobj->link.next); } @@ -4170,7 +4179,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal unsigned int flags = vm_ci_flag(ci); if ((flags & set_flags) == set_flags && !(flags & unset_flags)) { ((INSN*)niobj)->insn_id = BIN(putobject); - RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)))); + RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), RB_OBJ_SET_SHAREABLE(rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0))))); const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci), flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci)); @@ -4725,6 +4734,7 @@ compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node) if (!RNODE_DSTR(node)->nd_next) { VALUE lit = rb_node_dstr_string_val(node); ADD_INSN1(ret, node, putstring, lit); + RB_OBJ_SET_SHAREABLE(lit); RB_OBJ_WRITTEN(iseq, Qundef, lit); } else { @@ -4744,6 +4754,7 @@ compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i if (!popped) { VALUE src = rb_node_dregx_string_val(node); VALUE match = rb_reg_compile(src, cflag, NULL, 0); + RB_OBJ_SET_SHAREABLE(match); ADD_INSN1(ret, node, putobject, match); RB_OBJ_WRITTEN(iseq, Qundef, match); } @@ -5088,13 +5099,21 @@ static_literal_value(const NODE *node, rb_iseq_t *iseq) { switch (nd_type(node)) { case NODE_INTEGER: - return rb_node_integer_literal_val(node); + { + VALUE lit = rb_node_integer_literal_val(node); + if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit); + return lit; + } case NODE_FLOAT: - return rb_node_float_literal_val(node); + { + VALUE lit = rb_node_float_literal_val(node); + if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit); + return lit; + } case NODE_RATIONAL: - return rb_node_rational_literal_val(node); + return rb_ractor_make_shareable(rb_node_rational_literal_val(node)); case NODE_IMAGINARY: - return rb_node_imaginary_literal_val(node); + return rb_ractor_make_shareable(rb_node_imaginary_literal_val(node)); case NODE_NIL: return Qnil; case NODE_TRUE: @@ -5104,7 +5123,7 @@ static_literal_value(const NODE *node, rb_iseq_t *iseq) case NODE_SYM: return rb_node_sym_string_val(node); case NODE_REGX: - return rb_node_regx_string_val(node); + return RB_OBJ_SET_SHAREABLE(rb_node_regx_string_val(node)); case NODE_LINE: return rb_node_line_lineno_val(node); case NODE_ENCODING: @@ -5113,7 +5132,9 @@ static_literal_value(const NODE *node, rb_iseq_t *iseq) case NODE_STR: if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) { VALUE lit = get_string_value(node); - return rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node)); + VALUE str = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node)); + RB_OBJ_SET_SHAREABLE(str); + return str; } else { return get_string_value(node); @@ -5211,7 +5232,7 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int pop /* Create a hidden array */ for (; count; count--, node = RNODE_LIST(node)->nd_next) rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq)); - OBJ_FREEZE(ary); + RB_OBJ_SET_FROZEN_SHAREABLE(ary); /* Emit optimized code */ FLUSH_CHUNK; @@ -5223,6 +5244,7 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int pop ADD_INSN1(ret, line_node, putobject, ary); ADD_INSN(ret, line_node, concattoarray); } + RB_OBJ_SET_SHAREABLE(ary); RB_OBJ_WRITTEN(iseq, Qundef, ary); } } @@ -5349,13 +5371,14 @@ compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int meth for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) { VALUE elem[2]; elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq); + if (!RB_SPECIAL_CONST_P(elem[0])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[0]); elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq); + if (!RB_SPECIAL_CONST_P(elem[1])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[1]); rb_ary_cat(ary, elem, 2); } VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2); rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash); - hash = rb_obj_hide(hash); - OBJ_FREEZE(hash); + hash = RB_OBJ_SET_FROZEN_SHAREABLE(rb_obj_hide(hash)); /* Emit optimized code */ FLUSH_CHUNK(); @@ -6022,10 +6045,12 @@ collect_const_segments(rb_iseq_t *iseq, const NODE *node) switch (nd_type(node)) { case NODE_CONST: rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid)); + RB_OBJ_SET_SHAREABLE(arr); return arr; case NODE_COLON3: rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid)); rb_ary_unshift(arr, ID2SYM(idNULL)); + RB_OBJ_SET_SHAREABLE(arr); return arr; case NODE_COLON2: rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid)); @@ -7122,6 +7147,7 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) { ADD_INSN(ret, orig_node, dup); + rb_obj_hide(literals); ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel); RB_OBJ_WRITTEN(iseq, Qundef, literals); LABEL_REF(elselabel); @@ -7657,6 +7683,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c ADD_INSN(ret, line_node, putnil); } else { + RB_OBJ_SET_FROZEN_SHAREABLE(keys); ADD_INSN1(ret, line_node, duparray, keys); RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys)); } @@ -7694,7 +7721,8 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c ADD_INSN(ret, line_node, dup); ADD_INSNL(ret, line_node, branchif, match_succeeded); - ADD_INSN1(ret, line_node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key))); // (4) + VALUE str = rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key)); + ADD_INSN1(ret, line_node, putobject, RB_OBJ_SET_SHAREABLE(str)); // (4) ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */)); ADD_INSN1(ret, line_node, putobject, Qtrue); // (5) ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */)); @@ -10163,9 +10191,13 @@ compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i INIT_ANCHOR(val); switch ((int)type) { case NODE_MATCH: - ADD_INSN1(recv, node, putobject, rb_node_regx_string_val(node)); - ADD_INSN2(val, node, getspecial, INT2FIX(0), - INT2FIX(0)); + { + VALUE re = rb_node_regx_string_val(node); + RB_OBJ_SET_FROZEN_SHAREABLE(re); + ADD_INSN1(recv, node, putobject, re); + ADD_INSN2(val, node, getspecial, INT2FIX(0), + INT2FIX(0)); + } break; case NODE_MATCH2: CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv)); @@ -10242,6 +10274,7 @@ compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) { ISEQ_BODY(iseq)->ic_size++; VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid)); + RB_OBJ_SET_FROZEN_SHAREABLE(segments); ADD_INSN1(ret, node, opt_getconstant_path, segments); RB_OBJ_WRITTEN(iseq, Qundef, segments); } @@ -10269,6 +10302,7 @@ compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in VALUE bv = optimized_range_item(b); VALUE ev = optimized_range_item(e); VALUE val = rb_range_new(bv, ev, excl); + rb_ractor_make_shareable(rb_obj_freeze(val)); ADD_INSN1(ret, node, putobject, val); RB_OBJ_WRITTEN(iseq, Qundef, val); } @@ -11080,6 +11114,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) { body->ic_size++; VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid)); + RB_OBJ_SET_FROZEN_SHAREABLE(segments); ADD_INSN1(ret, node, opt_getconstant_path, segments); RB_OBJ_WRITTEN(iseq, Qundef, segments); } @@ -11145,6 +11180,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no } case NODE_INTEGER:{ VALUE lit = rb_node_integer_literal_val(node); + if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit); debugp_param("integer", lit); if (!popped) { ADD_INSN1(ret, node, putobject, lit); @@ -11154,6 +11190,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no } case NODE_FLOAT:{ VALUE lit = rb_node_float_literal_val(node); + if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit); debugp_param("float", lit); if (!popped) { ADD_INSN1(ret, node, putobject, lit); @@ -11163,6 +11200,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no } case NODE_RATIONAL:{ VALUE lit = rb_node_rational_literal_val(node); + rb_ractor_make_shareable(lit); debugp_param("rational", lit); if (!popped) { ADD_INSN1(ret, node, putobject, lit); @@ -11172,6 +11210,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no } case NODE_IMAGINARY:{ VALUE lit = rb_node_imaginary_literal_val(node); + rb_ractor_make_shareable(lit); debugp_param("imaginary", lit); if (!popped) { ADD_INSN1(ret, node, putobject, lit); @@ -11188,6 +11227,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) && option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) { lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line); + RB_OBJ_SET_SHAREABLE(lit); } switch (option->frozen_string_literal) { case ISEQ_FROZEN_STRING_LITERAL_UNSET: @@ -11242,6 +11282,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no case NODE_REGX:{ if (!popped) { VALUE lit = rb_node_regx_string_val(node); + RB_OBJ_SET_SHAREABLE(lit); ADD_INSN1(ret, node, putobject, lit); RB_OBJ_WRITTEN(iseq, Qundef, lit); } @@ -12105,6 +12146,7 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, rb_hash_aset(map, key, (VALUE)label | 1); } RB_GC_GUARD(op); + RB_OBJ_SET_SHAREABLE(rb_obj_hide(map)); // allow mutation while compiling argv[j] = map; RB_OBJ_WRITTEN(iseq, Qundef, map); } @@ -12992,7 +13034,7 @@ ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecod v = rb_hash_dup(v); // hash dumped as frozen RHASH_TBL_RAW(v)->type = &cdhash_type; rb_hash_rehash(v); // hash function changed - freeze_hide_obj(v); + RB_OBJ_SET_SHAREABLE(freeze_hide_obj(v)); // Overwrite the existing hash in the object list. This // is to keep the object alive during load time. @@ -14126,7 +14168,9 @@ ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_heade double d; /* Avoid unaligned VFP load on ARMv7; IBF payload may be unaligned (C99 6.3.2.3 p7). */ memcpy(&d, IBF_OBJBODY(double, offset), sizeof(d)); - return DBL2NUM(d); + VALUE f = DBL2NUM(d); + if (!FLONUM_P(f)) RB_OBJ_SET_SHAREABLE(f); + return f; } static void @@ -14197,7 +14241,7 @@ ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_head VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0); if (header->internal) rb_obj_hide(reg); - if (header->frozen) rb_obj_freeze(reg); + if (header->frozen) RB_OBJ_SET_SHAREABLE(rb_obj_freeze(reg)); return reg; } @@ -14228,7 +14272,10 @@ ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_heade rb_ary_push(ary, ibf_load_object(load, index)); } - if (header->frozen) rb_ary_freeze(ary); + if (header->frozen) { + rb_ary_freeze(ary); + rb_ractor_make_shareable(ary); // TODO: check elements + } return ary; } @@ -14273,7 +14320,9 @@ ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header rb_hash_rehash(obj); if (header->internal) rb_obj_hide(obj); - if (header->frozen) rb_obj_freeze(obj); + if (header->frozen) { + RB_OBJ_SET_FROZEN_SHAREABLE(obj); + } return obj; } @@ -14309,7 +14358,7 @@ ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_head VALUE end = ibf_load_object(load, range->end); VALUE obj = rb_range_new(beg, end, range->excl); if (header->internal) rb_obj_hide(obj); - if (header->frozen) rb_obj_freeze(obj); + if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj); return obj; } @@ -14337,7 +14386,7 @@ ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_head big_unpack_flags | (sign == 0 ? INTEGER_PACK_NEGATIVE : 0)); if (header->internal) rb_obj_hide(obj); - if (header->frozen) rb_obj_freeze(obj); + if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj); return obj; } @@ -14398,7 +14447,7 @@ ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_o rb_complex_new(a, b) : rb_rational_new(a, b); if (header->internal) rb_obj_hide(obj); - if (header->frozen) rb_obj_freeze(obj); + if (header->frozen) rb_ractor_make_shareable(rb_obj_freeze(obj)); return obj; } @@ -263,6 +263,7 @@ array.$(OBJEXT): {$(VPATH)}onigmo.h array.$(OBJEXT): {$(VPATH)}oniguruma.h array.$(OBJEXT): {$(VPATH)}probes.dmyh array.$(OBJEXT): {$(VPATH)}probes.h +array.$(OBJEXT): {$(VPATH)}ractor.h array.$(OBJEXT): {$(VPATH)}ruby_assert.h array.$(OBJEXT): {$(VPATH)}ruby_atomic.h array.$(OBJEXT): {$(VPATH)}rubyparser.h @@ -4385,6 +4386,7 @@ encoding.$(OBJEXT): {$(VPATH)}missing.h encoding.$(OBJEXT): {$(VPATH)}node.h encoding.$(OBJEXT): {$(VPATH)}onigmo.h encoding.$(OBJEXT): {$(VPATH)}oniguruma.h +encoding.$(OBJEXT): {$(VPATH)}ractor.h encoding.$(OBJEXT): {$(VPATH)}regenc.h encoding.$(OBJEXT): {$(VPATH)}ruby_assert.h encoding.$(OBJEXT): {$(VPATH)}ruby_atomic.h @@ -16794,6 +16796,7 @@ string.$(OBJEXT): {$(VPATH)}onigmo.h string.$(OBJEXT): {$(VPATH)}oniguruma.h string.$(OBJEXT): {$(VPATH)}probes.dmyh string.$(OBJEXT): {$(VPATH)}probes.h +string.$(OBJEXT): {$(VPATH)}ractor.h string.$(OBJEXT): {$(VPATH)}re.h string.$(OBJEXT): {$(VPATH)}regex.h string.$(OBJEXT): {$(VPATH)}ruby_assert.h @@ -17265,6 +17268,7 @@ symbol.$(OBJEXT): {$(VPATH)}onigmo.h symbol.$(OBJEXT): {$(VPATH)}oniguruma.h symbol.$(OBJEXT): {$(VPATH)}probes.dmyh symbol.$(OBJEXT): {$(VPATH)}probes.h +symbol.$(OBJEXT): {$(VPATH)}ractor.h symbol.$(OBJEXT): {$(VPATH)}ruby_assert.h symbol.$(OBJEXT): {$(VPATH)}ruby_atomic.h symbol.$(OBJEXT): {$(VPATH)}rubyparser.h diff --git a/encoding.c b/encoding.c index da434cda1a..3d5c1d7772 100644 --- a/encoding.c +++ b/encoding.c @@ -27,6 +27,7 @@ #include "ruby/atomic.h" #include "ruby/encoding.h" #include "ruby/util.h" +#include "ruby/ractor.h" #include "ruby_assert.h" #include "vm_sync.h" #include "ruby_atomic.h" @@ -135,8 +136,7 @@ static VALUE enc_new(rb_encoding *encoding) { VALUE enc = TypedData_Wrap_Struct(rb_cEncoding, &encoding_data_type, (void *)encoding); - rb_obj_freeze(enc); - FL_SET_RAW(enc, RUBY_FL_SHAREABLE); + RB_OBJ_SET_FROZEN_SHAREABLE(enc); return enc; } @@ -2804,13 +2804,17 @@ mark_m_tbl(void *objspace, struct rb_id_table *tbl) } } +bool rb_gc_impl_checking_shareable(void *objspace_ptr); // in defaut/deafult.c + static enum rb_id_table_iterator_result mark_const_entry_i(VALUE value, void *objspace) { const rb_const_entry_t *ce = (const rb_const_entry_t *)value; - gc_mark_internal(ce->value); - gc_mark_internal(ce->file); + if (!rb_gc_impl_checking_shareable(objspace)) { + gc_mark_internal(ce->value); + gc_mark_internal(ce->file); // TODO: ce->file should be shareable? + } return ID_TABLE_CONTINUE; } @@ -3071,7 +3075,12 @@ gc_mark_classext_module(rb_classext_t *ext, bool prime, VALUE namespace, void *a gc_mark_internal(RCLASSEXT_SUPER(ext)); } mark_m_tbl(objspace, RCLASSEXT_M_TBL(ext)); - gc_mark_internal(RCLASSEXT_FIELDS_OBJ(ext)); + + if (!rb_gc_impl_checking_shareable(objspace)) { + // unshareable + gc_mark_internal(RCLASSEXT_FIELDS_OBJ(ext)); + } + if (!RCLASSEXT_SHARED_CONST_TBL(ext) && RCLASSEXT_CONST_TBL(ext)) { mark_const_tbl(objspace, RCLASSEXT_CONST_TBL(ext)); } @@ -3137,7 +3146,8 @@ rb_gc_mark_children(void *objspace, VALUE obj) switch (BUILTIN_TYPE(obj)) { case T_CLASS: - if (FL_TEST_RAW(obj, FL_SINGLETON)) { + if (FL_TEST_RAW(obj, FL_SINGLETON) && + !rb_gc_impl_checking_shareable(objspace)) { gc_mark_internal(RCLASS_ATTACHED_OBJECT(obj)); } // Continue to the shared T_CLASS/T_MODULE diff --git a/gc/default/default.c b/gc/default/default.c index 7cceb9911b..b1c3bbf1a6 100644 --- a/gc/default/default.c +++ b/gc/default/default.c @@ -5053,6 +5053,10 @@ verify_internal_consistency_i(void *page_start, void *page_end, size_t stride, rb_objspace_reachable_objects_from(obj, check_generation_i, (void *)data); } + if (!is_marking(objspace) && RB_OBJ_SHAREABLE_P(obj)) { + gc_verify_shareable(objspace, obj, data); + } + if (is_incremental_marking(objspace)) { if (RVALUE_BLACK_P(objspace, obj)) { /* reachable objects from black objects should be black or grey objects */ @@ -8975,6 +8979,12 @@ gc_profile_disable(VALUE _) return Qnil; } +void +rb_gc_verify_internal_consistency(void) +{ + gc_verify_internal_consistency(rb_gc_get_objspace()); +} + /* * call-seq: * GC.verify_internal_consistency -> nil @@ -8988,7 +8998,7 @@ gc_profile_disable(VALUE _) static VALUE gc_verify_internal_consistency_m(VALUE dummy) { - gc_verify_internal_consistency(rb_gc_get_objspace()); + rb_gc_verify_internal_consistency(); return Qnil; } @@ -7474,6 +7474,7 @@ Init_Hash(void) rb_define_singleton_method(rb_cHash, "ruby2_keywords_hash", rb_hash_s_ruby2_keywords_hash, 1); rb_cHash_empty_frozen = rb_hash_freeze(rb_hash_new()); + RB_OBJ_SET_SHAREABLE(rb_cHash_empty_frozen); rb_vm_register_global_object(rb_cHash_empty_frozen); /* Document-class: ENV @@ -7643,8 +7644,7 @@ Init_Hash(void) origenviron = environ; envtbl = TypedData_Wrap_Struct(rb_cObject, &env_data_type, NULL); rb_extend_object(envtbl, rb_mEnumerable); - FL_SET_RAW(envtbl, RUBY_FL_SHAREABLE); - + RB_OBJ_SET_SHAREABLE(envtbl); rb_define_singleton_method(envtbl, "[]", rb_f_getenv, 1); rb_define_singleton_method(envtbl, "fetch", env_fetch, -1); diff --git a/id_table.c b/id_table.c index b705873191..eb8477237e 100644 --- a/id_table.c +++ b/id_table.c @@ -373,6 +373,7 @@ rb_managed_id_table_create(const rb_data_type_t *type, size_t capa) { struct rb_id_table *tbl; VALUE obj = TypedData_Make_Struct(0, struct rb_id_table, type, tbl); + RB_OBJ_SET_SHAREABLE(obj); rb_id_table_init(tbl, capa); return obj; } @@ -40,9 +40,9 @@ rb_imemo_name(enum imemo_type type) * ========================================================================= */ VALUE -rb_imemo_new(enum imemo_type type, VALUE v0, size_t size) +rb_imemo_new(enum imemo_type type, VALUE v0, size_t size, bool is_shareable) { - VALUE flags = T_IMEMO | FL_WB_PROTECTED | (type << FL_USHIFT); + VALUE flags = T_IMEMO | FL_WB_PROTECTED | (type << FL_USHIFT) | (is_shareable ? FL_SHAREABLE : 0); NEWOBJ_OF(obj, void, v0, flags, size, 0); return (VALUE)obj; @@ -98,16 +98,16 @@ rb_free_tmp_buffer(volatile VALUE *store) } static VALUE -imemo_fields_new(VALUE owner, size_t capa) +imemo_fields_new(VALUE owner, size_t capa, bool shareable) { size_t embedded_size = offsetof(struct rb_fields, as.embed) + capa * sizeof(VALUE); if (rb_gc_size_allocatable_p(embedded_size)) { - VALUE fields = rb_imemo_new(imemo_fields, owner, embedded_size); + VALUE fields = rb_imemo_new(imemo_fields, owner, embedded_size, shareable); RUBY_ASSERT(IMEMO_TYPE_P(fields, imemo_fields)); return fields; } else { - VALUE fields = rb_imemo_new(imemo_fields, owner, sizeof(struct rb_fields)); + VALUE fields = rb_imemo_new(imemo_fields, owner, sizeof(struct rb_fields), shareable); IMEMO_OBJ_FIELDS(fields)->as.external.ptr = ALLOC_N(VALUE, capa); FL_SET_RAW(fields, OBJ_FIELD_HEAP); return fields; @@ -115,24 +115,24 @@ imemo_fields_new(VALUE owner, size_t capa) } VALUE -rb_imemo_fields_new(VALUE owner, size_t capa) +rb_imemo_fields_new(VALUE owner, size_t capa, bool shareable) { - return imemo_fields_new(owner, capa); + return imemo_fields_new(owner, capa, shareable); } static VALUE -imemo_fields_new_complex(VALUE owner, size_t capa) +imemo_fields_new_complex(VALUE owner, size_t capa, bool shareable) { - VALUE fields = rb_imemo_new(imemo_fields, owner, sizeof(struct rb_fields)); + VALUE fields = rb_imemo_new(imemo_fields, owner, sizeof(struct rb_fields), shareable); IMEMO_OBJ_FIELDS(fields)->as.complex.table = st_init_numtable_with_size(capa); FL_SET_RAW(fields, OBJ_FIELD_HEAP); return fields; } VALUE -rb_imemo_fields_new_complex(VALUE owner, size_t capa) +rb_imemo_fields_new_complex(VALUE owner, size_t capa, bool shareable) { - return imemo_fields_new_complex(owner, capa); + return imemo_fields_new_complex(owner, capa, shareable); } static int @@ -151,9 +151,9 @@ imemo_fields_complex_wb_i(st_data_t key, st_data_t value, st_data_t arg) } VALUE -rb_imemo_fields_new_complex_tbl(VALUE owner, st_table *tbl) +rb_imemo_fields_new_complex_tbl(VALUE owner, st_table *tbl, bool shareable) { - VALUE fields = rb_imemo_new(imemo_fields, owner, sizeof(struct rb_fields)); + VALUE fields = rb_imemo_new(imemo_fields, owner, sizeof(struct rb_fields), shareable); IMEMO_OBJ_FIELDS(fields)->as.complex.table = tbl; FL_SET_RAW(fields, OBJ_FIELD_HEAP); st_foreach(tbl, imemo_fields_trigger_wb_i, (st_data_t)fields); @@ -170,7 +170,7 @@ rb_imemo_fields_clone(VALUE fields_obj) st_table *src_table = rb_imemo_fields_complex_tbl(fields_obj); st_table *dest_table = xcalloc(1, sizeof(st_table)); - clone = rb_imemo_fields_new_complex_tbl(rb_imemo_fields_owner(fields_obj), dest_table); + clone = rb_imemo_fields_new_complex_tbl(rb_imemo_fields_owner(fields_obj), dest_table, false /* TODO: check */); st_replace(dest_table, src_table); RBASIC_SET_SHAPE_ID(clone, shape_id); @@ -178,7 +178,7 @@ rb_imemo_fields_clone(VALUE fields_obj) st_foreach(dest_table, imemo_fields_complex_wb_i, (st_data_t)clone); } else { - clone = imemo_fields_new(rb_imemo_fields_owner(fields_obj), RSHAPE_CAPACITY(shape_id)); + clone = imemo_fields_new(rb_imemo_fields_owner(fields_obj), RSHAPE_CAPACITY(shape_id), false /* TODO: check */); RBASIC_SET_SHAPE_ID(clone, shape_id); VALUE *fields = rb_imemo_fields_ptr(clone); attr_index_t fields_count = RSHAPE_LEN(shape_id); @@ -303,7 +303,9 @@ mark_and_move_method_entry(rb_method_entry_t *ment, bool reference_updating) rb_gc_mark_and_move(&def->body.attr.location); break; case VM_METHOD_TYPE_BMETHOD: - rb_gc_mark_and_move(&def->body.bmethod.proc); + if (!rb_gc_checking_shareable()) { + rb_gc_mark_and_move(&def->body.bmethod.proc); + } if (def->body.bmethod.hooks) { rb_hook_list_mark_and_move(def->body.bmethod.hooks); } @@ -386,16 +388,27 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating) case imemo_constcache: { struct iseq_inline_constant_cache_entry *ice = (struct iseq_inline_constant_cache_entry *)obj; - rb_gc_mark_and_move(&ice->value); + if ((ice->flags & IMEMO_CONST_CACHE_SHAREABLE) || + !rb_gc_checking_shareable()) { + rb_gc_mark_and_move(&ice->value); + } break; } case imemo_cref: { rb_cref_t *cref = (rb_cref_t *)obj; - rb_gc_mark_and_move(&cref->klass_or_self); + if (!rb_gc_checking_shareable()) { + // cref->klass_or_self can be unshareable, but no way to access it from other ractors + rb_gc_mark_and_move(&cref->klass_or_self); + } + rb_gc_mark_and_move_ptr(&cref->next); - rb_gc_mark_and_move(&cref->refinements); + + // TODO: Ractor and refeinements are not resolved yet + if (!rb_gc_checking_shareable()) { + rb_gc_mark_and_move(&cref->refinements); + } break; } @@ -481,20 +494,25 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating) case imemo_fields: { rb_gc_mark_and_move((VALUE *)&RBASIC(obj)->klass); - if (rb_shape_obj_too_complex_p(obj)) { - st_table *tbl = rb_imemo_fields_complex_tbl(obj); - if (reference_updating) { - rb_gc_ref_update_table_values_only(tbl); + if (!rb_gc_checking_shareable()) { + // imemo_fields can refer unshareable objects + // even if the imemo_fields is shareable. + + if (rb_shape_obj_too_complex_p(obj)) { + st_table *tbl = rb_imemo_fields_complex_tbl(obj); + if (reference_updating) { + rb_gc_ref_update_table_values_only(tbl); + } + else { + rb_mark_tbl_no_pin(tbl); + } } else { - rb_mark_tbl_no_pin(tbl); - } - } - else { - VALUE *fields = rb_imemo_fields_ptr(obj); - attr_index_t len = RSHAPE_LEN(RBASIC_SHAPE_ID(obj)); - for (attr_index_t i = 0; i < len; i++) { - rb_gc_mark_and_move(&fields[i]); + VALUE *fields = rb_imemo_fields_ptr(obj); + attr_index_t len = RSHAPE_LEN(RBASIC_SHAPE_ID(obj)); + for (attr_index_t i = 0; i < len; i++) { + rb_gc_mark_and_move(&fields[i]); + } } } break; diff --git a/internal/class.h b/internal/class.h index a791672cad..5d843e58da 100644 --- a/internal/class.h +++ b/internal/class.h @@ -555,7 +555,7 @@ RCLASS_WRITABLE_ENSURE_FIELDS_OBJ(VALUE obj) RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE)); rb_classext_t *ext = RCLASS_EXT_WRITABLE(obj); if (!ext->fields_obj) { - RB_OBJ_WRITE(obj, &ext->fields_obj, rb_imemo_fields_new(obj, 1)); + RB_OBJ_WRITE(obj, &ext->fields_obj, rb_imemo_fields_new(obj, 1, true)); } return ext->fields_obj; } @@ -762,6 +762,7 @@ RCLASS_SET_CLASSPATH(VALUE klass, VALUE classpath, bool permanent) rb_classext_t *ext = RCLASS_EXT_READABLE(klass); assert(BUILTIN_TYPE(klass) == T_CLASS || BUILTIN_TYPE(klass) == T_MODULE); assert(classpath == 0 || BUILTIN_TYPE(classpath) == T_STRING); + assert(FL_TEST_RAW(classpath, RUBY_FL_SHAREABLE)); RB_OBJ_WRITE(klass, &(RCLASSEXT_CLASSPATH(ext)), classpath); RCLASSEXT_PERMANENT_CLASSPATH(ext) = permanent; @@ -773,6 +774,7 @@ RCLASS_WRITE_CLASSPATH(VALUE klass, VALUE classpath, bool permanent) rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass); assert(BUILTIN_TYPE(klass) == T_CLASS || BUILTIN_TYPE(klass) == T_MODULE); assert(classpath == 0 || BUILTIN_TYPE(classpath) == T_STRING); + assert(!RB_FL_ABLE(classpath) || FL_TEST_RAW(classpath, RUBY_FL_SHAREABLE)); RB_OBJ_WRITE(klass, &(RCLASSEXT_CLASSPATH(ext)), classpath); RCLASSEXT_PERMANENT_CLASSPATH(ext) = permanent; diff --git a/internal/gc.h b/internal/gc.h index 7357bef732..ec408d7fac 100644 --- a/internal/gc.h +++ b/internal/gc.h @@ -353,5 +353,6 @@ ruby_sized_realloc_n(void *ptr, size_t new_count, size_t element_size, size_t ol #define ruby_sized_xfree ruby_sized_xfree_inlined void rb_gc_verify_shareable(VALUE); +bool rb_gc_checking_shareable(void); #endif /* INTERNAL_GC_H */ diff --git a/internal/imemo.h b/internal/imemo.h index 3b91ef4b81..f8bda26f0b 100644 --- a/internal/imemo.h +++ b/internal/imemo.h @@ -114,7 +114,8 @@ struct MEMO { } u3; }; -#define IMEMO_NEW(T, type, v0) ((T *)rb_imemo_new((type), (v0), sizeof(T))) +#define IMEMO_NEW(T, type, v0) ((T *)rb_imemo_new((type), (v0), sizeof(T), false)) +#define SHAREABLE_IMEMO_NEW(T, type, v0) ((T *)rb_imemo_new((type), (v0), sizeof(T), true)) /* ment is in method.h */ @@ -131,7 +132,7 @@ struct MEMO { #ifndef RUBY_RUBYPARSER_H typedef struct rb_imemo_tmpbuf_struct rb_imemo_tmpbuf_t; #endif -VALUE rb_imemo_new(enum imemo_type type, VALUE v0, size_t size); +VALUE rb_imemo_new(enum imemo_type type, VALUE v0, size_t size, bool is_shareable); VALUE rb_imemo_tmpbuf_new(void); struct vm_ifunc *rb_vm_ifunc_new(rb_block_call_func_t func, const void *data, int min_argc, int max_argc); static inline enum imemo_type imemo_type(VALUE imemo); @@ -270,9 +271,9 @@ STATIC_ASSERT(imemo_fields_embed_offset, offsetof(struct RObject, as.heap.fields #define IMEMO_OBJ_FIELDS(fields) ((struct rb_fields *)fields) -VALUE rb_imemo_fields_new(VALUE owner, size_t capa); -VALUE rb_imemo_fields_new_complex(VALUE owner, size_t capa); -VALUE rb_imemo_fields_new_complex_tbl(VALUE owner, st_table *tbl); +VALUE rb_imemo_fields_new(VALUE owner, size_t capa, bool shareable); +VALUE rb_imemo_fields_new_complex(VALUE owner, size_t capa, bool shareable); +VALUE rb_imemo_fields_new_complex_tbl(VALUE owner, st_table *tbl, bool shareable); VALUE rb_imemo_fields_clone(VALUE fields_obj); void rb_imemo_fields_clear(VALUE fields_obj); @@ -425,13 +425,15 @@ rb_iseq_mark_and_move(rb_iseq_t *iseq, bool reference_updating) rb_gc_mark_and_move(&iseq->aux.loader.obj); } else if (FL_TEST_RAW((VALUE)iseq, ISEQ_USE_COMPILE_DATA)) { - const struct iseq_compile_data *const compile_data = ISEQ_COMPILE_DATA(iseq); + if (!rb_gc_checking_shareable()) { + const struct iseq_compile_data *const compile_data = ISEQ_COMPILE_DATA(iseq); - rb_iseq_mark_and_move_insn_storage(compile_data->insn.storage_head); - rb_iseq_mark_and_move_each_compile_data_value(iseq, reference_updating ? ISEQ_ORIGINAL_ISEQ(iseq) : NULL); + rb_iseq_mark_and_move_insn_storage(compile_data->insn.storage_head); + rb_iseq_mark_and_move_each_compile_data_value(iseq, reference_updating ? ISEQ_ORIGINAL_ISEQ(iseq) : NULL); - rb_gc_mark_and_move((VALUE *)&compile_data->err_info); - rb_gc_mark_and_move((VALUE *)&compile_data->catch_table_ary); + rb_gc_mark_and_move((VALUE *)&compile_data->err_info); + rb_gc_mark_and_move((VALUE *)&compile_data->catch_table_ary); + } } else { /* executable */ @@ -544,9 +546,14 @@ rb_iseq_pathobj_new(VALUE path, VALUE realpath) pathobj = rb_fstring(path); } else { - if (!NIL_P(realpath)) realpath = rb_fstring(realpath); - pathobj = rb_ary_new_from_args(2, rb_fstring(path), realpath); + if (!NIL_P(realpath)) { + realpath = rb_fstring(realpath); + } + VALUE fpath = rb_fstring(path); + + pathobj = rb_ary_new_from_args(2, fpath, realpath); rb_ary_freeze(pathobj); + RB_OBJ_SET_SHAREABLE(pathobj); } return pathobj; } @@ -565,6 +572,11 @@ rb_iseq_alloc_with_dummy_path(VALUE fname) rb_iseq_t *dummy_iseq = iseq_alloc(); ISEQ_BODY(dummy_iseq)->type = ISEQ_TYPE_TOP; + + if (!RB_OBJ_SHAREABLE_P(fname)) { + RB_OBJ_SET_FROZEN_SHAREABLE(fname); + } + RB_OBJ_WRITE(dummy_iseq, &ISEQ_BODY(dummy_iseq)->location.pathobj, fname); RB_OBJ_WRITE(dummy_iseq, &ISEQ_BODY(dummy_iseq)->location.label, fname); @@ -1568,6 +1580,7 @@ iseqw_new(const rb_iseq_t *iseq) RB_OBJ_WRITE(obj, ptr, iseq); /* cache a wrapper object */ + RB_OBJ_SET_FROZEN_SHAREABLE((VALUE)obj); RB_OBJ_WRITE((VALUE)iseq, &iseq->wrapper, obj); return obj; @@ -175,7 +175,7 @@ ISEQ_COMPILE_DATA_CLEAR(rb_iseq_t *iseq) static inline rb_iseq_t * iseq_imemo_alloc(void) { - rb_iseq_t *iseq = IMEMO_NEW(rb_iseq_t, imemo_iseq, 0); + rb_iseq_t *iseq = SHAREABLE_IMEMO_NEW(rb_iseq_t, imemo_iseq, 0); // Clear out the whole iseq except for the flags. memset((char *)iseq + sizeof(VALUE), 0, sizeof(rb_iseq_t) - sizeof(VALUE)); diff --git a/prism_compile.c b/prism_compile.c index 86753c90cc..6b4e32f629 100644 --- a/prism_compile.c +++ b/prism_compile.c @@ -201,6 +201,10 @@ parse_integer_value(const pm_integer_t *integer) result = rb_funcall(result, rb_intern("-@"), 0); } + if (!SPECIAL_CONST_P(result)) { + RB_OBJ_SET_SHAREABLE(result); // bignum + } + return result; } @@ -219,7 +223,11 @@ parse_integer(const pm_integer_node_t *node) static VALUE parse_float(const pm_float_node_t *node) { - return DBL2NUM(node->value); + VALUE val = DBL2NUM(node->value); + if (!FLONUM_P(val)) { + RB_OBJ_SET_SHAREABLE(val); + } + return val; } /** @@ -233,7 +241,8 @@ parse_rational(const pm_rational_node_t *node) { VALUE numerator = parse_integer_value(&node->numerator); VALUE denominator = parse_integer_value(&node->denominator); - return rb_rational_new(numerator, denominator); + + return rb_ractor_make_shareable(rb_rational_new(numerator, denominator)); } /** @@ -263,7 +272,7 @@ parse_imaginary(const pm_imaginary_node_t *node) rb_bug("Unexpected numeric type on imaginary number %s\n", pm_node_type_to_str(PM_NODE_TYPE(node->numeric))); } - return rb_complex_raw(INT2FIX(0), imaginary_part); + return RB_OBJ_SET_SHAREABLE(rb_complex_raw(INT2FIX(0), imaginary_part)); } static inline VALUE @@ -315,7 +324,7 @@ parse_static_literal_string(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) { int line_number = pm_node_line_number(scope_node->parser, node); - value = rb_str_with_debug_created_info(value, rb_iseq_path(iseq), line_number); + value = rb_ractor_make_shareable(rb_str_with_debug_created_info(value, rb_iseq_path(iseq), line_number)); } return value; @@ -531,8 +540,7 @@ parse_regexp(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_node_t return Qnil; } - rb_obj_freeze(regexp); - return regexp; + return RB_OBJ_SET_SHAREABLE(rb_obj_freeze(regexp)); } static inline VALUE @@ -542,6 +550,7 @@ parse_regexp_literal(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const p if (regexp_encoding == NULL) regexp_encoding = scope_node->encoding; VALUE string = rb_enc_str_new((const char *) pm_string_source(unescaped), pm_string_length(unescaped), regexp_encoding); + RB_OBJ_SET_SHAREABLE(string); return parse_regexp(iseq, scope_node, node, string); } @@ -724,7 +733,9 @@ static VALUE pm_static_literal_string(rb_iseq_t *iseq, VALUE string, int line_number) { if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) { - return rb_str_with_debug_created_info(string, rb_iseq_path(iseq), line_number); + VALUE str = rb_str_with_debug_created_info(string, rb_iseq_path(iseq), line_number); + RB_OBJ_SET_SHAREABLE(str); + return str; } else { return rb_fstring(string); @@ -753,7 +764,7 @@ pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, const pm_scope_n rb_ary_push(value, pm_static_literal_value(iseq, elements->nodes[index], scope_node)); } - OBJ_FREEZE(value); + RB_OBJ_SET_FROZEN_SHAREABLE(value); return value; } case PM_FALSE_NODE: @@ -776,7 +787,7 @@ pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, const pm_scope_n rb_hash_bulk_insert(RARRAY_LEN(array), RARRAY_CONST_PTR(array), value); value = rb_obj_hide(value); - OBJ_FREEZE(value); + RB_OBJ_SET_FROZEN_SHAREABLE(value); return value; } case PM_IMAGINARY_NODE: @@ -1445,7 +1456,7 @@ pm_compile_hash_elements(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_l VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2); rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash); hash = rb_obj_hide(hash); - OBJ_FREEZE(hash); + RB_OBJ_SET_FROZEN_SHAREABLE(hash); // Emit optimized code. FLUSH_CHUNK; @@ -2860,8 +2871,10 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t PUSH_INSN(ret, location, putnil); } else { + rb_obj_hide(keys); + RB_OBJ_SET_FROZEN_SHAREABLE(keys); PUSH_INSN1(ret, location, duparray, keys); - RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys)); + RB_OBJ_WRITTEN(iseq, Qundef, keys); } PUSH_SEND(ret, location, rb_intern("deconstruct_keys"), INT2FIX(1)); @@ -2897,6 +2910,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t { VALUE operand = rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, symbol)); + RB_OBJ_SET_SHAREABLE(operand); PUSH_INSN1(ret, location, putobject, operand); } @@ -5545,6 +5559,7 @@ pm_compile_constant_read(rb_iseq_t *iseq, VALUE name, const pm_location_t *name_ if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) { ISEQ_BODY(iseq)->ic_size++; VALUE segments = rb_ary_new_from_args(1, name); + RB_OBJ_SET_SHAREABLE(segments); PUSH_INSN1(ret, location, opt_getconstant_path, segments); } else { @@ -5758,6 +5773,9 @@ pm_compile_shareable_constant_value(rb_iseq_t *iseq, const pm_node_t *node, cons if (shareability & PM_SHAREABLE_CONSTANT_NODE_FLAGS_LITERAL) { PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); PUSH_SEQ(ret, value_seq); + if (!RB_OBJ_SHAREABLE_P(path)) { + RB_OBJ_SET_SHAREABLE(path); + } PUSH_INSN1(ret, location, putobject, path); PUSH_SEND_WITH_FLAG(ret, location, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE)); } @@ -7108,6 +7126,7 @@ pm_compile_array_node(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_list if (!popped) { if (elements->size) { VALUE value = pm_static_literal_value(iseq, node, scope_node); + RB_OBJ_SET_FROZEN_SHAREABLE(value); PUSH_INSN1(ret, *location, duparray, value); } else { @@ -7238,7 +7257,7 @@ pm_compile_array_node(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_list rb_ary_push(tmp_array, pm_static_literal_value(iseq, elements->nodes[index++], scope_node)); index--; // about to be incremented by for loop - OBJ_FREEZE(tmp_array); + RB_OBJ_SET_FROZEN_SHAREABLE(tmp_array); // Emit the optimized code. FLUSH_CHUNK; @@ -7465,7 +7484,6 @@ static VALUE pm_compile_case_node_dispatch(rb_iseq_t *iseq, VALUE dispatch, const pm_node_t *node, LABEL *label, const pm_scope_node_t *scope_node) { VALUE key = Qundef; - switch (PM_NODE_TYPE(node)) { case PM_FLOAT_NODE: { key = pm_static_literal_value(iseq, node, scope_node); @@ -7498,7 +7516,6 @@ pm_compile_case_node_dispatch(rb_iseq_t *iseq, VALUE dispatch, const pm_node_t * if (NIL_P(rb_hash_lookup(dispatch, key))) { rb_hash_aset(dispatch, key, ((VALUE) label) | 1); } - return dispatch; } @@ -7726,6 +7743,7 @@ pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_ // optimization. if (dispatch != Qundef) { PUSH_INSN(ret, location, dup); + RB_OBJ_SET_SHAREABLE(dispatch); // it is special that the hash is shareable but not frozen, because compile.c modify them. This Hahs instance is not accessible so it is safe to leave it. PUSH_INSN2(ret, location, opt_case_dispatch, dispatch, else_label); LABEL_REF(else_label); } @@ -8953,6 +8971,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache && ((parts = pm_constant_path_parts(node, scope_node)) != Qnil)) { ISEQ_BODY(iseq)->ic_size++; + RB_OBJ_SET_SHAREABLE(parts); PUSH_INSN1(ret, location, opt_getconstant_path, parts); } else { @@ -10068,6 +10087,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, exclude_end ); + RB_OBJ_SET_SHAREABLE(val); PUSH_INSN1(ret, location, putobject, val); } } @@ -207,28 +207,34 @@ static void ractor_mark(void *ptr) { rb_ractor_t *r = (rb_ractor_t *)ptr; + bool checking_shareable = rb_gc_checking_shareable(); // mark received messages ractor_sync_mark(r); rb_gc_mark(r->loc); rb_gc_mark(r->name); - rb_gc_mark(r->r_stdin); - rb_gc_mark(r->r_stdout); - rb_gc_mark(r->r_stderr); - rb_gc_mark(r->verbose); - rb_gc_mark(r->debug); - rb_hook_list_mark(&r->pub.hooks); - - if (r->threads.cnt > 0) { - rb_thread_t *th = 0; - ccan_list_for_each(&r->threads.set, th, lt_node) { - VM_ASSERT(th != NULL); - rb_gc_mark(th->self); + + if (!checking_shareable) { + // may unshareable objects + rb_gc_mark(r->r_stdin); + rb_gc_mark(r->r_stdout); + rb_gc_mark(r->r_stderr); + rb_gc_mark(r->verbose); + rb_gc_mark(r->debug); + + rb_hook_list_mark(&r->pub.hooks); + + if (r->threads.cnt > 0) { + rb_thread_t *th = 0; + ccan_list_for_each(&r->threads.set, th, lt_node) { + VM_ASSERT(th != NULL); + rb_gc_mark(th->self); + } } - } - ractor_local_storage_mark(r); + ractor_local_storage_mark(r); + } } static void @@ -493,8 +499,9 @@ ractor_init(rb_ractor_t *r, VALUE name, VALUE loc) } name = rb_str_new_frozen(name); } - r->name = name; + if (!SPECIAL_CONST_P(loc)) RB_OBJ_SET_SHAREABLE(loc); r->loc = loc; + r->name = name; } void @@ -1462,6 +1469,10 @@ make_shareable_check_shareable(VALUE obj) static enum obj_traverse_iterator_result mark_shareable(VALUE obj) { + if (RB_TYPE_P(obj, T_STRING)) { + rb_str_make_independent(obj); + } + rb_obj_set_shareable_no_assert(obj); return traverse_cont; } @@ -3369,10 +3369,13 @@ static void reg_set_source(VALUE reg, VALUE str, rb_encoding *enc) { rb_encoding *regenc = rb_enc_get(reg); + if (regenc != enc) { - str = rb_enc_associate(rb_str_dup(str), enc = regenc); + VALUE dup = rb_str_dup(str); + str = rb_enc_associate(dup, enc = regenc); } - RB_OBJ_WRITE(reg, &RREGEXP(reg)->src, rb_fstring(str)); + str = rb_fstring(str); + RB_OBJ_WRITE(reg, &RREGEXP(reg)->src, str); } static int @@ -45,6 +45,7 @@ #include "ruby/re.h" #include "ruby/thread.h" #include "ruby/util.h" +#include "ruby/ractor.h" #include "ruby_assert.h" #include "shape.h" #include "vm_sync.h" @@ -537,7 +538,10 @@ fstring_concurrent_set_create(VALUE str, void *data) ENC_CODERANGE_SET(str, coderange); RBASIC(str)->flags |= RSTRING_FSTR; - + if (!RB_OBJ_SHAREABLE_P(str)) { + RB_OBJ_SET_SHAREABLE(str); + } + RUBY_ASSERT((rb_gc_verify_shareable(str), 1)); RUBY_ASSERT(RB_TYPE_P(str, T_STRING)); RUBY_ASSERT(OBJ_FROZEN(str)); RUBY_ASSERT(!FL_TEST_RAW(str, STR_FAKESTR)); @@ -583,6 +587,8 @@ register_fstring(VALUE str, bool copy, bool force_precompute_hash) RUBY_ASSERT(!rb_objspace_garbage_object_p(result)); RUBY_ASSERT(RB_TYPE_P(result, T_STRING)); RUBY_ASSERT(OBJ_FROZEN(result)); + RUBY_ASSERT(RB_OBJ_SHAREABLE_P(result)); + RUBY_ASSERT((rb_gc_verify_shareable(result), 1)); RUBY_ASSERT(!FL_TEST_RAW(result, STR_FAKESTR)); RUBY_ASSERT(RBASIC_CLASS(result) == rb_cString); @@ -1555,6 +1561,10 @@ rb_str_tmp_frozen_no_embed_acquire(VALUE orig) RBASIC(str)->flags |= RBASIC(orig)->flags & STR_NOFREE; RBASIC(orig)->flags &= ~STR_NOFREE; STR_SET_SHARED(orig, str); + if (RB_OBJ_SHAREABLE_P(orig)) { + RB_OBJ_SET_SHAREABLE(str); + RUBY_ASSERT((rb_gc_verify_shareable(str), 1)); + } } RSTRING(str)->len = RSTRING(orig)->len; @@ -1604,6 +1614,7 @@ heap_str_make_shared(VALUE klass, VALUE orig) { RUBY_ASSERT(!STR_EMBED_P(orig)); RUBY_ASSERT(!STR_SHARED_P(orig)); + RUBY_ASSERT(!RB_OBJ_SHAREABLE_P(orig)); VALUE str = str_alloc_heap(klass); STR_SET_LEN(str, RSTRING_LEN(orig)); @@ -1613,7 +1624,7 @@ heap_str_make_shared(VALUE klass, VALUE orig) RBASIC(orig)->flags &= ~STR_NOFREE; STR_SET_SHARED(orig, str); if (klass == 0) - FL_UNSET_RAW(str, STR_BORROWED); + FL_UNSET_RAW(str, STR_BORROWED); return str; } @@ -1663,7 +1674,12 @@ str_new_frozen_buffer(VALUE klass, VALUE orig, int copy_encoding) TERM_FILL(RSTRING_END(str), TERM_LEN(orig)); } else { - str = heap_str_make_shared(klass, orig); + if (RB_OBJ_SHAREABLE_P(orig)) { + str = str_new(klass, RSTRING_PTR(orig), RSTRING_LEN(orig)); + } + else { + str = heap_str_make_shared(klass, orig); + } } } @@ -12676,7 +12692,9 @@ rb_enc_literal_str(const char *ptr, long len, rb_encoding *enc) } struct RString fake_str = {RBASIC_INIT}; - return register_fstring(rb_setup_fake_str(&fake_str, ptr, len, enc), true, true); + VALUE str = register_fstring(rb_setup_fake_str(&fake_str, ptr, len, enc), true, true); + RUBY_ASSERT(RB_OBJ_SHAREABLE_P(str) && (rb_gc_verify_shareable(str), 1)); + return str; } VALUE @@ -19,6 +19,7 @@ #include "internal/vm.h" #include "probes.h" #include "ruby/encoding.h" +#include "ruby/ractor.h" #include "ruby/st.h" #include "symbol.h" #include "vm_sync.h" @@ -200,7 +201,6 @@ dup_string_for_create(VALUE str) OBJ_FREEZE(str); str = rb_fstring(str); - return str; } @@ -255,8 +255,8 @@ sym_set_create(VALUE sym, void *data) rb_encoding *enc = rb_enc_get(str); rb_enc_set_index((VALUE)obj, rb_enc_to_index(enc)); - OBJ_FREEZE((VALUE)obj); RB_OBJ_WRITE((VALUE)obj, &obj->fstr, str); + RB_OBJ_SET_FROZEN_SHAREABLE((VALUE)obj); int id = rb_str_symname_type(str, IDSET_ATTRSET_FOR_INTERN); if (id < 0) id = ID_INTERNAL; diff --git a/variable.c b/variable.c index 5fc98fb087..bab423e950 100644 --- a/variable.c +++ b/variable.c @@ -321,6 +321,7 @@ rb_mod_set_temporary_name(VALUE mod, VALUE name) } name = rb_str_new_frozen(name); + RB_OBJ_SET_SHAREABLE(name); // Set the temporary classpath to the given name: RB_VM_LOCKING() { @@ -432,6 +433,7 @@ rb_set_class_path_string(VALUE klass, VALUE under, VALUE name) str = build_const_pathname(str, name); } + RB_OBJ_SET_SHAREABLE(str); RCLASS_SET_CLASSPATH(klass, str, permanent); } @@ -1552,7 +1554,7 @@ obj_transition_too_complex(VALUE obj, st_table *table) break; default: { - VALUE fields_obj = rb_imemo_fields_new_complex_tbl(obj, table); + VALUE fields_obj = rb_imemo_fields_new_complex_tbl(obj, table, RB_OBJ_SHAREABLE_P(obj)); RBASIC_SET_SHAPE_ID(fields_obj, shape_id); rb_obj_replace_fields(obj, fields_obj); } @@ -1731,7 +1733,7 @@ static VALUE imemo_fields_complex_from_obj(VALUE owner, VALUE source_fields_obj, shape_id_t shape_id) { attr_index_t len = source_fields_obj ? RSHAPE_LEN(RBASIC_SHAPE_ID(source_fields_obj)) : 0; - VALUE fields_obj = rb_imemo_fields_new_complex(owner, len + 1); + VALUE fields_obj = rb_imemo_fields_new_complex(owner, len + 1, RB_OBJ_SHAREABLE_P(owner)); rb_field_foreach(source_fields_obj, imemo_fields_complex_from_obj_i, (st_data_t)fields_obj, false); RBASIC_SET_SHAPE_ID(fields_obj, shape_id); @@ -1742,7 +1744,7 @@ imemo_fields_complex_from_obj(VALUE owner, VALUE source_fields_obj, shape_id_t s static VALUE imemo_fields_copy_capa(VALUE owner, VALUE source_fields_obj, attr_index_t new_size) { - VALUE fields_obj = rb_imemo_fields_new(owner, new_size); + VALUE fields_obj = rb_imemo_fields_new(owner, new_size, RB_OBJ_SHAREABLE_P(owner)); if (source_fields_obj) { attr_index_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(source_fields_obj)); VALUE *fields = rb_imemo_fields_ptr(fields_obj); @@ -2227,7 +2229,7 @@ rb_copy_generic_ivar(VALUE dest, VALUE obj) return; } - new_fields_obj = rb_imemo_fields_new(dest, RSHAPE_CAPACITY(dest_shape_id)); + new_fields_obj = rb_imemo_fields_new(dest, RSHAPE_CAPACITY(dest_shape_id), RB_OBJ_SHAREABLE_P(dest)); VALUE *src_buf = rb_imemo_fields_ptr(fields_obj); VALUE *dest_buf = rb_imemo_fields_ptr(new_fields_obj); rb_shape_copy_fields(new_fields_obj, dest_buf, dest_shape_id, src_buf, src_shape_id); @@ -3797,6 +3799,7 @@ static void set_namespace_path(VALUE named_namespace, VALUE namespace_path) { struct rb_id_table *const_table = RCLASS_CONST_TBL(named_namespace); + RB_OBJ_SET_SHAREABLE(namespace_path); RB_VM_LOCKING() { RCLASS_WRITE_CLASSPATH(named_namespace, namespace_path, true); @@ -3875,7 +3878,8 @@ const_set(VALUE klass, ID id, VALUE val) set_namespace_path(val, build_const_path(parental_path, id)); } else if (!parental_path_permanent && NIL_P(val_path)) { - RCLASS_SET_CLASSPATH(val, build_const_path(parental_path, id), false); + VALUE path = build_const_path(parental_path, id); + RCLASS_SET_CLASSPATH(val, path, false); } } } @@ -4488,7 +4492,7 @@ static attr_index_t class_fields_ivar_set(VALUE klass, VALUE fields_obj, ID id, VALUE val, bool concurrent, VALUE *new_fields_obj, bool *new_ivar_out) { const VALUE original_fields_obj = fields_obj; - fields_obj = original_fields_obj ? original_fields_obj : rb_imemo_fields_new(klass, 1); + fields_obj = original_fields_obj ? original_fields_obj : rb_imemo_fields_new(klass, 1, true); shape_id_t current_shape_id = RBASIC_SHAPE_ID(fields_obj); shape_id_t next_shape_id = current_shape_id; // for too_complex @@ -311,7 +311,7 @@ vm_cref_new0(VALUE klass, rb_method_visibility_t visi, int module_func, rb_cref_ VM_ASSERT(singleton || klass); - rb_cref_t *cref = IMEMO_NEW(rb_cref_t, imemo_cref, refinements); + rb_cref_t *cref = SHAREABLE_IMEMO_NEW(rb_cref_t, imemo_cref, refinements); cref->klass_or_self = klass; cref->next = use_prev_prev ? CREF_NEXT(prev_cref) : prev_cref; *((rb_scope_visibility_t *)&cref->scope_visi) = scope_visi; @@ -1311,7 +1311,7 @@ rb_proc_dup(VALUE self) break; } - if (RB_OBJ_SHAREABLE_P(self)) FL_SET_RAW(procval, RUBY_FL_SHAREABLE); + if (RB_OBJ_SHAREABLE_P(self)) RB_OBJ_SET_SHAREABLE(procval); RB_GC_GUARD(self); /* for: body = rb_proc_dup(body) */ return procval; } @@ -1375,7 +1375,19 @@ env_copy(const VALUE *src_ep, VALUE read_only_variables) const rb_env_t *copied_env = vm_env_new(ep, env_body, src_env->env_size, src_env->iseq); // Copy after allocations above, since they can move objects in src_ep. - RB_OBJ_WRITE(copied_env, &ep[VM_ENV_DATA_INDEX_ME_CREF], src_ep[VM_ENV_DATA_INDEX_ME_CREF]); + VALUE svar_val = src_ep[VM_ENV_DATA_INDEX_ME_CREF]; + if (imemo_type_p(svar_val, imemo_svar)) { + const struct vm_svar *svar = (struct vm_svar *)svar_val; + + if (svar->cref_or_me) { + svar_val = svar->cref_or_me; + } + else { + svar_val = Qfalse; + } + } + RB_OBJ_WRITE(copied_env, &ep[VM_ENV_DATA_INDEX_ME_CREF], svar_val); + ep[VM_ENV_DATA_INDEX_FLAGS] = src_ep[VM_ENV_DATA_INDEX_FLAGS] | VM_ENV_FLAG_ISOLATED; if (!VM_ENV_LOCAL_P(src_ep)) { VM_ENV_FLAGS_SET(ep, VM_ENV_FLAG_LOCAL); @@ -1427,6 +1439,7 @@ env_copy(const VALUE *src_ep, VALUE read_only_variables) ep[VM_ENV_DATA_INDEX_SPECVAL] = VM_BLOCK_HANDLER_NONE; } + RB_OBJ_SET_SHAREABLE((VALUE)copied_env); return copied_env; } @@ -1493,9 +1506,10 @@ rb_proc_isolate_bang(VALUE self, VALUE replace_self) proc_isolate_env(self, proc, Qfalse); proc->is_isolated = TRUE; + RB_OBJ_WRITE(self, &proc->block.as.captured.self, Qnil); } - FL_SET_RAW(self, RUBY_FL_SHAREABLE); + RB_OBJ_SET_SHAREABLE(self); return self; } @@ -1537,10 +1551,16 @@ rb_proc_ractor_make_shareable(VALUE self, VALUE replace_self) proc_isolate_env(self, proc, read_only_variables); proc->is_isolated = TRUE; } + else { + VALUE proc_self = vm_block_self(vm_proc_block(self)); + if (!rb_ractor_shareable_p(proc_self)) { + rb_raise(rb_eRactorIsolationError, + "Proc's self is not shareable: %" PRIsVALUE, + self); + } + } - rb_obj_freeze(self); - FL_SET_RAW(self, RUBY_FL_SHAREABLE); - + RB_OBJ_SET_FROZEN_SHAREABLE(self); return self; } diff --git a/vm_callinfo.h b/vm_callinfo.h index 80b5b9a096..6701b17d76 100644 --- a/vm_callinfo.h +++ b/vm_callinfo.h @@ -340,7 +340,7 @@ vm_cc_new(VALUE klass, enum vm_cc_type type) { cc_check_class(klass); - struct rb_callcache *cc = IMEMO_NEW(struct rb_callcache, imemo_callcache, klass); + struct rb_callcache *cc = SHAREABLE_IMEMO_NEW(struct rb_callcache, imemo_callcache, klass); *((struct rb_callable_method_entry_struct **)&cc->cme_) = (struct rb_callable_method_entry_struct *)cme; *((vm_call_handler *)&cc->call_) = call; diff --git a/vm_insnhelper.c b/vm_insnhelper.c index b99ffdc4fd..cbed614329 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -6568,12 +6568,15 @@ vm_ic_update(const rb_iseq_t *iseq, IC ic, VALUE val, const VALUE *reg_ep, const return; } - struct iseq_inline_constant_cache_entry *ice = IMEMO_NEW(struct iseq_inline_constant_cache_entry, imemo_constcache, 0); + struct iseq_inline_constant_cache_entry *ice = SHAREABLE_IMEMO_NEW(struct iseq_inline_constant_cache_entry, imemo_constcache, 0); RB_OBJ_WRITE(ice, &ice->value, val); ice->ic_cref = vm_get_const_key_cref(reg_ep); - if (rb_ractor_shareable_p(val)) ice->flags |= IMEMO_CONST_CACHE_SHAREABLE; - RB_OBJ_WRITE(iseq, &ic->entry, ice); + if (rb_ractor_shareable_p(val)) { + RUBY_ASSERT((rb_gc_verify_shareable(val), 1)); + ice->flags |= IMEMO_CONST_CACHE_SHAREABLE; + } + RB_OBJ_WRITE(iseq, &ic->entry, ice); RUBY_ASSERT(pc >= ISEQ_BODY(iseq)->iseq_encoded); unsigned pos = (unsigned)(pc - ISEQ_BODY(iseq)->iseq_encoded); rb_yjit_constant_ic_update(iseq, ic, pos); @@ -6585,6 +6588,7 @@ rb_vm_opt_getconstant_path(rb_execution_context_t *ec, rb_control_frame_t *const VALUE val; const ID *segments = ic->segments; struct iseq_inline_constant_cache_entry *ice = ic->entry; + if (ice && vm_ic_hit_p(ice, GET_EP())) { val = ice->value; @@ -6615,7 +6619,14 @@ vm_once_dispatch(rb_execution_context_t *ec, ISEQ iseq, ISE is) VALUE val; is->once.running_thread = th; val = rb_ensure(vm_once_exec, (VALUE)iseq, vm_once_clear, (VALUE)is); + // TODO: confirm that it is shareable + + if (RB_FL_ABLE(val)) { + RB_OBJ_SET_SHAREABLE(val); + } + 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 */ return val; diff --git a/vm_method.c b/vm_method.c index 60c273ff2f..2cd41bd377 100644 --- a/vm_method.c +++ b/vm_method.c @@ -682,7 +682,7 @@ rb_vm_ci_lookup(ID mid, unsigned int flag, unsigned int argc, const struct rb_ca ((struct rb_callinfo_kwarg *)kwarg)->references++; } - struct rb_callinfo *new_ci = IMEMO_NEW(struct rb_callinfo, imemo_callinfo, (VALUE)kwarg); + struct rb_callinfo *new_ci = SHAREABLE_IMEMO_NEW(struct rb_callinfo, imemo_callinfo, (VALUE)kwarg); new_ci->mid = mid; new_ci->flag = flag; new_ci->argc = argc; @@ -1008,7 +1008,9 @@ rb_method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *de if (cfp && (line = rb_vm_get_sourceline(cfp))) { VALUE location = rb_ary_new3(2, rb_iseq_path(cfp->iseq), INT2FIX(line)); - RB_OBJ_WRITE(me, &def->body.attr.location, rb_ary_freeze(location)); + rb_ary_freeze(location); + RB_OBJ_SET_SHAREABLE(location); + RB_OBJ_WRITE(me, &def->body.attr.location, location); } else { VM_ASSERT(def->body.attr.location == 0); @@ -1099,7 +1101,7 @@ rb_method_entry_alloc(ID called_id, VALUE owner, VALUE defined_class, rb_method_ // not negative cache VM_ASSERT_TYPE2(defined_class, T_CLASS, T_ICLASS); } - rb_method_entry_t *me = IMEMO_NEW(rb_method_entry_t, imemo_ment, defined_class); + rb_method_entry_t *me = SHAREABLE_IMEMO_NEW(rb_method_entry_t, imemo_ment, defined_class); *((rb_method_definition_t **)&me->def) = def; me->called_id = called_id; me->owner = owner; |
