diff options
author | Aaron Patterson <[email protected]> | 2022-12-05 16:48:47 -0800 |
---|---|---|
committer | Aaron Patterson <[email protected]> | 2022-12-07 09:57:11 -0800 |
commit | edc7af48acd12666a2945f30901d16b62a39f474 () | |
tree | 7497e93afe9d84f970228cb515a5dc9092db1fbb /shape.c | |
parent | f725bf358a38b2d5dccb016a962f560baaee55c2 (diff) |
Stop transitioning to UNDEF when undefining an instance variable
Cases like this: ```ruby obj = Object.new loop do obj.instance_variable_set(:@foo, 1) obj.remove_instance_variable(:@foo) end ``` can cause us to use many more shapes than we want (and even run out). This commit changes the code such that when an instance variable is removed, we'll walk up the shape tree, find the shape, then rebuild any child nodes that happened to be below the "targetted for removal" IV. This also requires moving any instance variables so that indexes derived from the shape tree will work correctly. Co-Authored-By: Jemma Issroff <[email protected]> Co-authored-by: John Hawthorn <[email protected]>
Notes: Merged: https://.com/ruby/ruby/pull/6866
-rw-r--r-- | shape.c | 104 |
1 files changed, 94 insertions, 10 deletions
@@ -5,6 +5,7 @@ #include "internal/class.h" #include "internal/symbol.h" #include "internal/variable.h" #include <stdbool.h> #ifndef SHAPE_DEBUG @@ -96,6 +97,19 @@ rb_shape_get_shape_id(VALUE obj) #endif } rb_shape_t* rb_shape_get_shape(VALUE obj) { @@ -131,7 +145,6 @@ get_next_shape_internal(rb_shape_t * shape, ID id, enum shape_type shape_type) new_shape->next_iv_index = shape->next_iv_index + 1; break; case SHAPE_CAPACITY_CHANGE: - case SHAPE_IVAR_UNDEF: case SHAPE_FROZEN: case SHAPE_T_OBJECT: new_shape->next_iv_index = shape->next_iv_index; @@ -157,12 +170,88 @@ rb_shape_frozen_shape_p(rb_shape_t* shape) return SHAPE_FROZEN == (enum shape_type)shape->type; } -void -rb_shape_transition_shape_remove_ivar(VALUE obj, ID id, rb_shape_t *shape) { - rb_shape_t * next_shape = get_next_shape_internal(shape, id, SHAPE_IVAR_UNDEF); - rb_shape_set_shape(obj, next_shape); } void @@ -238,7 +327,6 @@ rb_shape_get_iv_index(rb_shape_t * shape, ID id, attr_index_t *value) *value = shape->next_iv_index - 1; return true; case SHAPE_CAPACITY_CHANGE: - case SHAPE_IVAR_UNDEF: case SHAPE_ROOT: case SHAPE_INITIAL_CAPACITY: case SHAPE_T_OBJECT: @@ -329,9 +417,6 @@ rb_shape_rebuild_shape(rb_shape_t * initial_shape, rb_shape_t * dest_shape) midway_shape = rb_shape_get_next_iv_shape(midway_shape, dest_shape->edge_name); break; - case SHAPE_IVAR_UNDEF: - midway_shape = get_next_shape_internal(midway_shape, dest_shape->edge_name, SHAPE_IVAR_UNDEF); - break; case SHAPE_ROOT: case SHAPE_FROZEN: case SHAPE_CAPACITY_CHANGE: @@ -638,7 +723,6 @@ Init_shape(void) rb_define_const(rb_cShape, "SHAPE_ROOT", INT2NUM(SHAPE_ROOT)); rb_define_const(rb_cShape, "SHAPE_IVAR", INT2NUM(SHAPE_IVAR)); rb_define_const(rb_cShape, "SHAPE_T_OBJECT", INT2NUM(SHAPE_T_OBJECT)); - rb_define_const(rb_cShape, "SHAPE_IVAR_UNDEF", INT2NUM(SHAPE_IVAR_UNDEF)); rb_define_const(rb_cShape, "SHAPE_FROZEN", INT2NUM(SHAPE_FROZEN)); rb_define_const(rb_cShape, "SHAPE_ID_NUM_BITS", INT2NUM(SHAPE_ID_NUM_BITS)); rb_define_const(rb_cShape, "SHAPE_FLAG_SHIFT", INT2NUM(SHAPE_FLAG_SHIFT)); |