@@ -1679,12 +1679,12 @@ rb_obj_init_too_complex(VALUE obj, st_table *table)
16791679 obj_transition_too_complex (obj , table );
16801680}
16811681
1682+ void rb_obj_copy_fields_to_hash_table (VALUE obj , st_table * table );
1683+
16821684// Copy all object fields, including ivars and internal object_id, etc
16831685shape_id_t
16841686rb_evict_fields_to_hash (VALUE obj )
16851687{
1686- void rb_obj_copy_fields_to_hash_table (VALUE obj , st_table * table );
1687-
16881688 RUBY_ASSERT (!rb_shape_obj_too_complex_p (obj ));
16891689
16901690 st_table * table = st_init_numtable_with_size (RSHAPE_LEN (RBASIC_SHAPE_ID (obj )));
@@ -1900,18 +1900,99 @@ generic_ivar_set_too_complex_table(VALUE obj, void *data)
19001900static void
19011901generic_ivar_set (VALUE obj , ID id , VALUE val )
19021902{
1903- struct gen_fields_lookup_ensure_size fields_lookup = {
1904- .obj = obj ,
1905- .id = id ,
1906- .resize = false,
1907- };
1903+ const VALUE original_fields_obj = 0 ;
1904+ st_table * generic_tbl ;
1905+ bool existing = true;
1906+
1907+ RB_VM_LOCKING () {
1908+ generic_tbl = generic_fields_tbl (obj , id , false);
1909+ st_lookup (generic_tbl , obj , (st_data_t * )& original_fields_obj );
1910+ }
1911+
1912+ VALUE fields_obj = original_fields_obj ;
1913+ if (!fields_obj ) {
1914+ fields_obj = rb_imemo_fields_new (rb_obj_class (obj ), 1 );
1915+ RUBY_ASSERT (RBASIC_SHAPE_ID (obj ) == ROOT_SHAPE_ID );
1916+ }
1917+
1918+ shape_id_t current_shape_id = RBASIC_SHAPE_ID (fields_obj );
1919+ shape_id_t next_shape_id = current_shape_id ;
1920+
1921+ if (UNLIKELY (rb_shape_too_complex_p (current_shape_id ))) {
1922+ goto too_complex ;
1923+ }
1924+
1925+ attr_index_t index ;
1926+ if (!rb_shape_get_iv_index (current_shape_id , id , & index )) {
1927+ existing = false;
1928+
1929+ index = RSHAPE_LEN (current_shape_id );
1930+ if (index >= SHAPE_MAX_FIELDS ) {
1931+ rb_raise (rb_eArgError , "too many instance variables" );
1932+ }
1933+
1934+ next_shape_id = rb_shape_transition_add_ivar (fields_obj , id );
1935+ if (UNLIKELY (rb_shape_too_complex_p (next_shape_id ))) {
1936+ attr_index_t current_len = RSHAPE_LEN (current_shape_id );
1937+ fields_obj = rb_imemo_fields_new_complex (rb_obj_class (obj ), current_len + 1 );
1938+ if (current_len ) {
1939+ rb_obj_copy_fields_to_hash_table (original_fields_obj , rb_imemo_fields_complex_tbl (fields_obj ));
1940+ RBASIC_SET_SHAPE_ID (fields_obj , next_shape_id );
1941+ }
1942+ goto too_complex ;
1943+ }
1944+
1945+ attr_index_t next_capacity = RSHAPE_CAPACITY (next_shape_id );
1946+ attr_index_t current_capacity = RSHAPE_CAPACITY (current_shape_id );
1947+
1948+ if (next_capacity != current_capacity ) {
1949+ RUBY_ASSERT (next_capacity > current_capacity );
1950+
1951+ fields_obj = rb_imemo_fields_new (rb_obj_class (obj ), next_capacity );
1952+ if (original_fields_obj ) {
1953+ MEMCPY (rb_imemo_fields_ptr (fields_obj ), rb_imemo_fields_ptr (original_fields_obj ), VALUE , RSHAPE_LEN (current_shape_id ));
1954+ }
1955+ }
1956+
1957+ RUBY_ASSERT (RSHAPE (next_shape_id )-> type == SHAPE_IVAR );
1958+ RUBY_ASSERT (index == (RSHAPE_LEN (next_shape_id ) - 1 ));
1959+ }
1960+
1961+ VALUE * fields = rb_imemo_fields_ptr (fields_obj );
1962+ RB_OBJ_WRITE (fields_obj , & fields [index ], val );
19081963
1909- general_ivar_set (obj , id , val , & fields_lookup ,
1910- generic_ivar_set_shape_fields ,
1911- generic_ivar_set_shape_resize_fields ,
1912- generic_ivar_set_set_shape_id ,
1913- generic_ivar_set_transition_too_complex ,
1914- generic_ivar_set_too_complex_table );
1964+ if (!existing ) {
1965+ RBASIC_SET_SHAPE_ID (fields_obj , next_shape_id );
1966+ }
1967+
1968+ if (fields_obj != original_fields_obj ) {
1969+ RB_VM_LOCKING () {
1970+ st_insert (generic_tbl , obj , fields_obj );
1971+ }
1972+ if (!existing ) {
1973+ RBASIC_SET_SHAPE_ID (obj , next_shape_id );
1974+ }
1975+ }
1976+
1977+ return ;
1978+
1979+ too_complex :
1980+ {
1981+ st_table * table = rb_imemo_fields_complex_tbl (fields_obj );
1982+ existing = st_insert (table , (st_data_t )id , (st_data_t )val );
1983+ RB_OBJ_WRITTEN (fields_obj , Qundef , val );
1984+
1985+ if (fields_obj != original_fields_obj ) {
1986+ RB_VM_LOCKING () {
1987+ st_insert (generic_tbl , obj , fields_obj );
1988+ }
1989+ if (!existing ) {
1990+ RBASIC_SET_SHAPE_ID (obj , next_shape_id );
1991+ }
1992+ }
1993+ }
1994+
1995+ return ;
19151996}
19161997
19171998static void
0 commit comments