diff --git i/eval.c w/eval.c index f0a06fb..fbe17d0 100644 --- i/eval.c +++ w/eval.c @@ -52,7 +52,6 @@ ruby_setup(void) Init_BareVM(); Init_heap(); Init_vm_objects(); - Init_frozen_strings(); PUSH_TAG(); if ((state = EXEC_TAG()) == 0) { diff --git i/string.c w/string.c index e7a971b..758854b 100644 --- i/string.c +++ w/string.c @@ -174,74 +174,6 @@ mustnot_broken(VALUE str) } } -static int fstring_cmp(VALUE a, VALUE b); - -/* in case we restart MVM development, this needs to be per-VM */ -static st_table* frozen_strings; - -static inline st_table* -rb_vm_fstring_table(void) -{ - return frozen_strings; -} - -static const struct st_hash_type fstring_hash_type = { - fstring_cmp, - rb_str_hash, -}; - -static int -fstr_update_callback(st_data_t *key, st_data_t *value, st_data_t arg, int existing) -{ - VALUE *fstr = (VALUE *)arg; - VALUE str = (VALUE)*key; - - if (existing) { - /* because of lazy sweep, str may be unmarked already and swept - * at next time */ - - if (rb_objspace_garbage_object_p(str)) { - *fstr = Qundef; - return ST_DELETE; - } - - *fstr = str; - return ST_STOP; - } - else { - if (STR_SHARED_P(str)) { /* str should not be shared */ - str = rb_enc_str_new(RSTRING_PTR(str), RSTRING_LEN(str), STR_ENC_GET(str)); - OBJ_FREEZE(str); - } - else { - str = rb_str_new_frozen(str); - } - RBASIC(str)->flags |= RSTRING_FSTR; - - *key = *value = *fstr = str; - return ST_CONTINUE; - } -} - -VALUE -rb_fstring(VALUE str) -{ - VALUE ret; - - Check_Type(str, T_STRING); - - if (FL_TEST(str, RSTRING_FSTR)) - return str; - - do { - ret = str; - st_update(rb_vm_fstring_table(), (st_data_t)str, - fstr_update_callback, (st_data_t)&ret); - } while (ret == Qundef); - - return ret; -} - static VALUE setup_fake_str(struct RString *fake_str, const char *name, long len, int encidx) { @@ -263,30 +195,6 @@ rb_setup_fake_str(struct RString *fake_str, const char *name, long len, rb_encod return setup_fake_str(fake_str, name, len, rb_enc_to_index(enc)); } -VALUE -rb_fstring_new(const char *ptr, long len) -{ - struct RString fake_str; - return rb_fstring(setup_fake_str(&fake_str, ptr, len, ENCINDEX_US_ASCII)); -} - -static int -fstring_set_class_i(st_data_t key, st_data_t val, st_data_t arg) -{ - RBASIC_SET_CLASS((VALUE)key, (VALUE)arg); - return ST_CONTINUE; -} - -static int -fstring_cmp(VALUE a, VALUE b) -{ - int cmp = rb_str_hash_cmp(a, b); - if (cmp != 0) { - return cmp; - } - return ENCODING_GET(b) - ENCODING_GET(a); -} - static inline int single_byte_optimizable(VALUE str) { @@ -956,8 +864,8 @@ void rb_str_free(VALUE str) { if (FL_TEST(str, RSTRING_FSTR)) { - st_data_t fstr = (st_data_t)str; - st_delete(rb_vm_fstring_table(), &fstr, NULL); + void rb_fstring_remove(VALUE str); + rb_fstring_remove(str); } if (!STR_EMBED_P(str) && !FL_TEST(str, STR_SHARED)) { @@ -8955,13 +8863,5 @@ Init_String(void) rb_define_method(rb_cSymbol, "encoding", sym_encoding, 0); - assert(rb_vm_fstring_table()); - st_foreach(rb_vm_fstring_table(), fstring_set_class_i, rb_cString); -} - -void -Init_frozen_strings(void) -{ - assert(!frozen_strings); - frozen_strings = st_init_table(&fstring_hash_type); + Init_frozen_strings(); } diff --git i/vm.c w/vm.c index cd80729..78d640e 100644 --- i/vm.c +++ w/vm.c @@ -2787,6 +2787,108 @@ Init_BareVM(void) ruby_thread_init_stack(th); } +static inline st_table * +rb_vm_fstring_table(void) +{ + return GET_VM()->frozen_strings; +} + +static int +fstring_cmp(VALUE a, VALUE b) +{ + int cmp = rb_str_hash_cmp(a, b); + if (cmp != 0) { + return cmp; + } + return ENCODING_GET(b) - ENCODING_GET(a); +} + +static const struct st_hash_type fstring_hash_type = { + fstring_cmp, + rb_str_hash, +}; + +static int +fstr_update_callback(st_data_t *key, st_data_t *value, st_data_t arg, int existing) +{ + VALUE *fstr = (VALUE *)arg; + VALUE str = (VALUE)*key; + + if (existing) { + /* because of lazy sweep, str may be unmarked already and swept + * at next time */ + + if (rb_objspace_garbage_object_p(str)) { + *fstr = Qundef; + return ST_DELETE; + } + + *fstr = str; + return ST_STOP; + } + else { + if (STR_SHARED_P(str)) { /* str should not be shared */ + str = rb_enc_str_new(RSTRING_PTR(str), RSTRING_LEN(str), rb_enc_get(str)); + OBJ_FREEZE(str); + } + else { + str = rb_str_new_frozen(str); + } + RBASIC(str)->flags |= RSTRING_FSTR; + + *key = *value = *fstr = str; + return ST_CONTINUE; + } +} + +VALUE +rb_fstring(VALUE str) +{ + VALUE ret; + st_table *frozen_strings = rb_vm_fstring_table(); + + Check_Type(str, T_STRING); + + if (FL_TEST(str, RSTRING_FSTR)) + return str; + + do { + ret = str; + st_update(frozen_strings, (st_data_t)str, fstr_update_callback, (st_data_t)&ret); + } while (ret == Qundef); + + return ret; +} + +VALUE +rb_fstring_new(const char *ptr, long len) +{ + struct RString fake_str; + return rb_fstring(rb_setup_fake_str(&fake_str, ptr, len, rb_usascii_encoding())); +} + +void +rb_fstring_remove(VALUE str) +{ + st_data_t fstr = (st_data_t)str; + st_delete(rb_vm_fstring_table(), &fstr, NULL); +} + +static int +fstring_set_class_i(st_data_t key, st_data_t val, st_data_t arg) +{ + RBASIC_SET_CLASS((VALUE)key, (VALUE)arg); + return ST_CONTINUE; +} + +void +Init_frozen_strings(void) +{ + st_table *frozen_strings = rb_vm_fstring_table(); + assert(frozen_strings); + st_foreach(frozen_strings, fstring_set_class_i, rb_cString); +} + void Init_vm_objects(void) { @@ -2796,6 +2898,9 @@ Init_vm_objects(void) /* initialize mark object array, hash */ vm->mark_object_ary = rb_ary_tmp_new(128); + + assert(!vm->frozen_strings); + vm->frozen_strings = st_init_table(&fstring_hash_type); } /* top self */