summaryrefslogtreecommitdiff
path: root/vm_insnhelper.c
diff options
context:
space:
mode:
authorJemma Issroff <jemmaissroff@gmail.com>2022-11-08 15:35:31 -0500
committerPeter Zhu <peter@peterzhu.ca>2022-11-10 10:11:34 -0500
commit5246f4027ec574e77809845e1b1f7822cc2a5cef (patch)
treea29c972df6a589c7ab8c2541ea2eea1f7caf5f70 /vm_insnhelper.c
parent9986697b621e5345177a1c395489dcc9fab8602b (diff)
Transition shape when object's capacity changes
This commit adds a `capacity` field to shapes, and adds shape transitions whenever an object's capacity changes. Objects which are allocated out of a bigger size pool will also make a transition from the root shape to the shape with the correct capacity for their size pool when they are allocated. This commit will allow us to remove numiv from objects completely, and will also mean we can guarantee that if two objects share shapes, their IVs are in the same positions (an embedded and extended object cannot share shapes). This will enable us to implement ivar sets in YJIT using object shapes. Co-Authored-By: Aaron Patterson <tenderlove@ruby-lang.org>
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/6699
Diffstat (limited to 'vm_insnhelper.c')
-rw-r--r--vm_insnhelper.c52
1 files changed, 22 insertions, 30 deletions
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index cff4b9138a..7b24392932 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -50,11 +50,6 @@ MJIT_STATIC VALUE
ruby_vm_special_exception_copy(VALUE exc)
{
VALUE e = rb_obj_alloc(rb_class_real(RBASIC_CLASS(exc)));
- rb_shape_t * shape = rb_shape_get_shape(exc);
- if (rb_shape_frozen_shape_p(shape)) {
- shape = rb_shape_get_shape_by_id(shape->parent_id);
- }
- rb_shape_set_shape(e, shape);
rb_obj_copy_ivar(e, exc);
return e;
}
@@ -1310,37 +1305,33 @@ vm_setivar_slowpath(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic,
rb_shape_t* shape = rb_shape_get_shape(obj);
shape_id_t next_shape_id = ROBJECT_SHAPE_ID(obj);
- rb_shape_t* next_shape = rb_shape_get_next(shape, obj, id);
+ if (!rb_shape_get_iv_index(shape, id, &index)) {
+ if (UNLIKELY(shape->next_iv_index >= num_iv)) {
+ RUBY_ASSERT(shape->next_iv_index == num_iv);
- if (shape != next_shape) {
- RUBY_ASSERT(next_shape->parent_id == rb_shape_id(shape));
- next_shape_id = rb_shape_id(next_shape);
- }
+ shape = rb_grow_iv_list(obj);
+ RUBY_ASSERT(shape->type == SHAPE_CAPACITY_CHANGE);
+ }
+
+ index = shape->next_iv_index;
- if (rb_shape_get_iv_index(next_shape, id, &index)) { // based off the hash stored in the transition tree
if (index >= MAX_IVARS) {
rb_raise(rb_eArgError, "too many instance variables");
}
- populate_cache(index, next_shape_id, id, iseq, ic, cc, is_attr);
- }
- else {
- rb_bug("Didn't find instance variable %s\n", rb_id2name(id));
- }
-
- // Ensure the IV buffer is wide enough to store the IV
- if (UNLIKELY(index >= num_iv)) {
- RUBY_ASSERT(index == num_iv);
- rb_init_iv_list(obj);
- }
+ rb_shape_t * next_shape = rb_shape_get_next(shape, obj, id);
+ RUBY_ASSERT(next_shape->type == SHAPE_IVAR);
+ RUBY_ASSERT(index == (next_shape->next_iv_index - 1));
+ next_shape_id = rb_shape_id(next_shape);
- if (shape != next_shape) {
rb_shape_set_shape(obj, next_shape);
}
+
+ populate_cache(index, next_shape_id, id, iseq, ic, cc, is_attr);
+
VALUE *ptr = ROBJECT_IVPTR(obj);
RB_OBJ_WRITE(obj, &ptr[index], val);
RB_DEBUG_COUNTER_INC(ivar_set_ic_miss_iv_hit);
-
return val;
}
case T_CLASS:
@@ -1450,17 +1441,18 @@ vm_setivar(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_index_t i
else if (dest_shape_id != INVALID_SHAPE_ID) {
rb_shape_t *dest_shape = rb_shape_get_shape_by_id(dest_shape_id);
shape_id_t source_shape_id = dest_shape->parent_id;
- if (shape_id == source_shape_id && dest_shape->edge_name == id && dest_shape->type == SHAPE_IVAR) {
+
+ RUBY_ASSERT(dest_shape->type == SHAPE_IVAR || dest_shape->type == SHAPE_IVAR_UNDEF);
+
+ if (shape_id == source_shape_id && dest_shape->edge_name == id) {
RUBY_ASSERT(dest_shape_id != INVALID_SHAPE_ID && shape_id != INVALID_SHAPE_ID);
- if (UNLIKELY(index >= ROBJECT_NUMIV(obj))) {
- rb_init_iv_list(obj);
- }
+ RUBY_ASSERT(ROBJECT_IV_CAPACITY(obj) == ROBJECT_NUMIV(obj));
ROBJECT_SET_SHAPE_ID(obj, dest_shape_id);
- RUBY_ASSERT(rb_shape_get_next(rb_shape_get_shape_by_id(source_shape_id), obj, id) == dest_shape);
+ RUBY_ASSERT(rb_shape_get_next_iv_shape(rb_shape_get_shape_by_id(source_shape_id), id) == dest_shape);
+ RUBY_ASSERT(ROBJECT_IV_CAPACITY(obj) == ROBJECT_NUMIV(obj));
RUBY_ASSERT(index < ROBJECT_NUMIV(obj));
-
}
else {
break;