mirror of
https://github.com/ruby/ruby.git
synced 2026-01-26 20:19:19 +00:00
use SET_SHAREABLE
to adopt strict shareable rule. * (basically) shareable objects only refer shareable objects * (exception) shareable objects can refere unshareable objects but should not leak reference to unshareable objects to Ruby world
This commit is contained in:
parent
45907b1b00
commit
bc00c4468e
Notes:
git
2025-10-23 04:09:08 +00:00
17
array.c
17
array.c
@ -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);
|
||||
}
|
||||
|
||||
|
||||
2
class.c
2
class.c
@ -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;
|
||||
|
||||
|
||||
99
compile.c
99
compile.c
@ -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;
|
||||
}
|
||||
|
||||
|
||||
4
depend
4
depend
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
18
gc.c
18
gc.c
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
4
hash.c
4
hash.c
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
80
imemo.c
80
imemo.c
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
27
iseq.c
27
iseq.c
@ -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;
|
||||
|
||||
2
iseq.h
2
iseq.h
@ -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));
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
39
ractor.c
39
ractor.c
@ -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;
|
||||
}
|
||||
|
||||
7
re.c
7
re.c
@ -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
|
||||
|
||||
26
string.c
26
string.c
@ -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
|
||||
|
||||
4
symbol.c
4
symbol.c
@ -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;
|
||||
|
||||
16
variable.c
16
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
|
||||
|
||||
34
vm.c
34
vm.c
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user