Skip to content
Merged
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
4 changes: 2 additions & 2 deletions debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -620,8 +620,8 @@ ruby_debug_log(const char *file, int line, const char *func_name, const char *fm
rb_vm_t *vm = GET_VM();

if (r && len < MAX_DEBUG_LOG_MESSAGE_LEN) {
r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\tr:#%d/%u (%u)",
cr ? (int)rb_ractor_id(cr) : -1, vm->ractor.cnt, vm->ractor.sched.running_cnt);
r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\tr:#%d/%u",
cr ? (int)rb_ractor_id(cr) : -1, vm->ractor.cnt);

if (r < 0) rb_bug("ruby_debug_log returns %d", r);
len += r;
Expand Down
44 changes: 26 additions & 18 deletions hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -1501,6 +1501,20 @@ hash_alloc_capa(VALUE klass, VALUE flags, VALUE ifnone, size_t size, bool frozen
{
VALUE hash = rb_newobj_of(klass, T_HASH | flags, hash_slot_size(size, frozen));
rb_hash_set_ifnone(hash, ifnone);

#ifdef RUBY_DEBUG
if (hash_slot_size(size, frozen) >= sizeof(struct RHash) + sizeof(st_table)) {
RHASH_ST_TABLE(hash)->num_entries = 0;
RHASH_ST_TABLE(hash)->entries = NULL;
}
#endif

return hash;
}

static VALUE
hash_init_capa(VALUE hash, size_t size)
{
if (size > RHASH_AR_TABLE_MAX_SIZE) {
hash_st_table_init(hash, &objhash, size);
}
Expand All @@ -1510,7 +1524,7 @@ hash_alloc_capa(VALUE klass, VALUE flags, VALUE ifnone, size_t size, bool frozen
static VALUE
hash_hidden_new(size_t size)
{
return hash_alloc_capa(0, 0, Qnil, size, false);
return hash_init_capa(hash_alloc_capa(0, 0, Qnil, size, false), size);
}

VALUE
Expand Down Expand Up @@ -1554,7 +1568,7 @@ copy_compare_by_id(VALUE hash, VALUE basis)
VALUE
rb_hash_new_capa(long capa)
{
return hash_alloc_capa(rb_cHash, 0, Qnil, capa, false);
return hash_init_capa(hash_alloc_capa(rb_cHash, 0, Qnil, capa, false), capa);
}

VALUE
Expand All @@ -1566,12 +1580,14 @@ rb_hash_new(void)
VALUE
rb_hash_alloc_fixed_size(VALUE klass, st_index_t size)
{
return hash_alloc_capa(klass, 0, Qnil, size, true);
return hash_init_capa(hash_alloc_capa(klass, 0, Qnil, size, true), size);
}

static VALUE
hash_copy(VALUE ret, VALUE hash)
{
RUBY_ASSERT(RHASH_SIZE(ret) == 0);

if (rb_hash_compare_by_id_p(hash)) {
rb_gc_register_pinning_obj(ret);
}
Expand All @@ -1582,6 +1598,12 @@ hash_copy(VALUE ret, VALUE hash)
}
else {
st_table *tab = RHASH_ST_TABLE(ret);

// If `hash` is an ar_table it can't be `compare_by_identity?`.
RUBY_ASSERT(!rb_hash_compare_by_id_p(hash));
RUBY_ASSERT(RHASH_ST_TABLE(ret)->entries == NULL);
st_init_existing_table_with_size(RHASH_ST_TABLE(ret), &objhash, RHASH_SIZE(hash));

int bound = RHASH_AR_TABLE_BOUND(hash);
for (int i = 0; i < bound; i++) {
if (ar_cleared_entry(hash, i)) continue;
Expand All @@ -1594,11 +1616,8 @@ hash_copy(VALUE ret, VALUE hash)
}
}
else {
HASH_ASSERT(sizeof(st_table) <= sizeof(ar_table));

RHASH_SET_ST_FLAG(ret);
st_replace(RHASH_ST_TABLE(ret), RHASH_ST_TABLE(hash));

rb_gc_writebarrier_remember(ret);
}
return ret;
Expand All @@ -1611,9 +1630,6 @@ hash_dup_with_compare_by_id(VALUE hash)
if (RHASH_ST_TABLE_P(hash)) {
RHASH_SET_ST_FLAG(dup);
}
else {
RHASH_UNSET_ST_FLAG(dup);
}

return hash_copy(dup, hash);
}
Expand All @@ -1639,8 +1655,7 @@ rb_hash_dup(VALUE hash)
VALUE
rb_hash_resurrect(VALUE hash)
{
VALUE ret = hash_dup(hash, rb_cHash, 0);
return ret;
return hash_dup(hash, rb_cHash, 0);
}

#if USE_ZJIT
Expand Down Expand Up @@ -3082,18 +3097,11 @@ rb_hash_replace(VALUE hash, VALUE hash2)

if (RHASH_AR_TABLE_P(hash)) {
hash_ar_free_and_clear_table(hash);
if (RHASH_SIZE(hash2) > RHASH_AR_TABLE_MAX_SIZE) {
RHASH_SET_ST_FLAG(hash);
}
}
else {
hash_st_free_and_clear_table(hash);
}

if (RHASH_ST_TABLE_P(hash)) {
st_init_existing_table_with_size(RHASH_ST_TABLE(hash), &objhash, RHASH_SIZE(hash2));
}

hash_copy(hash, hash2);

return hash;
Expand Down
3 changes: 3 additions & 0 deletions imemo.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,9 @@ rb_imemo_fields_clone(VALUE fields_obj)
// to mark an uninitialized table.
clone = imemo_fields_new(owner, ROOT_SHAPE_ID, sizeof(struct rb_fields), false /* TODO: check */);
st_table *dest_table = rb_imemo_fields_complex_tbl(clone);
#ifdef RUBY_DEBUG
dest_table->entries = NULL;
#endif
st_replace(dest_table, src_table);
st_foreach(dest_table, imemo_fields_complex_wb_i, (st_data_t)clone);
RBASIC_SET_FULL_SHAPE_ID(clone, shape_id);
Expand Down
9 changes: 8 additions & 1 deletion ractor.c
Original file line number Diff line number Diff line change
Expand Up @@ -399,13 +399,20 @@ free_targeted_hooks(st_table *hooks_tbl)
st_foreach(hooks_tbl, free_targeted_hook_lists, 0);
}

#ifdef RUBY_THREAD_PTHREAD_H
void rb_thread_sched_destroy(struct rb_thread_sched *);
#endif

static void
ractor_free(void *ptr)
{
rb_ractor_t *r = (rb_ractor_t *)ptr;
RUBY_DEBUG_LOG("free r:%d", rb_ractor_id(r));

free_targeted_hooks(&r->pub.targeted_hooks);
#ifdef RUBY_THREAD_PTHREAD_H
rb_thread_sched_destroy(&r->threads.sched);
#endif
rb_native_mutex_destroy(&r->sync.lock);
#ifdef RUBY_THREAD_WIN32_H
rb_native_cond_destroy(&r->sync.wakeup_cond);
Expand Down Expand Up @@ -1196,7 +1203,7 @@ rb_ractor_terminate_all(void)
rb_del_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
rb_vm_cond_timedwait(vm, &vm->ractor.sync.terminate_cond, 1000 /* ms */);
#ifdef RUBY_THREAD_PTHREAD_H
while (vm->ractor.sched.barrier_waiting) {
while (vm->ractor.sched.barrier_is_waiting) {
// A barrier is waiting. Threads relinquish the VM lock before joining the barrier and
// since we just acquired the VM lock back, we're blocking other threads from joining it.
// We loop until the barrier is over. We can't join this barrier because our thread isn't added to
Expand Down
16 changes: 12 additions & 4 deletions st.c
Original file line number Diff line number Diff line change
Expand Up @@ -1352,9 +1352,8 @@ st_insert2(st_table *tab, st_data_t key, st_data_t value,
return 1;
}

/* Create a copy of old_tab into new_tab. */
st_table *
st_replace(st_table *new_tab, st_table *old_tab)
static st_table *
st_replace_no_check(st_table *new_tab, st_table *old_tab)
{
*new_tab = *old_tab;
size_t memsize = get_allocated_entries(old_tab) * sizeof(st_table_entry);
Expand All @@ -1370,6 +1369,15 @@ st_replace(st_table *new_tab, st_table *old_tab)
return new_tab;
}


/* Create a copy of old_tab into new_tab. */
st_table *
st_replace(st_table *new_tab, st_table *old_tab)
{
RUBY_ASSERT(new_tab->entries == NULL);
return st_replace_no_check(new_tab, old_tab);
}

/* Create and return a copy of table OLD_TAB. */
st_table *
st_copy(st_table *old_tab)
Expand All @@ -1382,7 +1390,7 @@ st_copy(st_table *old_tab)
return NULL;
#endif

if (st_replace(new_tab, old_tab) == NULL) {
if (st_replace_no_check(new_tab, old_tab) == NULL) {
st_free_table(new_tab);
return NULL;
}
Expand Down
30 changes: 30 additions & 0 deletions test/ruby/test_hash.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2107,6 +2107,36 @@ def test_replace_st_with_ar
assert_equal(h2, h1)
end

def test_replace_ar_with_st
# AR hash
h1 = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7 }
# ST hash
h2 = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9 }
# Replace AR hash with ST hash
h1.replace(h2)
assert_equal(h2, h1)
end

def test_replace_ar_with_ar
# AR hash
h1 = { a: 1, b: 2 }
# AR hash
h2 = { a: 1 }
# Replace AR hash with AR hash
h1.replace(h2)
assert_equal(h2, h1)
end

def test_replace_st_with_st
# ST hash
h1 = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9 }
# ST hash
h2 = { a: 9, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9 }
# Replace ST hash with AR hash
h1.replace(h2)
assert_equal(h2, h1)
end

def test_nil_to_h
h = nil.to_h
assert_equal({}, h)
Expand Down
Loading