From 90b70738427567dc065ad75b32fa932b280c304a Mon Sep 17 00:00:00 2001 From: nari Date: Wed, 26 Mar 2014 04:57:47 +0000 Subject: * parse.y: support Symbol GC. [ruby-trunk Feature #9634] See this ticket about Symbol GC. * include/ruby/ruby.h: Declare few functions. * rb_sym2id: almost same as old SYM2ID but support dynamic symbols. * rb_id2sym: almost same as old ID2SYM but support dynamic symbols. * rb_sym2str: almost same as `rb_id2str(SYM2ID(sym))` but not pin down a dynamic symbol. Declare a new struct. * struct RSymbol: represents a dynamic symbol as object in Ruby's heaps. Add few macros. * STATIC_SYM_P: check a static symbol. * DYNAMIC_SYM_P: check a dynamic symbol. * RSYMBOL: cast to RSymbol * gc.c: declare RSymbol. support T_SYMBOL. * internal.h: Declare few functions. * rb_gc_free_dsymbol: free up a dynamic symbol. GC call this function at a sweep phase. * rb_str_dynamic_intern: convert a string to a dynamic symbol. * rb_check_id_without_pindown: not pinning function. * rb_sym2id_without_pindown: ditto. * rb_check_id_cstr_without_pindown: ditto. * string.c (Init_String): String#intern and String#to_sym use rb_str_dynamic_intern. * template/id.h.tmpl: use LSB of ID as a flag for determining a static symbol, so we shift left other ruby_id_types. * string.c: use rb_sym2str instead `rb_id2str(SYM2ID(sym))` to avoid pinning. * load.c: use xx_without_pindown function at creating temporary ID to avoid pinning. * object.c: ditto. * sprintf.c: ditto. * struct.c: ditto. * thread.c: ditto. * variable.c: ditto. * vm_method.c: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@45426 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 53 ++++++++++ gc.c | 11 +- include/ruby/ruby.h | 24 +++-- internal.h | 7 ++ load.c | 2 +- object.c | 12 +-- parse.y | 296 +++++++++++++++++++++++++++++++++++++++++++++------- sprintf.c | 2 +- string.c | 27 +++-- struct.c | 2 +- template/id.h.tmpl | 20 ++-- thread.c | 8 +- variable.c | 8 +- vm_method.c | 10 +- 14 files changed, 390 insertions(+), 92 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4b90d01d18..284352d30e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,56 @@ +Tue Mar 25 22:57:11 2014 Narihiro Nakamura + + * parse.y: support Symbol GC. [ruby-trunk Feature #9634] + See this ticket about Symbol GC. + + * include/ruby/ruby.h: + Declare few functions. + * rb_sym2id: almost same as old SYM2ID but support dynamic symbols. + * rb_id2sym: almost same as old ID2SYM but support dynamic symbols. + * rb_sym2str: almost same as `rb_id2str(SYM2ID(sym))` but not + pin down a dynamic symbol. + Declare a new struct. + * struct RSymbol: represents a dynamic symbol as object in + Ruby's heaps. + Add few macros. + * STATIC_SYM_P: check a static symbol. + * DYNAMIC_SYM_P: check a dynamic symbol. + * RSYMBOL: cast to RSymbol + + * gc.c: declare RSymbol. support T_SYMBOL. + + * internal.h: Declare few functions. + * rb_gc_free_dsymbol: free up a dynamic symbol. GC call this + function at a sweep phase. + * rb_str_dynamic_intern: convert a string to a dynamic symbol. + * rb_check_id_without_pindown: not pinning function. + * rb_sym2id_without_pindown: ditto. + * rb_check_id_cstr_without_pindown: ditto. + + * string.c (Init_String): String#intern and String#to_sym use + rb_str_dynamic_intern. + + * template/id.h.tmpl: use LSB of ID as a flag for determining a + static symbol, so we shift left other ruby_id_types. + + * string.c: use rb_sym2str instead `rb_id2str(SYM2ID(sym))` to + avoid pinning. + + * load.c: use xx_without_pindown function at creating temporary ID + to avoid pinning. + + * object.c: ditto. + + * sprintf.c: ditto. + + * struct.c: ditto. + + * thread.c: ditto. + + * variable.c: ditto. + + * vm_method.c: ditto. + Wed Mar 26 13:25:54 2014 NARUSE, Yui * addr2line.c (fill_lines): loop reverse order not to overwrite diff --git a/gc.c b/gc.c index e91fee5f37..106b2ecde7 100644 --- a/gc.c +++ b/gc.c @@ -354,6 +354,7 @@ typedef struct RVALUE { struct RMatch match; struct RRational rational; struct RComplex complex; + struct RSymbol symbol; struct { struct RBasic basic; VALUE v1; @@ -1652,6 +1653,12 @@ obj_free(rb_objspace_t *objspace, VALUE obj) } break; + case T_SYMBOL: + { + rb_gc_free_dsymbol(obj); + } + break; + default: rb_bug("gc_sweep(): unknown data type 0x%x(%p) 0x%"PRIxVALUE, BUILTIN_TYPE(obj), (void*)obj, RBASIC(obj)->flags); @@ -2393,7 +2400,7 @@ rb_obj_id(VALUE obj) * 24 if 32-bit, double is 8-byte aligned * 40 if 64-bit */ - if (SYMBOL_P(obj)) { + if (STATIC_SYM_P(obj)) { return (SYM2ID(obj) * sizeof(RVALUE) + (4 << 2)) | FIXNUM_FLAG; } else if (FLONUM_P(obj)) { @@ -2499,6 +2506,7 @@ obj_memsize_of(VALUE obj, int use_tdata) break; case T_FLOAT: + case T_SYMBOL: break; case T_BIGNUM: @@ -3918,6 +3926,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr) case T_FLOAT: case T_BIGNUM: + case T_SYMBOL: break; case T_MATCH: diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h index abd4b4bad3..8de3a43010 100644 --- a/include/ruby/ruby.h +++ b/include/ruby/ruby.h @@ -351,9 +351,13 @@ rb_long2int_inline(long n) #define IMMEDIATE_P(x) ((VALUE)(x) & IMMEDIATE_MASK) -#define SYMBOL_P(x) (((VALUE)(x)&~((~(VALUE)0)<= SIZEOF_DOUBLE @@ -957,6 +961,12 @@ struct RComplex { #define RCOMPLEX_SET_REAL(cmp, r) RB_OBJ_WRITE((cmp), &((struct RComplex *)(cmp))->real,(r)) #define RCOMPLEX_SET_IMAG(cmp, i) RB_OBJ_WRITE((cmp), &((struct RComplex *)(cmp))->imag,(i)) +struct RSymbol { + struct RBasic basic; + VALUE fstr; + ID type; +}; + struct RData { struct RBasic basic; void (*dmark)(void*); @@ -1093,6 +1103,7 @@ struct RStruct { #define RFILE(obj) (R_CAST(RFile)(obj)) #define RRATIONAL(obj) (R_CAST(RRational)(obj)) #define RCOMPLEX(obj) (R_CAST(RComplex)(obj)) +#define RSYMBOL(obj) (R_CAST(RSymbol)(obj)) #define FL_SINGLETON FL_USER0 #define FL_WB_PROTECTED (((VALUE)1)<<5) @@ -1146,7 +1157,7 @@ struct RStruct { (OBJ_TAINTABLE(x) && FL_ABLE(s)) ? \ RBASIC(x)->flags |= RBASIC(s)->flags & FL_TAINT : 0) -#define OBJ_FROZEN(x) (!!(FL_ABLE(x)?(RBASIC(x)->flags&(FL_FREEZE)):(FIXNUM_P(x)||FLONUM_P(x)||SYMBOL_P(x)))) +#define OBJ_FROZEN(x) (!!(FL_ABLE(x)?(RBASIC(x)->flags&(FL_FREEZE)):(FIXNUM_P(x)||FLONUM_P(x)||STATIC_SYM_P(x)))) #define OBJ_FREEZE(x) FL_SET((x), FL_FREEZE) #if USE_RGENGC @@ -1381,6 +1392,7 @@ const char *rb_id2name(ID); ID rb_check_id(volatile VALUE *); ID rb_to_id(VALUE); VALUE rb_id2str(ID); +VALUE rb_sym2str(VALUE); #define CONST_ID_CACHE(result, str) \ { \ @@ -1597,7 +1609,7 @@ rb_class_of(VALUE obj) if (FIXNUM_P(obj)) return rb_cFixnum; if (FLONUM_P(obj)) return rb_cFloat; if (obj == Qtrue) return rb_cTrueClass; - if (SYMBOL_P(obj)) return rb_cSymbol; + if (STATIC_SYM_P(obj)) return rb_cSymbol; } else if (!RTEST(obj)) { if (obj == Qnil) return rb_cNilClass; @@ -1613,7 +1625,7 @@ rb_type(VALUE obj) if (FIXNUM_P(obj)) return T_FIXNUM; if (FLONUM_P(obj)) return T_FLOAT; if (obj == Qtrue) return T_TRUE; - if (SYMBOL_P(obj)) return T_SYMBOL; + if (STATIC_SYM_P(obj)) return T_SYMBOL; if (obj == Qundef) return T_UNDEF; } else if (!RTEST(obj)) { diff --git a/internal.h b/internal.h index da6b5fa236..6e4cd271a0 100644 --- a/internal.h +++ b/internal.h @@ -742,6 +742,13 @@ int rb_is_junk_name(VALUE name); void rb_gc_mark_parser(void); void rb_gc_mark_symbols(int full_mark); ID rb_make_internal_id(void); +void rb_gc_free_dsymbol(VALUE); +VALUE rb_str_dynamic_intern(VALUE); +ID rb_check_id_without_pindown(VALUE *); +ID rb_sym2id_without_pindown(VALUE); +#ifdef RUBY_ENCODING_H +ID rb_check_id_cstr_without_pindown(const char *, long, rb_encoding *); +#endif /* proc.c */ VALUE rb_proc_location(VALUE self); diff --git a/load.c b/load.c index e88abfbb0c..bb8829da05 100644 --- a/load.c +++ b/load.c @@ -1108,7 +1108,7 @@ rb_mod_autoload(VALUE mod, VALUE sym, VALUE file) static VALUE rb_mod_autoload_p(VALUE mod, VALUE sym) { - ID id = rb_check_id(&sym); + ID id = rb_check_id_without_pindown(&sym); if (!id) { return Qnil; } diff --git a/object.c b/object.c index 7dc5407630..9981978622 100644 --- a/object.c +++ b/object.c @@ -2125,7 +2125,7 @@ rb_mod_const_get(int argc, VALUE *argv, VALUE mod) if (pbeg == p) goto wrong_name; - id = rb_check_id_cstr(pbeg, len = p-pbeg, enc); + id = rb_check_id_cstr_without_pindown(pbeg, len = p-pbeg, enc); beglen = pbeg-path; if (p < pend && p[0] == ':') { @@ -2267,7 +2267,7 @@ rb_mod_const_defined(int argc, VALUE *argv, VALUE mod) if (pbeg == p) goto wrong_name; - id = rb_check_id_cstr(pbeg, len = p-pbeg, enc); + id = rb_check_id_cstr_without_pindown(pbeg, len = p-pbeg, enc); beglen = pbeg-path; if (p < pend && p[0] == ':') { @@ -2338,7 +2338,7 @@ rb_mod_const_defined(int argc, VALUE *argv, VALUE mod) static VALUE rb_obj_ivar_get(VALUE obj, VALUE iv) { - ID id = rb_check_id(&iv); + ID id = rb_check_id_without_pindown(&iv); if (!id) { if (rb_is_instance_name(iv)) { @@ -2409,7 +2409,7 @@ rb_obj_ivar_set(VALUE obj, VALUE iv, VALUE val) static VALUE rb_obj_ivar_defined(VALUE obj, VALUE iv) { - ID id = rb_check_id(&iv); + ID id = rb_check_id_without_pindown(&iv); if (!id) { if (rb_is_instance_name(iv)) { @@ -2446,7 +2446,7 @@ rb_obj_ivar_defined(VALUE obj, VALUE iv) static VALUE rb_mod_cvar_get(VALUE obj, VALUE iv) { - ID id = rb_check_id(&iv); + ID id = rb_check_id_without_pindown(&iv); if (!id) { if (rb_is_class_name(iv)) { @@ -2512,7 +2512,7 @@ rb_mod_cvar_set(VALUE obj, VALUE iv, VALUE val) static VALUE rb_mod_cvar_defined(VALUE obj, VALUE iv) { - ID id = rb_check_id(&iv); + ID id = rb_check_id_without_pindown(&iv); if (!id) { if (rb_is_class_name(iv)) { diff --git a/parse.y b/parse.y index aab0e40ebd..f56d9636c8 100644 --- a/parse.y +++ b/parse.y @@ -41,26 +41,26 @@ #define free YYFREE #ifndef RIPPER -static ID register_symid(ID, const char *, long, rb_encoding *); -static ID register_symid_str(ID, VALUE); -#define REGISTER_SYMID(id, name) register_symid((id), (name), strlen(name), enc) +static ID register_static_symid(ID, const char *, long, rb_encoding *); +static ID register_static_symid_str(ID, VALUE); +#define REGISTER_SYMID(id, name) register_static_symid((id), (name), strlen(name), enc) #include "id.c" #endif +static inline int id_type(ID); #define is_notop_id(id) ((id)>tLAST_OP_ID) -#define is_local_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_LOCAL) -#define is_global_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_GLOBAL) -#define is_instance_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_INSTANCE) -#define is_attrset_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_ATTRSET) -#define is_const_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_CONST) -#define is_class_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_CLASS) -#define is_junk_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_JUNK) -#define id_type(id) (is_notop_id(id) ? (int)((id)&ID_SCOPE_MASK) : -1) +#define is_local_id(id) (id_type(id)==ID_LOCAL) +#define is_global_id(id) (id_type(id)==ID_GLOBAL) +#define is_instance_id(id) (id_type(id)==ID_INSTANCE) +#define is_attrset_id(id) (id_type(id)==ID_ATTRSET) +#define is_const_id(id) (id_type(id)==ID_CONST) +#define is_class_id(id) (id_type(id)==ID_CLASS) +#define is_junk_id(id) (id_type(id)==ID_JUNK) #define is_asgn_or_id(id) ((is_notop_id(id)) && \ - (((id)&ID_SCOPE_MASK) == ID_GLOBAL || \ - ((id)&ID_SCOPE_MASK) == ID_INSTANCE || \ - ((id)&ID_SCOPE_MASK) == ID_CLASS)) + ((id_type(id)) == ID_GLOBAL || \ + (id_type(id)) == ID_INSTANCE || \ + (id_type(id)) == ID_CLASS)) enum lex_state_bits { EXPR_BEG_bit, /* ignore newline, +/- is a sign. */ @@ -300,11 +300,17 @@ struct parser_params { #endif }; +#ifdef RIPPER +#define intern_cstr_without_pindown(n,l,en) rb_intern3(n,l,en) +#else +static ID intern_cstr_without_pindown(const char *, long, rb_encoding *); +#endif + #define STR_NEW(p,n) rb_enc_str_new((p),(n),current_enc) #define STR_NEW0() rb_enc_str_new(0,0,current_enc) #define STR_NEW2(p) rb_enc_str_new((p),strlen(p),current_enc) #define STR_NEW3(p,n,e,func) parser_str_new((p),(n),(e),(func),current_enc) -#define TOK_INTERN() rb_intern3(tok(), toklen(), current_enc) +#define TOK_INTERN() intern_cstr_without_pindown(tok(), toklen(), current_enc) static int parser_yyerror(struct parser_params*, const char*); #define yyerror(msg) parser_yyerror(parser, (msg)) @@ -8010,7 +8016,7 @@ parser_yylex(struct parser_params *parser) return '$'; } gvar: - set_yylval_name(rb_intern3(tok(), tokidx, current_enc)); + set_yylval_name(intern_cstr_without_pindown(tok(), tokidx, current_enc)); return tGVAR; case '&': /* $&: last match */ @@ -8813,6 +8819,8 @@ static const char id_type_names[][9] = { "JUNK", }; +static ID rb_pin_dynamic_symbol(VALUE); + ID rb_id_attrset(ID id) { @@ -8824,7 +8832,7 @@ rb_id_attrset(ID id) rb_name_error(id, "cannot make operator ID :%s attrset", rb_id2name(id)); } else { - int scope = (int)(id & ID_SCOPE_MASK); + int scope = id_type(id); switch (scope) { case ID_LOCAL: case ID_INSTANCE: case ID_GLOBAL: case ID_CONST: case ID_CLASS: case ID_JUNK: @@ -8837,8 +8845,19 @@ rb_id_attrset(ID id) } } - id &= ~ID_SCOPE_MASK; - id |= ID_ATTRSET; + if (id&ID_STATIC_SYM) { + id &= ~ID_SCOPE_MASK; + id |= ID_ATTRSET; + } + else { + VALUE str; + + /* make new dynamic symbol */ + str = rb_str_dup(RSYMBOL((VALUE)id)->fstr); + rb_str_cat(str, "=", 1); + id = (ID)rb_str_dynamic_intern(str); + rb_pin_dynamic_symbol((VALUE)id); + } return id; } @@ -9930,7 +9949,7 @@ reg_named_capture_assign_iter(const OnigUChar *name, const OnigUChar *name_end, !rb_enc_symname2_p(s, len, enc)) { return ST_CONTINUE; } - var = rb_intern3(s, len, enc); + var = intern_cstr_without_pindown(s, len, enc); if (dvar_defined(var) || local_id(var)) { rb_warningS("named capture conflicts a local variable - %s", rb_id2name(var)); @@ -10116,12 +10135,14 @@ static struct symbols { ID last_id; st_table *sym_id; st_table *id_str; + st_table *pinned_dsym; #if ENABLE_SELECTOR_NAMESPACE st_table *ivar2_id; st_table *id_ivar2; #endif VALUE op_sym[tLAST_OP_ID]; int minor_marked; + int pinned_dsym_minor_marked; } global_symbols = {tLAST_TOKEN}; static const struct st_hash_type symhash = { @@ -10161,6 +10182,7 @@ Init_sym(void) { global_symbols.sym_id = st_init_table_with_size(&symhash, 1000); global_symbols.id_str = st_init_numtable_with_size(1000); + global_symbols.pinned_dsym = st_init_numtable_with_size(1000); #if ENABLE_SELECTOR_NAMESPACE global_symbols.ivar2_id = st_init_table_with_size(&ivar2_hash_type, 1000); global_symbols.id_ivar2 = st_init_numtable_with_size(1000); @@ -10185,6 +10207,11 @@ rb_gc_mark_symbols(int full_mark) if (!full_mark) global_symbols.minor_marked = 1; } + + if (full_mark || global_symbols.pinned_dsym_minor_marked == 0) { + rb_mark_tbl(global_symbols.pinned_dsym); + if (!full_mark) global_symbols.pinned_dsym_minor_marked = 1; + } } #endif /* !RIPPER */ @@ -10193,7 +10220,22 @@ internal_id_gen(struct parser_params *parser) { ID id = (ID)vtable_size(lvtbl->args) + (ID)vtable_size(lvtbl->vars); id += ((tLAST_TOKEN - ID_INTERNAL) >> ID_SCOPE_SHIFT) + 1; - return ID_INTERNAL | (id << ID_SCOPE_SHIFT); + return ID_STATIC_SYM | ID_INTERNAL | (id << ID_SCOPE_SHIFT); +} + +static inline int +id_type(ID id) +{ + if (id<=tLAST_OP_ID) { + return -1; + } + if (id&ID_STATIC_SYM) { + return (int)((id)&ID_SCOPE_MASK); + } + else { + VALUE dsym = (VALUE)id; + return RSYMBOL(dsym)->type; + } } #ifndef RIPPER @@ -10353,14 +10395,14 @@ rb_str_symname_type(VALUE name, unsigned int allowed_attrset) } static ID -register_symid(ID id, const char *name, long len, rb_encoding *enc) +register_static_symid(ID id, const char *name, long len, rb_encoding *enc) { VALUE str = rb_enc_str_new(name, len, enc); - return register_symid_str(id, str); + return register_static_symid_str(id, str); } static ID -register_symid_str(ID id, VALUE str) +register_static_symid_str(ID id, VALUE str) { OBJ_FREEZE(str); str = rb_fstring(str); @@ -10406,8 +10448,35 @@ setup_fake_str(struct RString *fake_str, const char *name, long len) return (VALUE)fake_str; } +#define ID_DYNAMIC_SYM_P(id) (!(id&ID_STATIC_SYM)&&id>tLAST_TOKEN) + ID -rb_intern3(const char *name, long len, rb_encoding *enc) +rb_pin_dynamic_symbol(VALUE sym) +{ + /* stick dynamic symbol */ + if (!st_insert(global_symbols.pinned_dsym, sym, (st_data_t)sym)) { + global_symbols.pinned_dsym_minor_marked = 0; + } + return (ID)sym; +} + +static int +lookup_sym_id(st_data_t str, st_data_t *data) +{ + ID id; + + if (!st_lookup(global_symbols.sym_id, str, data)) { + return FALSE; + } + id = (ID)*data; + if (ID_DYNAMIC_SYM_P(id)) { + rb_pin_dynamic_symbol((VALUE)id); + } + return TRUE; +} + +static ID +intern_cstr_without_pindown(const char *name, long len, rb_encoding *enc) { st_data_t data; struct RString fake_str; @@ -10422,17 +10491,31 @@ rb_intern3(const char *name, long len, rb_encoding *enc) return intern_str(str); } +ID +rb_intern3(const char *name, long len, rb_encoding *enc) +{ + ID id; + + id = intern_cstr_without_pindown(name, len, enc); + if (ID_DYNAMIC_SYM_P(id)) { + rb_pin_dynamic_symbol((VALUE)id); + } + + return id; +} + static ID next_id_base(void) { if (global_symbols.last_id >= ~(ID)0 >> (ID_SCOPE_SHIFT+RUBY_SPECIAL_SHIFT)) { return (ID)-1; } - return ++global_symbols.last_id << ID_SCOPE_SHIFT; + ++global_symbols.last_id; + return global_symbols.last_id << ID_SCOPE_SHIFT; } static ID -intern_str(VALUE str) +next_id(VALUE str) { const char *name, *m, *e; long len, last; @@ -10484,13 +10567,13 @@ intern_str(VALUE str) if (len == 1) { id = c; - goto id_register; + return id; } for (i = 0; i < op_tbl_count; i++) { if (*op_tbl[i].name == *m && strcmp(op_tbl[i].name, m) == 0) { id = op_tbl[i].token; - goto id_register; + return id; } } } @@ -10501,10 +10584,11 @@ intern_str(VALUE str) if (last > 1 && name[last-1] == '=') goto junk; id = rb_intern3(name, last, enc); + id |= ID_STATIC_SYM; if (id > tLAST_OP_ID && !is_attrset_id(id)) { enc = rb_enc_get(rb_id2str(id)); id = rb_id_attrset(id); - goto id_register; + return id; } id = ID_ATTRSET; } @@ -10541,8 +10625,14 @@ intern_str(VALUE str) } } id |= nid; - id_register: - return register_symid_str(id, str); + id |= ID_STATIC_SYM; + return id; +} + +static ID +intern_str(VALUE str) +{ + return register_static_symid_str(next_id(str), str); } ID @@ -10563,11 +10653,113 @@ rb_intern_str(VALUE str) { st_data_t id; - if (st_lookup(global_symbols.sym_id, str, &id)) + if (lookup_sym_id(str, &id)) return (ID)id; return intern_str(rb_str_dup(str)); } +void +rb_gc_free_dsymbol(VALUE ptr) +{ + st_delete(global_symbols.sym_id, (st_data_t *)&RSYMBOL(ptr)->fstr, 0); + st_delete(global_symbols.id_str, (st_data_t *)&ptr, 0); + RSYMBOL(ptr)->fstr = (VALUE)NULL; +} + +VALUE +rb_str_dynamic_intern(VALUE s) +{ + VALUE str = RB_GC_GUARD(s); + VALUE dup; + rb_encoding *enc; + VALUE dsym; + ID id, type; + + if (st_lookup(global_symbols.sym_id, str, &id)) { + return ID2SYM(id); + } + + dup = rb_str_dup(str); + enc = rb_enc_get(str); + if (rb_enc_asciicompat(enc)) { + if (sym_check_asciionly(str)) { + rb_enc_associate(dup, rb_usascii_encoding()); + } + } + + type = rb_str_symname_type(str, TRUE); + OBJ_FREEZE(dup); + str = rb_fstring(dup); + dsym = rb_newobj_of(rb_cSymbol, T_SYMBOL); + OBJ_FREEZE(dsym); + RSYMBOL(dsym)->fstr = str; + RSYMBOL(dsym)->type = type; + + st_add_direct(global_symbols.sym_id, (st_data_t)str, (ID)dsym); + st_add_direct(global_symbols.id_str, (ID)dsym, (st_data_t)str); + global_symbols.minor_marked = 0; + + if (RUBY_DTRACE_SYMBOL_CREATE_ENABLED()) { + RUBY_DTRACE_SYMBOL_CREATE(RSTRING_PTR(str), rb_sourcefile(), rb_sourceline()); + } + + return dsym; +} + +static int +lookup_id_str(ID id, st_data_t *data) +{ + if (ID_DYNAMIC_SYM_P(id)) { + *data = RSYMBOL(id)->fstr; + return TRUE; + } + if (st_lookup(global_symbols.id_str, id, data)) { + return TRUE; + } + return FALSE; +} + +inline ID +rb_sym2id(VALUE x) +{ + if (STATIC_SYM_P(x)) { + return RSHIFT((unsigned long)(x),RUBY_SPECIAL_SHIFT); + } + else { + return rb_pin_dynamic_symbol(x); + } +} + +inline ID +rb_sym2id_without_pindown(VALUE x) +{ + if (STATIC_SYM_P(x)) { + return RSHIFT((unsigned long)(x),RUBY_SPECIAL_SHIFT); + } + else { + return (ID)x; + } +} + +inline VALUE +rb_id2sym(ID x) +{ + if (!ID_DYNAMIC_SYM_P(x)) { + return ((VALUE)(x)<klass == 0) RBASIC_SET_CLASS_RAW(str, rb_cString); @@ -10613,7 +10805,7 @@ rb_id2str(ID id) } if (is_attrset_id(id)) { - ID id_stem = (id & ~ID_SCOPE_MASK); + ID id_stem = (id & ~ID_SCOPE_MASK) | ID_STATIC_SYM; VALUE str; do { @@ -10627,7 +10819,7 @@ rb_id2str(ID id) } while (0); str = rb_str_dup(str); rb_str_cat(str, "=", 1); - register_symid_str(id, str); + register_static_symid_str(id, str); if (st_lookup(global_symbols.id_str, id, &data)) { VALUE str = (VALUE)data; if (RBASIC(str)->klass == 0) @@ -10650,7 +10842,7 @@ rb_id2name(ID id) ID rb_make_internal_id(void) { - return next_id_base() | ID_INTERNAL; + return next_id_base() | ID_INTERNAL | ID_STATIC_SYM; } static int @@ -10740,13 +10932,39 @@ rb_is_junk_id(ID id) */ ID rb_check_id(volatile VALUE *namep) +{ + ID id; + + id = rb_check_id_without_pindown((VALUE *)namep); + if (ID_DYNAMIC_SYM_P(id)) { + rb_pin_dynamic_symbol((VALUE)id); + } + + return id; +} + +ID +rb_check_id_cstr(const char *ptr, long len, rb_encoding *enc) +{ + ID id; + + id = rb_check_id_cstr_without_pindown(ptr, len, enc); + if (ID_DYNAMIC_SYM_P(id)) { + rb_pin_dynamic_symbol((VALUE)id); + } + + return id; +} + +ID +rb_check_id_without_pindown(VALUE *namep) { st_data_t id; VALUE tmp; VALUE name = *namep; if (SYMBOL_P(name)) { - return SYM2ID(name); + return rb_sym2id_without_pindown(name); } else if (!RB_TYPE_P(name, T_STRING)) { tmp = rb_check_string_type(name); @@ -10781,7 +10999,7 @@ rb_check_id(volatile VALUE *namep) } ID -rb_check_id_cstr(const char *ptr, long len, rb_encoding *enc) +rb_check_id_cstr_without_pindown(const char *ptr, long len, rb_encoding *enc) { st_data_t id; struct RString fake_str; diff --git a/sprintf.c b/sprintf.c index 6551f8f043..52a7168dc9 100644 --- a/sprintf.c +++ b/sprintf.c @@ -567,7 +567,7 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt) rb_enc_raise(enc, rb_eArgError, "named%.*s after <%s>", len, start, rb_id2name(id)); } - nextvalue = GETNAMEARG((id = rb_check_id_cstr(start + 1, + nextvalue = GETNAMEARG((id = rb_check_id_cstr_without_pindown(start + 1, len - 2 /* without parenthesis */, enc), ID2SYM(id)), diff --git a/string.c b/string.c index 3eda81ca3c..936cc18ac4 100644 --- a/string.c +++ b/string.c @@ -8345,10 +8345,9 @@ sym_inspect(VALUE sym) VALUE str; const char *ptr; long len; - ID id = SYM2ID(sym); char *dest; - sym = rb_id2str(id); + sym = rb_sym2str(sym); if (!rb_str_symname_p(sym)) { str = rb_str_inspect(sym); len = RSTRING_LEN(str); @@ -8384,9 +8383,7 @@ sym_inspect(VALUE sym) VALUE rb_sym_to_s(VALUE sym) { - ID id = SYM2ID(sym); - - return str_new_shared(rb_cString, rb_id2str(id)); + return str_new_shared(rb_cString, rb_sym2str(sym)); } @@ -8468,7 +8465,7 @@ sym_to_proc(VALUE sym) static VALUE sym_succ(VALUE sym) { - return rb_str_intern(rb_str_succ(rb_sym_to_s(sym))); + return rb_str_dynamic_intern(rb_str_succ(rb_sym_to_s(sym))); } /* @@ -8552,7 +8549,7 @@ sym_aref(int argc, VALUE *argv, VALUE sym) static VALUE sym_length(VALUE sym) { - return rb_str_length(rb_id2str(SYM2ID(sym))); + return rb_str_length(rb_sym2str(sym)); } /* @@ -8565,7 +8562,7 @@ sym_length(VALUE sym) static VALUE sym_empty(VALUE sym) { - return rb_str_empty(rb_id2str(SYM2ID(sym))); + return rb_str_empty(rb_sym2str(sym)); } /* @@ -8578,7 +8575,7 @@ sym_empty(VALUE sym) static VALUE sym_upcase(VALUE sym) { - return rb_str_intern(rb_str_upcase(rb_id2str(SYM2ID(sym)))); + return rb_str_dynamic_intern(rb_str_upcase(rb_sym2str(sym))); } /* @@ -8591,7 +8588,7 @@ sym_upcase(VALUE sym) static VALUE sym_downcase(VALUE sym) { - return rb_str_intern(rb_str_downcase(rb_id2str(SYM2ID(sym)))); + return rb_str_dynamic_intern(rb_str_downcase(rb_sym2str(sym))); } /* @@ -8604,7 +8601,7 @@ sym_downcase(VALUE sym) static VALUE sym_capitalize(VALUE sym) { - return rb_str_intern(rb_str_capitalize(rb_id2str(SYM2ID(sym)))); + return rb_str_dynamic_intern(rb_str_capitalize(rb_sym2str(sym))); } /* @@ -8617,7 +8614,7 @@ sym_capitalize(VALUE sym) static VALUE sym_swapcase(VALUE sym) { - return rb_str_intern(rb_str_swapcase(rb_id2str(SYM2ID(sym)))); + return rb_str_dynamic_intern(rb_str_swapcase(rb_sym2str(sym))); } /* @@ -8630,7 +8627,7 @@ sym_swapcase(VALUE sym) static VALUE sym_encoding(VALUE sym) { - return rb_obj_encoding(rb_id2str(SYM2ID(sym))); + return rb_obj_encoding(rb_sym2str(sym)); } ID @@ -8742,8 +8739,8 @@ Init_String(void) rb_define_method(rb_cString, "<<", rb_str_concat, 1); rb_define_method(rb_cString, "prepend", rb_str_prepend, 1); rb_define_method(rb_cString, "crypt", rb_str_crypt, 1); - rb_define_method(rb_cString, "intern", rb_str_intern, 0); - rb_define_method(rb_cString, "to_sym", rb_str_intern, 0); + rb_define_method(rb_cString, "intern", rb_str_dynamic_intern, 0); /* in parse.y */ + rb_define_method(rb_cString, "to_sym", rb_str_dynamic_intern, 0); /* in parse.y */ rb_define_method(rb_cString, "ord", rb_str_ord, 0); rb_define_method(rb_cString, "include?", rb_str_include, 1); diff --git a/struct.c b/struct.c index 7da60dbad0..7c230c0e2c 100644 --- a/struct.c +++ b/struct.c @@ -749,7 +749,7 @@ rb_struct_aref(VALUE s, VALUE idx) return rb_struct_aref_id(s, SYM2ID(idx)); } else if (RB_TYPE_P(idx, T_STRING)) { - ID id = rb_check_id(&idx); + ID id = rb_check_id_without_pindown(&idx); if (!id) { rb_name_error_str(idx, "no member '%"PRIsVALUE"' in struct", QUOTE(idx)); diff --git a/template/id.h.tmpl b/template/id.h.tmpl index 9df7947214..0a480f438f 100644 --- a/template/id.h.tmpl +++ b/template/id.h.tmpl @@ -29,18 +29,20 @@ types = ids.keys.grep(/^[A-Z]/) #define RUBY_ID_H enum ruby_id_types { + RUBY_ID_STATIC_SYM = 0x01, RUBY_ID_LOCAL = 0x00, - RUBY_ID_INSTANCE = 0x01, - RUBY_ID_GLOBAL = 0x03, - RUBY_ID_ATTRSET = 0x04, - RUBY_ID_CONST = 0x05, - RUBY_ID_CLASS = 0x06, - RUBY_ID_JUNK = 0x07, + RUBY_ID_INSTANCE = (0x01<<1), + RUBY_ID_GLOBAL = (0x03<<1), + RUBY_ID_ATTRSET = (0x04<<1), + RUBY_ID_CONST = (0x05<<1), + RUBY_ID_CLASS = (0x06<<1), + RUBY_ID_JUNK = (0x07<<1), RUBY_ID_INTERNAL = RUBY_ID_JUNK, - RUBY_ID_SCOPE_SHIFT = 3, - RUBY_ID_SCOPE_MASK = ~(~0U<ID(n) id##n = ((t##n<) +#define TOKEN2<%=type%>ID(n) id##n = ((t##n<|ID_STATIC_SYM) % types.each do |token| TOKEN2<%=type%>ID(<%=token%>), % end diff --git a/thread.c b/thread.c index 0b52cbd127..dfa91a827b 100644 --- a/thread.c +++ b/thread.c @@ -2776,7 +2776,7 @@ rb_thread_local_aref(VALUE thread, ID id) static VALUE rb_thread_aref(VALUE thread, VALUE key) { - ID id = rb_check_id(&key); + ID id = rb_check_id_without_pindown(&key); if (!id) return Qnil; return rb_thread_local_aref(thread, id); } @@ -2853,7 +2853,7 @@ static VALUE rb_thread_variable_get(VALUE thread, VALUE key) { VALUE locals; - ID id = rb_check_id(&key); + ID id = rb_check_id_without_pindown(&key); if (!id) return Qnil; locals = rb_ivar_get(thread, id_locals); @@ -2899,7 +2899,7 @@ static VALUE rb_thread_key_p(VALUE self, VALUE key) { rb_thread_t *th; - ID id = rb_check_id(&key); + ID id = rb_check_id_without_pindown(&key); GetThreadPtr(self, th); @@ -3020,7 +3020,7 @@ static VALUE rb_thread_variable_p(VALUE thread, VALUE key) { VALUE locals; - ID id = rb_check_id(&key); + ID id = rb_check_id_without_pindown(&key); if (!id) return Qfalse; diff --git a/variable.c b/variable.c index 079f862797..292b084011 100644 --- a/variable.c +++ b/variable.c @@ -353,7 +353,7 @@ rb_path_to_class(VALUE pathname) } while (*p) { while (*p && *p != ':') p++; - id = rb_check_id_cstr(pbeg, p-pbeg, enc); + id = rb_check_id_cstr_without_pindown(pbeg, p-pbeg, enc); if (p[0] == ':') { if (p[1] != ':') goto undefined_class; p += 2; @@ -1403,7 +1403,7 @@ VALUE rb_obj_remove_instance_variable(VALUE obj, VALUE name) { VALUE val = Qnil; - const ID id = rb_check_id(&name); + const ID id = rb_check_id_without_pindown(&name); st_data_t n, v; struct st_table *iv_index_tbl; st_data_t index; @@ -1919,7 +1919,7 @@ rb_public_const_get_at(VALUE klass, ID id) VALUE rb_mod_remove_const(VALUE mod, VALUE name) { - const ID id = rb_check_id(&name); + const ID id = rb_check_id_without_pindown(&name); if (!id) { if (rb_is_const_name(name)) { @@ -2568,7 +2568,7 @@ rb_mod_class_variables(int argc, VALUE *argv, VALUE mod) VALUE rb_mod_remove_cvar(VALUE mod, VALUE name) { - const ID id = rb_check_id(&name); + const ID id = rb_check_id_without_pindown(&name); st_data_t val, n = id; if (!id) { diff --git a/vm_method.c b/vm_method.c index 6516a0b03e..6b2eaf8f1b 100644 --- a/vm_method.c +++ b/vm_method.c @@ -791,7 +791,7 @@ rb_mod_remove_method(int argc, VALUE *argv, VALUE mod) for (i = 0; i < argc; i++) { VALUE v = argv[i]; - ID id = rb_check_id(&v); + ID id = rb_check_id_without_pindown(&v); if (!id) { rb_name_error_str(v, "method `%s' not defined in %s", RSTRING_PTR(v), rb_class2name(mod)); @@ -1002,7 +1002,7 @@ rb_mod_undef_method(int argc, VALUE *argv, VALUE mod) int i; for (i = 0; i < argc; i++) { VALUE v = argv[i]; - ID id = rb_check_id(&v); + ID id = rb_check_id_without_pindown(&v); if (!id) { rb_method_name_error(mod, v); } @@ -1042,7 +1042,7 @@ rb_mod_undef_method(int argc, VALUE *argv, VALUE mod) static VALUE rb_mod_method_defined(VALUE mod, VALUE mid) { - ID id = rb_check_id(&mid); + ID id = rb_check_id_without_pindown(&mid); if (!id || !rb_method_boundp(mod, id, 1)) { return Qfalse; } @@ -1056,7 +1056,7 @@ static VALUE check_definition(VALUE mod, VALUE mid, rb_method_flag_t noex) { const rb_method_entry_t *me; - ID id = rb_check_id(&mid); + ID id = rb_check_id_without_pindown(&mid); if (!id) return Qfalse; me = rb_method_entry(mod, id, 0); if (me) { @@ -1685,7 +1685,7 @@ obj_respond_to(int argc, VALUE *argv, VALUE obj) ID id; rb_scan_args(argc, argv, "11", &mid, &priv); - if (!(id = rb_check_id(&mid))) { + if (!(id = rb_check_id_without_pindown(&mid))) { if (!rb_method_basic_definition_p(CLASS_OF(obj), idRespond_to_missing)) { VALUE args[2]; args[0] = ID2SYM(rb_to_id(mid)); -- cgit v1.2.3