summaryrefslogtreecommitdiff
path: root/variable.c
diff options
context:
space:
mode:
Diffstat (limited to 'variable.c')
-rw-r--r--variable.c51
1 files changed, 20 insertions, 31 deletions
diff --git a/variable.c b/variable.c
index 67dc2d3397..6bd9f69d06 100644
--- a/variable.c
+++ b/variable.c
@@ -1818,51 +1818,40 @@ general_field_set(VALUE obj, shape_id_t target_shape_id, VALUE val, void *data,
struct gen_fields_lookup_ensure_size {
VALUE obj;
ID id;
- struct gen_fields_tbl *fields_tbl;
shape_id_t shape_id;
bool resize;
};
-static int
-generic_fields_lookup_ensure_size(st_data_t *k, st_data_t *v, st_data_t u, int existing)
-{
- ASSERT_vm_locking();
-
- struct gen_fields_lookup_ensure_size *fields_lookup = (struct gen_fields_lookup_ensure_size *)u;
- struct gen_fields_tbl *fields_tbl = existing ? (struct gen_fields_tbl *)*v : NULL;
-
- if (!existing || fields_lookup->resize) {
- if (existing) {
- RUBY_ASSERT(RSHAPE_TYPE_P(fields_lookup->shape_id, SHAPE_IVAR) || RSHAPE_TYPE_P(fields_lookup->shape_id, SHAPE_OBJ_ID));
- RUBY_ASSERT(RSHAPE_CAPACITY(RSHAPE_PARENT(fields_lookup->shape_id)) < RSHAPE_CAPACITY(fields_lookup->shape_id));
- }
-
- fields_tbl = gen_fields_tbl_resize(fields_tbl, RSHAPE_CAPACITY(fields_lookup->shape_id));
- *v = (st_data_t)fields_tbl;
- }
-
- fields_lookup->fields_tbl = fields_tbl;
- if (fields_lookup->shape_id) {
- rb_obj_set_shape_id(fields_lookup->obj, fields_lookup->shape_id);
- }
-
- RUBY_ASSERT(rb_obj_exivar_p((VALUE)*k));
-
- return ST_CONTINUE;
-}
-
static VALUE *
generic_ivar_set_shape_fields(VALUE obj, void *data)
{
RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj));
struct gen_fields_lookup_ensure_size *fields_lookup = data;
+ struct gen_fields_tbl *fields_tbl = NULL;
+ // We can't use st_update, since when resizing the fields table GC can
+ // happen, which will modify the st_table and may rebuild it
RB_VM_LOCKING() {
- st_update(generic_fields_tbl(obj, fields_lookup->id, false), (st_data_t)obj, generic_fields_lookup_ensure_size, (st_data_t)fields_lookup);
+ st_table *tbl = generic_fields_tbl(obj, fields_lookup->id, false);
+ int existing = st_lookup(tbl, (st_data_t)obj, (st_data_t *)&fields_tbl);
+
+ if (!existing || fields_lookup->resize) {
+ if (existing) {
+ RUBY_ASSERT(RSHAPE_TYPE_P(fields_lookup->shape_id, SHAPE_IVAR) || RSHAPE_TYPE_P(fields_lookup->shape_id, SHAPE_OBJ_ID));
+ RUBY_ASSERT(RSHAPE_CAPACITY(RSHAPE_PARENT(fields_lookup->shape_id)) < RSHAPE_CAPACITY(fields_lookup->shape_id));
+ }
+
+ fields_tbl = gen_fields_tbl_resize(fields_tbl, RSHAPE_CAPACITY(fields_lookup->shape_id));
+ st_insert(tbl, (st_data_t)obj, (st_data_t)fields_tbl);
+ }
+
+ if (fields_lookup->shape_id) {
+ rb_obj_set_shape_id(fields_lookup->obj, fields_lookup->shape_id);
+ }
}
- return fields_lookup->fields_tbl->as.shape.fields;
+ return fields_tbl->as.shape.fields;
}
static void