Skip to content

Commit 852aa64

Browse files
byrootetiennebarrie
andcommitted
Refactor generic fields to use T_IMEMO/fields objects.
Followup: ruby#13589 This simplify a lot of things, as we no longer need to manually manage the memory, we can use the Read-Copy-Update pattern and avoid numerous race conditions. Co-Authored-By: Étienne Barrié <etienne.barrie@gmail.com>
1 parent e3748b9 commit 852aa64

File tree

9 files changed

+283
-400
lines changed

9 files changed

+283
-400
lines changed

gc.c

Lines changed: 32 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -2015,41 +2015,29 @@ object_id_to_ref(void *objspace_ptr, VALUE object_id)
20152015
static inline void
20162016
obj_free_object_id(VALUE obj)
20172017
{
2018-
if (RB_BUILTIN_TYPE(obj) == T_IMEMO) {
2019-
return;
2020-
}
2021-
2022-
#if RUBY_DEBUG
2023-
switch (BUILTIN_TYPE(obj)) {
2024-
case T_CLASS:
2025-
case T_MODULE:
2026-
break;
2027-
default:
2028-
if (rb_shape_obj_has_id(obj)) {
2029-
VALUE id = object_id_get(obj, RBASIC_SHAPE_ID(obj)); // Crash if missing
2030-
if (!(FIXNUM_P(id) || RB_TYPE_P(id, T_BIGNUM))) {
2031-
rb_p(obj);
2032-
rb_bug("Corrupted object_id");
2033-
}
2034-
}
2035-
break;
2036-
}
2037-
#endif
2038-
20392018
VALUE obj_id = 0;
20402019
if (RB_UNLIKELY(id2ref_tbl)) {
20412020
switch (BUILTIN_TYPE(obj)) {
20422021
case T_CLASS:
20432022
case T_MODULE:
20442023
obj_id = RCLASS(obj)->object_id;
20452024
break;
2046-
default: {
2025+
case T_IMEMO:
2026+
if (!IMEMO_TYPE_P(obj, imemo_fields)) {
2027+
return;
2028+
}
2029+
// fallthrough
2030+
case T_OBJECT:
2031+
{
20472032
shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
20482033
if (rb_shape_has_object_id(shape_id)) {
20492034
obj_id = object_id_get(obj, shape_id);
20502035
}
20512036
break;
20522037
}
2038+
default:
2039+
// For generic_fields, the T_IMEMO/fields is responsible for freeing the id.
2040+
return;
20532041
}
20542042

20552043
if (RB_UNLIKELY(obj_id)) {
@@ -2316,10 +2304,6 @@ rb_obj_memsize_of(VALUE obj)
23162304
return 0;
23172305
}
23182306

2319-
if (rb_obj_exivar_p(obj)) {
2320-
size += rb_generic_ivar_memsize(obj);
2321-
}
2322-
23232307
switch (BUILTIN_TYPE(obj)) {
23242308
case T_OBJECT:
23252309
if (rb_shape_obj_too_complex_p(obj)) {
@@ -3936,38 +3920,6 @@ vm_weak_table_foreach_update_weak_value(st_data_t *key, st_data_t *value, st_dat
39363920
return iter_data->update_callback((VALUE *)value, iter_data->data);
39373921
}
39383922

3939-
static void
3940-
free_gen_fields_tbl(VALUE obj, struct gen_fields_tbl *fields_tbl)
3941-
{
3942-
if (UNLIKELY(rb_shape_obj_too_complex_p(obj))) {
3943-
st_free_table(fields_tbl->as.complex.table);
3944-
}
3945-
3946-
xfree(fields_tbl);
3947-
}
3948-
3949-
static int
3950-
vm_weak_table_gen_fields_foreach_too_complex_i(st_data_t _key, st_data_t value, st_data_t data, int error)
3951-
{
3952-
struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data;
3953-
3954-
GC_ASSERT(!iter_data->weak_only);
3955-
3956-
if (SPECIAL_CONST_P((VALUE)value)) return ST_CONTINUE;
3957-
3958-
return iter_data->callback((VALUE)value, iter_data->data);
3959-
}
3960-
3961-
static int
3962-
vm_weak_table_gen_fields_foreach_too_complex_replace_i(st_data_t *_key, st_data_t *value, st_data_t data, int existing)
3963-
{
3964-
struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data;
3965-
3966-
GC_ASSERT(!iter_data->weak_only);
3967-
3968-
return iter_data->update_callback((VALUE *)value, iter_data->data);
3969-
}
3970-
39713923
struct st_table *rb_generic_fields_tbl_get(void);
39723924

39733925
static int
@@ -4004,60 +3956,50 @@ vm_weak_table_gen_fields_foreach(st_data_t key, st_data_t value, st_data_t data)
40043956

40053957
int ret = iter_data->callback((VALUE)key, iter_data->data);
40063958

3959+
VALUE new_value = (VALUE)value;
3960+
VALUE new_key = (VALUE)key;
3961+
40073962
switch (ret) {
40083963
case ST_CONTINUE:
40093964
break;
40103965

40113966
case ST_DELETE:
4012-
free_gen_fields_tbl((VALUE)key, (struct gen_fields_tbl *)value);
40133967
RBASIC_SET_SHAPE_ID((VALUE)key, ROOT_SHAPE_ID);
40143968
return ST_DELETE;
40153969

40163970
case ST_REPLACE: {
4017-
VALUE new_key = (VALUE)key;
40183971
ret = iter_data->update_callback(&new_key, iter_data->data);
4019-
if (key != new_key) ret = ST_DELETE;
4020-
DURING_GC_COULD_MALLOC_REGION_START();
4021-
{
4022-
st_insert(rb_generic_fields_tbl_get(), (st_data_t)new_key, value);
3972+
if (key != new_key) {
3973+
ret = ST_DELETE;
40233974
}
4024-
DURING_GC_COULD_MALLOC_REGION_END();
4025-
key = (st_data_t)new_key;
40263975
break;
40273976
}
40283977

40293978
default:
4030-
return ret;
3979+
rb_bug("vm_weak_table_gen_fields_foreach: return value %d not supported", ret);
40313980
}
40323981

40333982
if (!iter_data->weak_only) {
4034-
struct gen_fields_tbl *fields_tbl = (struct gen_fields_tbl *)value;
3983+
int ivar_ret = iter_data->callback(new_value, iter_data->data);
3984+
switch (ivar_ret) {
3985+
case ST_CONTINUE:
3986+
break;
40353987

4036-
if (rb_shape_obj_too_complex_p((VALUE)key)) {
4037-
st_foreach_with_replace(
4038-
fields_tbl->as.complex.table,
4039-
vm_weak_table_gen_fields_foreach_too_complex_i,
4040-
vm_weak_table_gen_fields_foreach_too_complex_replace_i,
4041-
data
4042-
);
3988+
case ST_REPLACE:
3989+
iter_data->update_callback(&new_value, iter_data->data);
3990+
break;
3991+
3992+
default:
3993+
rb_bug("vm_weak_table_gen_fields_foreach: return value %d not supported", ivar_ret);
40433994
}
4044-
else {
4045-
uint32_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID((VALUE)key));
4046-
for (uint32_t i = 0; i < fields_count; i++) {
4047-
if (SPECIAL_CONST_P(fields_tbl->as.shape.fields[i])) continue;
3995+
}
40483996

4049-
int ivar_ret = iter_data->callback(fields_tbl->as.shape.fields[i], iter_data->data);
4050-
switch (ivar_ret) {
4051-
case ST_CONTINUE:
4052-
break;
4053-
case ST_REPLACE:
4054-
iter_data->update_callback(&fields_tbl->as.shape.fields[i], iter_data->data);
4055-
break;
4056-
default:
4057-
rb_bug("vm_weak_table_gen_fields_foreach: return value %d not supported", ivar_ret);
4058-
}
4059-
}
3997+
if (key != new_key || value != new_value) {
3998+
DURING_GC_COULD_MALLOC_REGION_START();
3999+
{
4000+
st_insert(rb_generic_fields_tbl_get(), (st_data_t)new_key, new_value);
40604001
}
4002+
DURING_GC_COULD_MALLOC_REGION_END();
40614003
}
40624004

40634005
return ret;

imemo.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,23 @@ rb_imemo_fields_new_complex(VALUE klass, size_t capa)
147147
return imemo_fields_new_complex(klass, capa);
148148
}
149149

150+
static int
151+
imemo_fields_trigger_wb_i(st_data_t key, st_data_t value, st_data_t arg)
152+
{
153+
VALUE field_obj = (VALUE)arg;
154+
RB_OBJ_WRITTEN(field_obj, Qundef, (VALUE)value);
155+
return ST_CONTINUE;
156+
}
157+
158+
VALUE
159+
rb_imemo_fields_new_complex_tbl(VALUE klass, st_table *tbl)
160+
{
161+
VALUE fields = imemo_fields_new(klass, sizeof(struct rb_fields));
162+
IMEMO_OBJ_FIELDS(fields)->as.complex.table = tbl;
163+
st_foreach(tbl, imemo_fields_trigger_wb_i, (st_data_t)fields);
164+
return fields;
165+
}
166+
150167
VALUE
151168
rb_imemo_fields_clone(VALUE fields_obj)
152169
{

internal/imemo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ struct rb_fields {
280280

281281
VALUE rb_imemo_fields_new(VALUE klass, size_t capa);
282282
VALUE rb_imemo_fields_new_complex(VALUE klass, size_t capa);
283+
VALUE rb_imemo_fields_new_complex_tbl(VALUE klass, st_table *tbl);
283284
VALUE rb_imemo_fields_clone(VALUE fields_obj);
284285

285286
static inline VALUE *

internal/variable.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
/* variable.c */
1919
void rb_gc_mark_global_tbl(void);
2020
void rb_gc_update_global_tbl(void);
21-
size_t rb_generic_ivar_memsize(VALUE);
2221
VALUE rb_search_class_path(VALUE);
2322
VALUE rb_attr_delete(VALUE, ID);
2423
void rb_autoload_str(VALUE mod, ID id, VALUE file);
@@ -47,8 +46,7 @@ void rb_gvar_namespace_ready(const char *name);
4746
*/
4847
VALUE rb_mod_set_temporary_name(VALUE, VALUE);
4948

50-
struct gen_fields_tbl;
51-
int rb_gen_fields_tbl_get(VALUE obj, ID id, struct gen_fields_tbl **fields_tbl);
49+
int rb_gen_fields_tbl_get(VALUE obj, ID id, VALUE *fields_obj);
5250
void rb_obj_copy_ivs_to_hash_table(VALUE obj, st_table *table);
5351
void rb_obj_init_too_complex(VALUE obj, st_table *table);
5452
void rb_evict_ivars_to_hash(VALUE obj);

ractor.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1657,8 +1657,8 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
16571657
} while (0)
16581658

16591659
if (UNLIKELY(rb_obj_exivar_p(obj))) {
1660-
struct gen_fields_tbl *fields_tbl;
1661-
rb_ivar_generic_fields_tbl_lookup(obj, &fields_tbl);
1660+
VALUE fields_obj;
1661+
rb_ivar_generic_fields_tbl_lookup(obj, &fields_obj);
16621662

16631663
if (UNLIKELY(rb_shape_obj_too_complex_p(obj))) {
16641664
struct obj_traverse_replace_callback_data d = {
@@ -1667,7 +1667,7 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
16671667
.src = obj,
16681668
};
16691669
rb_st_foreach_with_replace(
1670-
fields_tbl->as.complex.table,
1670+
rb_imemo_fields_complex_tbl(fields_obj),
16711671
obj_iv_hash_traverse_replace_foreach_i,
16721672
obj_iv_hash_traverse_replace_i,
16731673
(st_data_t)&d
@@ -1676,8 +1676,9 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
16761676
}
16771677
else {
16781678
uint32_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
1679+
VALUE *fields = rb_imemo_fields_ptr(fields_obj);
16791680
for (uint32_t i = 0; i < fields_count; i++) {
1680-
CHECK_AND_REPLACE(fields_tbl->as.shape.fields[i]);
1681+
CHECK_AND_REPLACE(fields[i]);
16811682
}
16821683
}
16831684
}

test/ruby/test_encoding.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def test_singleton
3333
encodings.each do |e|
3434
assert_raise(TypeError) { e.dup }
3535
assert_raise(TypeError) { e.clone }
36-
assert_equal(e.object_id, Marshal.load(Marshal.dump(e)).object_id)
36+
assert_same(e, Marshal.load(Marshal.dump(e)))
3737
end
3838
end
3939

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy