Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 21 additions & 12 deletions compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -7067,7 +7067,7 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
DECL_ANCHOR(body_seq);
DECL_ANCHOR(cond_seq);
int only_special_literals = 1;
VALUE literals = rb_hash_new();
VALUE literals = rb_hash_new_with_size_and_type(0, 0, &cdhash_type);
int line;
enum node_type type;
const NODE *line_node;
Expand All @@ -7078,8 +7078,6 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
INIT_ANCHOR(body_seq);
INIT_ANCHOR(cond_seq);

RHASH_TBL_RAW(literals)->type = &cdhash_type;

CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));

branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
Expand Down Expand Up @@ -7165,7 +7163,6 @@ 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);
Expand Down Expand Up @@ -12167,9 +12164,8 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
case TS_CDHASH:
{
int i;
VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
VALUE map = rb_hash_new_with_size_and_type(0, RARRAY_LEN(op)/2, &cdhash_type);

RHASH_TBL_RAW(map)->type = &cdhash_type;
op = rb_to_array_type(op);
for (i=0; i<RARRAY_LEN(op); i+=2) {
VALUE key = RARRAY_AREF(op, i);
Expand All @@ -12179,7 +12175,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
RB_OBJ_SET_SHAREABLE(map); // allow mutation while compiling
argv[j] = map;
RB_OBJ_WRITTEN(iseq, Qundef, map);
}
Expand Down Expand Up @@ -13004,6 +13000,20 @@ ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
return offset;
}

static int
cdhash_copy_i(st_data_t key, st_data_t val, st_data_t arg)
{
rb_hash_aset((VALUE)arg, (VALUE)key, (VALUE)val);
return ST_CONTINUE;
}

static VALUE
cdhash_copy(VALUE dest, VALUE src)
{
rb_hash_stlike_foreach(src, cdhash_copy_i, dest);
return dest;
}

static VALUE *
ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecode_offset, ibf_offset_t bytecode_size, unsigned int iseq_size)
{
Expand Down Expand Up @@ -13058,11 +13068,10 @@ ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecod
case TS_CDHASH:
{
VALUE op = ibf_load_small_value(load, &reading_pos);
VALUE v = ibf_load_object(load, op);
v = rb_hash_dup(v); // hash dumped as frozen
RHASH_TBL_RAW(v)->type = &cdhash_type;
rb_hash_rehash(v); // hash function changed
RB_OBJ_SET_SHAREABLE(freeze_hide_obj(v));
VALUE src = ibf_load_object(load, op);
VALUE v = rb_hash_new_with_size_and_type(0, RHASH_SIZE(src), &cdhash_type);
rb_hash_rehash(cdhash_copy(v, src));
RB_OBJ_SET_SHAREABLE(v);

// Overwrite the existing hash in the object list. This
// is to keep the object alive during load time.
Expand Down
8 changes: 8 additions & 0 deletions hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -1490,6 +1490,14 @@ rb_hash_new_with_size(st_index_t size)
return ret;
}

VALUE
rb_hash_new_with_size_and_type(VALUE klass, st_index_t size, const struct st_hash_type *type)
{
VALUE ret = hash_alloc_flags(klass, 0, Qnil, true);
hash_st_table_init(ret, type, size);
return ret;
}

VALUE
rb_hash_new_capa(long capa)
{
Expand Down
1 change: 1 addition & 0 deletions internal/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ int rb_hash_stlike_foreach(VALUE hash, st_foreach_callback_func *func, st_data_t
RUBY_SYMBOL_EXPORT_END

VALUE rb_hash_new_with_size(st_index_t size);
VALUE rb_hash_new_with_size_and_type(VALUE klass, st_index_t size, const struct st_hash_type *type);
VALUE rb_hash_resurrect(VALUE hash);
int rb_hash_stlike_lookup(VALUE hash, st_data_t key, st_data_t *pval);
VALUE rb_hash_keys(VALUE hash);
Expand Down
1 change: 1 addition & 0 deletions internal/variable.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ rb_gvar_setter_t *rb_gvar_setter_function_of(ID);
void rb_gvar_readonly_setter(VALUE v, ID id, VALUE *_);
void rb_gvar_ractor_local(const char *name);
void rb_gvar_box_ready(const char *name);
void rb_gvar_box_dynamic(const char *name);

/**
* Sets the name of a module.
Expand Down
5 changes: 5 additions & 0 deletions re.c
Original file line number Diff line number Diff line change
Expand Up @@ -4900,6 +4900,11 @@ Init_Regexp(void)
rb_gvar_ractor_local("$`");
rb_gvar_ractor_local("$'");
rb_gvar_ractor_local("$+");
rb_gvar_box_dynamic("$~");
rb_gvar_box_ready("$&");
rb_gvar_box_ready("$`");
rb_gvar_box_ready("$'");
rb_gvar_box_ready("$+");

rb_define_virtual_variable("$=", ignorecase_getter, ignorecase_setter);

Expand Down
20 changes: 20 additions & 0 deletions test/ruby/test_box.rb
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,26 @@ def test_global_variables
end
end

def test_match_variables_are_not_cached_in_box
assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
begin;
/(?<a>foo)/ =~ 'bar'
/(?<b>baz)/ =~ 'baz'
assert_equal "baz", b
assert_equal "baz", $~.to_s

/foo/ =~ 'bar'
assert_nil $~
/(?<word>foo)(bar)?/ =~ 'foo'
assert_equal "foo", word
assert_equal "foo", $~.to_s
assert_equal "foo", $&
assert_equal "", $`
assert_equal "", $'
assert_equal "foo", $+
end;
end

def test_load_path_and_loaded_features
setup_box

Expand Down
23 changes: 18 additions & 5 deletions variable.c
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,7 @@ struct rb_global_variable {
rb_gvar_compact_t *compactor;
struct trace_var *trace;
bool box_ready;
bool box_dynamic;
};

struct rb_global_entry {
Expand Down Expand Up @@ -618,6 +619,13 @@ rb_gvar_box_ready(const char *name)
entry->var->box_ready = true;
}

void
rb_gvar_box_dynamic(const char *name)
{
struct rb_global_entry *entry = rb_find_global_entry(rb_intern(name));
entry->var->box_dynamic = true;
}

static void
rb_gvar_undef_compactor(void *var)
{
Expand Down Expand Up @@ -646,6 +654,7 @@ rb_global_entry(ID id)
var->block_trace = 0;
var->trace = 0;
var->box_ready = false;
var->box_dynamic = false;
rb_id_table_insert(rb_global_tbl, id, (VALUE)entry);
}
}
Expand Down Expand Up @@ -1000,9 +1009,13 @@ rb_gvar_set_entry(struct rb_global_entry *entry, VALUE val)
return val;
}

#define USE_BOX_GVAR_TBL(ns,entry) \
(BOX_USER_P(ns) && \
(!entry || !entry->var->box_ready || entry->var->setter != rb_gvar_readonly_setter))
static inline bool
gvar_use_box_tbl(const rb_box_t *box, const struct rb_global_entry *entry)
{
return BOX_USER_P(box) &&
!entry->var->box_dynamic &&
(!entry->var->box_ready || entry->var->setter != rb_gvar_readonly_setter);
}

VALUE
rb_gvar_set(ID id, VALUE val)
Expand All @@ -1015,7 +1028,7 @@ rb_gvar_set(ID id, VALUE val)
RB_VM_LOCKING() {
entry = rb_global_entry(id);

if (USE_BOX_GVAR_TBL(box, entry)) {
if (gvar_use_box_tbl(box, entry)) {
use_box_tbl = true;
rb_hash_aset(box->gvar_tbl, rb_id2sym(entry->id), val);
retval = val;
Expand Down Expand Up @@ -1048,7 +1061,7 @@ rb_gvar_get(ID id)
entry = rb_global_entry(id);
var = entry->var;

if (USE_BOX_GVAR_TBL(box, entry)) {
if (gvar_use_box_tbl(box, entry)) {
use_box_tbl = true;
gvars = box->gvar_tbl;
key = rb_id2sym(entry->id);
Expand Down