* symbol.c (global_symbols): make IDs immortal always, instead
  of treating dynamic symbols as IDs.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2014-10-14 07:23:08 +00:00
Родитель 5617e31771
Коммит 3e69b074c5
4 изменённых файлов: 220 добавлений и 318 удалений

Просмотреть файл

@ -378,9 +378,9 @@ define rp_id
end end
end end
printf "(%ld): ", $id printf "(%ld): ", $id
rb_numtable_entry global_symbols.id_str $id if global_symbols.ids.size > ($id >> RUBY_ID_SCOPE_SHIFT)
if $rb_numtable_rec set $str = global_symbols.ids.ptr[$id >> RUBY_ID_SCOPE_SHIFT]->str
rp_string $rb_numtable_rec rp_string $str
else else
echo undef\n echo undef\n
end end

Просмотреть файл

@ -1,4 +1,7 @@
Tue Oct 14 16:22:59 2014 Nobuyoshi Nakada <nobu@ruby-lang.org> Tue Oct 14 16:23:04 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
* symbol.c (global_symbols): make IDs immortal always, instead
of treating dynamic symbols as IDs.
* iseq.c, marshal.c, string.c: use rb_str_intern instead of * iseq.c, marshal.c, string.c: use rb_str_intern instead of
rb_str_dynamic_intern. rb_str_dynamic_intern.

493
symbol.c
Просмотреть файл

@ -18,10 +18,9 @@
#include "gc.h" #include "gc.h"
#include "probes.h" #include "probes.h"
#define SYMBOL_PINNED FL_USER1 #define SYMBOL_PINNED_P(sym) (RSYMBOL(sym)->id&~ID_SCOPE_MASK)
#define SYMBOL_PINNED_P(sym) FL_TEST((sym), SYMBOL_PINNED)
#define ID_DYNAMIC_SYM_P(id) (!(id&ID_STATIC_SYM)&&id>tLAST_OP_ID) #define DYNAMIC_ID_P(id) (!(id&ID_STATIC_SYM)&&id>tLAST_OP_ID)
#define STATIC_SYM2ID(sym) RSHIFT((unsigned long)(sym), RUBY_SPECIAL_SHIFT) #define STATIC_SYM2ID(sym) RSHIFT((unsigned long)(sym), RUBY_SPECIAL_SHIFT)
#define STATIC_ID2SYM(id) (((VALUE)(id)<<RUBY_SPECIAL_SHIFT)|SYMBOL_FLAG) #define STATIC_ID2SYM(id) (((VALUE)(id)<<RUBY_SPECIAL_SHIFT)|SYMBOL_FLAG)
@ -77,10 +76,36 @@ static const struct {
STATIC_ASSERT(op_tbl_name_size, sizeof(op_tbl[0].name) == 3); STATIC_ASSERT(op_tbl_name_size, sizeof(op_tbl[0].name) == 3);
#define op_tbl_len(i) (!op_tbl[i].name[1] ? 1 : !op_tbl[i].name[2] ? 2 : 3) #define op_tbl_len(i) (!op_tbl[i].name[1] ? 1 : !op_tbl[i].name[2] ? 2 : 3)
static void
Init_op_tbl(void)
{
int i;
rb_encoding *const enc = rb_usascii_encoding();
for (i = '!'; i <= '~'; ++i) {
if (!ISALNUM(i) && i != '_') {
char c = (char)i;
register_static_symid(i, &c, 1, enc);
}
}
for (i = 0; i < op_tbl_count; ++i) {
register_static_symid(op_tbl[i].token, op_tbl[i].name, op_tbl_len(i), enc);
}
}
enum {ID_ENTRY_UNIT = 2048};
struct id_entry {
VALUE str, sym;
};
static struct symbols { static struct symbols {
ID last_id; ID last_id;
st_table *str_id; st_table *str_sym;
st_table *id_str; struct {
size_t size;
struct id_entry *ptr;
} ids;
VALUE dsymbol_fstr_hash; VALUE dsymbol_fstr_hash;
} global_symbols = {tNEXT_ID-1}; } global_symbols = {tNEXT_ID-1};
@ -97,24 +122,31 @@ Init_sym(void)
rb_gc_register_mark_object(dsym_fstrs); rb_gc_register_mark_object(dsym_fstrs);
rb_obj_hide(dsym_fstrs); rb_obj_hide(dsym_fstrs);
global_symbols.str_id = st_init_table_with_size(&symhash, 1000); global_symbols.str_sym = st_init_table_with_size(&symhash, 1000);
global_symbols.id_str = st_init_numtable_with_size(1000); global_symbols.ids.size = ID_ENTRY_UNIT;
global_symbols.ids.ptr = ALLOC_N(struct id_entry, global_symbols.ids.size);
Init_op_tbl();
Init_id(); Init_id();
} }
WARN_UNUSED_RESULT(static VALUE dsymbol_alloc(const VALUE klass, const VALUE str, rb_encoding *const enc, const ID type)); WARN_UNUSED_RESULT(static VALUE dsymbol_alloc(const VALUE klass, const VALUE str, rb_encoding *const enc, const ID type));
WARN_UNUSED_RESULT(static VALUE dsymbol_check(const VALUE sym)); WARN_UNUSED_RESULT(static VALUE dsymbol_check(const VALUE sym));
WARN_UNUSED_RESULT(static ID dsymbol_pindown(VALUE sym));
WARN_UNUSED_RESULT(static ID lookup_str_id(VALUE str)); WARN_UNUSED_RESULT(static ID lookup_str_id(VALUE str));
WARN_UNUSED_RESULT(static VALUE lookup_str_sym(const VALUE str)); WARN_UNUSED_RESULT(static VALUE lookup_str_sym(const VALUE str));
WARN_UNUSED_RESULT(static VALUE lookup_id_str(ID id)); WARN_UNUSED_RESULT(static VALUE lookup_id_str(ID id));
WARN_UNUSED_RESULT(static ID attrsetname_to_attr(VALUE name)); WARN_UNUSED_RESULT(static ID attrsetname_to_attr(VALUE name));
WARN_UNUSED_RESULT(static ID attrsetname_to_attr_id(VALUE name)); WARN_UNUSED_RESULT(static ID attrsetname_to_attr_id(VALUE name));
WARN_UNUSED_RESULT(static ID intern_str(VALUE str, int mutable));
#define id_to_serial(id) (is_notop_id(id) ? id >> ID_SCOPE_SHIFT : id)
ID ID
rb_id_attrset(ID id) rb_id_attrset(ID id)
{ {
VALUE str, sym;
int scope;
if (!is_notop_id(id)) { if (!is_notop_id(id)) {
switch (id) { switch (id) {
case tAREF: case tASET: case tAREF: case tASET:
@ -124,7 +156,7 @@ rb_id_attrset(ID id)
rb_id2str(id)); rb_id2str(id));
} }
else { else {
int scope = id_type(id); scope = id_type(id);
switch (scope) { switch (scope) {
case ID_LOCAL: case ID_INSTANCE: case ID_GLOBAL: case ID_LOCAL: case ID_INSTANCE: case ID_GLOBAL:
case ID_CONST: case ID_CLASS: case ID_JUNK: case ID_CONST: case ID_CLASS: case ID_JUNK:
@ -133,7 +165,6 @@ rb_id_attrset(ID id)
return id; return id;
default: default:
{ {
VALUE str;
if ((str = lookup_id_str(id)) != 0) { if ((str = lookup_id_str(id)) != 0) {
rb_name_error(id, "cannot make unknown type ID %d:%"PRIsVALUE" attrset", rb_name_error(id, "cannot make unknown type ID %d:%"PRIsVALUE" attrset",
scope, str); scope, str);
@ -145,18 +176,26 @@ rb_id_attrset(ID id)
} }
} }
} }
if (id&ID_STATIC_SYM) {
id &= ~ID_SCOPE_MASK;
id |= ID_ATTRSET;
}
else {
VALUE str;
/* make new dynamic symbol */ /* make new symbol and ID */
str = rb_str_dup(RSYMBOL((VALUE)id)->fstr); if (!(str = lookup_id_str(id))) {
rb_str_cat(str, "=", 1); static const char id_types[][8] = {
id = SYM2ID(rb_str_intern(str)); "local",
"instance",
"invalid",
"global",
"attrset",
"const",
"class",
"junk",
};
rb_name_error(id, "cannot make anonymous %.*s ID %"PRIxVALUE" attrset",
(int)sizeof(id_types[0]), id_types[scope], (VALUE)id);
} }
str = rb_str_dup(str);
rb_str_cat(str, "=", 1);
sym = lookup_str_sym(str);
id = sym ? rb_sym2id(sym) : intern_str(str, 1);
return id; return id;
} }
@ -330,35 +369,41 @@ rb_str_symname_type(VALUE name, unsigned int allowed_attrset)
} }
static void static void
register_symid_direct(VALUE str, ID id) set_id_entry(ID num, VALUE str, VALUE sym)
{ {
st_add_direct(global_symbols.str_id, (st_data_t)str, (st_data_t)id); struct id_entry *entry;
st_add_direct(global_symbols.id_str, (st_data_t)id, (st_data_t)str); if (num >= global_symbols.ids.size) {
size_t new_size = (num / ID_ENTRY_UNIT + 1) * ID_ENTRY_UNIT;
REALLOC_N(global_symbols.ids.ptr, struct id_entry, new_size);
global_symbols.ids.size = new_size;
}
entry = &global_symbols.ids.ptr[num];
entry->str = str;
entry->sym = sym;
} }
static int static struct id_entry *
unregister_sym_str(VALUE str) get_id_entry(ID num)
{ {
st_data_t str_data = (st_data_t)str; if (num && num <= global_symbols.last_id) {
return st_delete(global_symbols.str_id, &str_data, NULL); return &global_symbols.ids.ptr[num];
}
return 0;
} }
static int static void
unregister_sym_id(VALUE sym) register_sym(VALUE str, VALUE sym)
{ {
st_data_t sym_data = (st_data_t)sym; st_add_direct(global_symbols.str_sym, (st_data_t)str, (st_data_t)sym);
return st_delete(global_symbols.id_str, &sym_data, NULL);
} }
static void static void
unregister_sym(VALUE str, VALUE sym) unregister_sym(VALUE str, VALUE sym)
{ {
if (!unregister_sym_str(str)) { st_data_t str_data = (st_data_t)str;
if (!st_delete(global_symbols.str_sym, &str_data, NULL)) {
rb_bug("%p can't remove str from str_id (%s)", (void *)sym, RSTRING_PTR(str)); rb_bug("%p can't remove str from str_id (%s)", (void *)sym, RSTRING_PTR(str));
} }
if (!unregister_sym_id(sym)) {
rb_bug("%p can't remove sym from id_str (%s)", (void *)sym, RSTRING_PTR(str));
}
} }
static ID static ID
@ -371,6 +416,9 @@ register_static_symid(ID id, const char *name, long len, rb_encoding *enc)
static ID static ID
register_static_symid_str(ID id, VALUE str) register_static_symid_str(ID id, VALUE str)
{ {
ID num = id_to_serial(id);
VALUE sym = STATIC_ID2SYM(id);
OBJ_FREEZE(str); OBJ_FREEZE(str);
str = rb_fstring(str); str = rb_fstring(str);
@ -378,7 +426,8 @@ register_static_symid_str(ID id, VALUE str)
RUBY_DTRACE_SYMBOL_CREATE(RSTRING_PTR(str), rb_sourcefile(), rb_sourceline()); RUBY_DTRACE_SYMBOL_CREATE(RSTRING_PTR(str), rb_sourcefile(), rb_sourceline());
} }
register_symid_direct(str, id); register_sym(str, sym);
set_id_entry(num, str, sym);
rb_gc_register_mark_object(str); rb_gc_register_mark_object(str);
return id; return id;
@ -397,12 +446,12 @@ sym_check_asciionly(VALUE str)
return FALSE; return FALSE;
} }
#if 0
/* /*
* _str_ itself will be registered at the global symbol table. _str_ * _str_ itself will be registered at the global symbol table. _str_
* can be modified before the registration, since the encoding will be * can be modified before the registration, since the encoding will be
* set to ASCII-8BIT if it is a special global name. * set to ASCII-8BIT if it is a special global name.
*/ */
static ID intern_str(VALUE str);
static inline void static inline void
must_be_dynamic_symbol(VALUE x) must_be_dynamic_symbol(VALUE x)
@ -423,6 +472,7 @@ must_be_dynamic_symbol(VALUE x)
} }
} }
} }
#endif
static VALUE static VALUE
dsymbol_alloc(const VALUE klass, const VALUE str, rb_encoding * const enc, const ID type) dsymbol_alloc(const VALUE klass, const VALUE str, rb_encoding * const enc, const ID type)
@ -432,9 +482,9 @@ dsymbol_alloc(const VALUE klass, const VALUE str, rb_encoding * const enc, const
rb_enc_associate(dsym, enc); rb_enc_associate(dsym, enc);
OBJ_FREEZE(dsym); OBJ_FREEZE(dsym);
RB_OBJ_WRITE(dsym, &RSYMBOL(dsym)->fstr, str); RB_OBJ_WRITE(dsym, &RSYMBOL(dsym)->fstr, str);
RSYMBOL(dsym)->type = type; RSYMBOL(dsym)->id = type;
register_symid_direct(str, (ID)dsym); register_sym(str, dsym);
rb_hash_aset(global_symbols.dsymbol_fstr_hash, str, Qtrue); rb_hash_aset(global_symbols.dsymbol_fstr_hash, str, Qtrue);
if (RUBY_DTRACE_SYMBOL_CREATE_ENABLED()) { if (RUBY_DTRACE_SYMBOL_CREATE_ENABLED()) {
@ -449,7 +499,7 @@ dsymbol_check(const VALUE sym)
{ {
if (UNLIKELY(rb_objspace_garbage_object_p(sym))) { if (UNLIKELY(rb_objspace_garbage_object_p(sym))) {
const VALUE fstr = RSYMBOL(sym)->fstr; const VALUE fstr = RSYMBOL(sym)->fstr;
const ID type = RSYMBOL(sym)->type; const ID type = RSYMBOL(sym)->id & ID_SCOPE_MASK;
RSYMBOL(sym)->fstr = 0; RSYMBOL(sym)->fstr = 0;
unregister_sym(fstr, sym); unregister_sym(fstr, sym);
@ -460,34 +510,23 @@ dsymbol_check(const VALUE sym)
} }
} }
static ID
dsymbol_pindown(VALUE sym)
{
must_be_dynamic_symbol(sym);
if (UNLIKELY(SYMBOL_PINNED_P(sym) == 0)) {
VALUE fstr = RSYMBOL(sym)->fstr;
sym = dsymbol_check(sym);
FL_SET(sym, SYMBOL_PINNED);
/* make it permanent object */
rb_gc_register_mark_object(sym);
rb_gc_register_mark_object(fstr);
rb_hash_delete(global_symbols.dsymbol_fstr_hash, fstr);
}
return (ID)sym;
}
static ID static ID
lookup_str_id(VALUE str) lookup_str_id(VALUE str)
{ {
st_data_t id_data; st_data_t sym_data;
if (st_lookup(global_symbols.str_id, (st_data_t)str, &id_data)) { if (st_lookup(global_symbols.str_sym, (st_data_t)str, &sym_data)) {
const ID id = (ID)id_data; const VALUE sym = (VALUE)sym_data;
if (!ID_DYNAMIC_SYM_P(id) || SYMBOL_PINNED_P(id)) { if (STATIC_SYM_P(sym)) {
return id; return STATIC_SYM2ID(sym);
}
else if (DYNAMIC_SYM_P(sym)) {
ID id = RSYMBOL(sym)->id;
if (id & ~ID_SCOPE_MASK) return id;
}
else {
rb_bug("non-symbol object %s:%"PRIxVALUE" for %"PRIsVALUE" in symbol table",
rb_builtin_class_name(sym), sym, str);
} }
} }
return (ID)0; return (ID)0;
@ -497,15 +536,13 @@ static VALUE
lookup_str_sym(const VALUE str) lookup_str_sym(const VALUE str)
{ {
st_data_t sym_data; st_data_t sym_data;
if (st_lookup(global_symbols.str_id, (st_data_t)str, &sym_data)) { if (st_lookup(global_symbols.str_sym, (st_data_t)str, &sym_data)) {
const ID id = (ID)sym_data; VALUE sym = (VALUE)sym_data;
if (ID_DYNAMIC_SYM_P(id)) { if (DYNAMIC_SYM_P(sym)) {
return dsymbol_check(id); sym = dsymbol_check(sym);
}
else {
return STATIC_ID2SYM(id);
} }
return sym;
} }
else { else {
return (VALUE)0; return (VALUE)0;
@ -515,46 +552,26 @@ lookup_str_sym(const VALUE str)
static VALUE static VALUE
lookup_id_str(ID id) lookup_id_str(ID id)
{ {
st_data_t data; const struct id_entry *entry;
if (ID_DYNAMIC_SYM_P(id)) {
return RSYMBOL(id)->fstr; if ((entry = get_id_entry(id_to_serial(id))) != 0) {
} return entry->str;
if (st_lookup(global_symbols.id_str, id, &data)) {
return (VALUE)data;
} }
return 0; return 0;
} }
ID ID
rb_intern_cstr_without_pindown(const char *name, long len, rb_encoding *enc) rb_intern3(const char *name, long len, rb_encoding *enc)
{ {
st_data_t id; VALUE sym;
struct RString fake_str; struct RString fake_str;
VALUE str = rb_setup_fake_str(&fake_str, name, len, enc); VALUE str = rb_setup_fake_str(&fake_str, name, len, enc);
OBJ_FREEZE(str); OBJ_FREEZE(str);
if (st_lookup(global_symbols.str_id, str, &id)) { sym = lookup_str_sym(str);
if (ID_DYNAMIC_SYM_P((ID)id)) { if (sym) return rb_sym2id(sym);
return (ID)dsymbol_check((VALUE)id);
}
return (ID)id;
}
str = rb_enc_str_new(name, len, enc); /* make true string */ str = rb_enc_str_new(name, len, enc); /* make true string */
return intern_str(str); return intern_str(str, 1);
}
ID
rb_intern3(const char *name, long len, rb_encoding *enc)
{
ID id;
id = rb_intern_cstr_without_pindown(name, len, enc);
if (ID_DYNAMIC_SYM_P(id)) {
id = dsymbol_pindown((VALUE)id);
}
return id;
} }
static ID static ID
@ -563,109 +580,24 @@ next_id_base(void)
if (global_symbols.last_id >= ~(ID)0 >> (ID_SCOPE_SHIFT+RUBY_SPECIAL_SHIFT)) { if (global_symbols.last_id >= ~(ID)0 >> (ID_SCOPE_SHIFT+RUBY_SPECIAL_SHIFT)) {
return (ID)-1; return (ID)-1;
} }
++global_symbols.last_id; else {
return global_symbols.last_id << ID_SCOPE_SHIFT; const size_t num = ++global_symbols.last_id;
return num << ID_SCOPE_SHIFT;
}
} }
static ID static ID
next_id(VALUE str) intern_str(VALUE str, int mutable)
{ {
const char *name, *m, *e;
long len, last;
rb_encoding *enc, *symenc;
unsigned char c;
ID id; ID id;
ID nid; ID nid;
int mb;
RSTRING_GETMEM(str, name, len); id = rb_str_symname_type(str, IDSET_ATTRSET_FOR_INTERN);
m = name; if (id == (ID)-1) id = ID_JUNK;
e = m + len; if (sym_check_asciionly(str)) {
enc = rb_enc_get(str); if (!mutable) str = rb_str_dup(str);
symenc = enc; rb_enc_associate(str, rb_usascii_encoding());
if (!len || (rb_cString && !rb_enc_asciicompat(enc))) {
junk:
id = ID_JUNK;
goto new_id;
} }
last = len-1;
id = 0;
switch (*m) {
case '$':
if (len < 2) goto junk;
id |= ID_GLOBAL;
if ((mb = is_special_global_name(++m, e, enc)) != 0) {
if (!--mb) symenc = rb_usascii_encoding();
goto new_id;
}
break;
case '@':
if (m[1] == '@') {
if (len < 3) goto junk;
m++;
id |= ID_CLASS;
}
else {
if (len < 2) goto junk;
id |= ID_INSTANCE;
}
m++;
break;
default:
c = m[0];
if (c != '_' && rb_enc_isascii(c, enc) && rb_enc_ispunct(c, enc)) {
/* operators */
int i;
if (len == 1) {
id = c;
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;
return id;
}
}
}
break;
}
if (name[last] == '=') {
/* attribute assignment */
if (last > 1 && name[last-1] == '=')
goto junk;
id = rb_intern3(name, last, enc);
if (id > tLAST_OP_ID && !is_attrset_id(id)) {
enc = rb_enc_get(rb_id2str(id));
id = rb_id_attrset(id);
return id;
}
id = ID_ATTRSET;
}
else if (id == 0) {
if (rb_enc_isupper(m[0], enc)) {
id = ID_CONST;
}
else {
id = ID_LOCAL;
}
}
if (!rb_enc_isdigit(*m, enc)) {
while (m <= name + last && is_identchar(m, e, enc)) {
if (ISASCII(*m)) {
m++;
}
else {
m += rb_enc_mbclen(m, e, enc);
}
}
}
if (id != ID_ATTRSET && m - name < len) id = ID_JUNK;
if (sym_check_asciionly(str)) symenc = rb_usascii_encoding();
new_id:
if (symenc != enc) rb_enc_associate(str, symenc);
if ((nid = next_id_base()) == (ID)-1) { if ((nid = next_id_base()) == (ID)-1) {
str = rb_str_ellipsize(str, 20); str = rb_str_ellipsize(str, 20);
rb_raise(rb_eRuntimeError, "symbol table overflow (symbol %"PRIsVALUE")", rb_raise(rb_eRuntimeError, "symbol table overflow (symbol %"PRIsVALUE")",
@ -673,14 +605,6 @@ next_id(VALUE str)
} }
id |= nid; id |= nid;
id |= ID_STATIC_SYM; id |= ID_STATIC_SYM;
return id;
}
static ID
intern_str(VALUE str)
{
ID id = next_id(str);
if (ID_DYNAMIC_SYM_P(id) && is_attrset_id(id)) return id;
return register_static_symid_str(id, str); return register_static_symid_str(id, str);
} }
@ -706,7 +630,7 @@ rb_intern_str(VALUE str)
return SYM2ID(sym); return SYM2ID(sym);
} }
return intern_str(rb_str_dup(str)); return intern_str(str, 0);
} }
void void
@ -745,13 +669,17 @@ rb_str_intern(VALUE str)
{ {
#if USE_SYMBOL_GC #if USE_SYMBOL_GC
rb_encoding *enc, *ascii; rb_encoding *enc, *ascii;
int type;
#else
ID id;
#endif
VALUE sym = lookup_str_sym(str); VALUE sym = lookup_str_sym(str);
ID type;
if (sym) { if (sym) {
return sym; return sym;
} }
#if USE_SYMBOL_GC
enc = rb_enc_get(str); enc = rb_enc_get(str);
ascii = rb_usascii_encoding(); ascii = rb_usascii_encoding();
if (enc != ascii) { if (enc != ascii) {
@ -762,45 +690,56 @@ rb_str_intern(VALUE str)
enc = ascii; enc = ascii;
} }
} }
str = rb_fstring(str);
type = rb_str_symname_type(str, IDSET_ATTRSET_FOR_INTERN); type = rb_str_symname_type(str, IDSET_ATTRSET_FOR_INTERN);
if (type == ID_ATTRSET) { if (type < 0) type = ID_JUNK;
ID attr_id = attrsetname_to_attr_id(str); return dsymbol_alloc(rb_cSymbol, str, enc, type);
if (attr_id && !ID_DYNAMIC_SYM_P(attr_id)) {
attr_id = rb_id_attrset(attr_id);
return ID2SYM(attr_id);
}
}
return dsymbol_alloc(rb_cSymbol, rb_fstring(str), enc, type);
#else #else
return rb_str_intern(str); id = intern_str(str, 0);
return ID2SYM(id);
#endif #endif
} }
ID ID
rb_sym2id(VALUE sym) rb_sym2id(VALUE sym)
{ {
ID id;
if (STATIC_SYM_P(sym)) { if (STATIC_SYM_P(sym)) {
return STATIC_SYM2ID(sym); id = STATIC_SYM2ID(sym);
}
else if (DYNAMIC_SYM_P(sym)) {
sym = dsymbol_check(sym);
id = RSYMBOL(sym)->id;
if (UNLIKELY(!(id & ~ID_SCOPE_MASK))) {
VALUE fstr = RSYMBOL(sym)->fstr;
ID num = next_id_base();
RSYMBOL(sym)->id = id |= num;
/* make it permanent object */
set_id_entry(num >>= ID_SCOPE_SHIFT, fstr, sym);
rb_gc_register_mark_object(sym);
rb_gc_register_mark_object(fstr);
rb_hash_delete(global_symbols.dsymbol_fstr_hash, fstr);
}
} }
else { else {
if (!SYMBOL_PINNED_P(sym)) { rb_raise(rb_eTypeError, "wrong argument type %s (expected Symbol)",
return dsymbol_pindown(sym); rb_builtin_class_name(sym));
}
return (ID)sym;
} }
return id;
} }
VALUE VALUE
rb_id2sym(ID x) rb_id2sym(ID x)
{ {
if (!ID_DYNAMIC_SYM_P(x)) { const struct id_entry *entry;
return STATIC_ID2SYM(x);
} if (!DYNAMIC_ID_P(x)) return STATIC_ID2SYM(x);
else {
return (VALUE)x; if ((entry = get_id_entry(id_to_serial(x))) != 0) {
return entry->sym;
} }
return 0;
} }
@ -820,49 +759,12 @@ rb_id2str(ID id)
{ {
VALUE str; VALUE str;
if (id < tLAST_OP_ID) {
int i = 0;
if (id < INT_MAX && rb_ispunct((int)id)) {
char name[1];
name[0] = (char)id;
return rb_fstring_new(name, 1);
}
for (i = 0; i < op_tbl_count; i++) {
if (op_tbl[i].token == id) {
const char *name = op_tbl[i].name;
return rb_fstring_new(name, op_tbl_len(i));
}
}
}
if ((str = lookup_id_str(id)) != 0) { if ((str = lookup_id_str(id)) != 0) {
if (RBASIC(str)->klass == 0) if (RBASIC(str)->klass == 0)
RBASIC_SET_CLASS_RAW(str, rb_cString); RBASIC_SET_CLASS_RAW(str, rb_cString);
return str; return str;
} }
if (is_attrset_id(id)) {
ID id_stem = (id & ~ID_SCOPE_MASK) | ID_STATIC_SYM;
do {
if (!!(str = rb_id2str(id_stem | ID_LOCAL))) break;
if (!!(str = rb_id2str(id_stem | ID_CONST))) break;
if (!!(str = rb_id2str(id_stem | ID_INSTANCE))) break;
if (!!(str = rb_id2str(id_stem | ID_GLOBAL))) break;
if (!!(str = rb_id2str(id_stem | ID_CLASS))) break;
if (!!(str = rb_id2str(id_stem | ID_JUNK))) break;
return 0;
} while (0);
str = rb_str_dup(str);
rb_str_cat(str, "=", 1);
register_static_symid_str(id, str);
if ((str = lookup_id_str(id)) != 0) {
if (RBASIC(str)->klass == 0)
RBASIC_SET_CLASS_RAW(str, rb_cString);
return str;
}
}
return 0; return 0;
} }
@ -885,11 +787,17 @@ static int
symbols_i(st_data_t key, st_data_t value, st_data_t arg) symbols_i(st_data_t key, st_data_t value, st_data_t arg)
{ {
VALUE ary = (VALUE)arg; VALUE ary = (VALUE)arg;
VALUE sym = ID2SYM((ID)value); VALUE sym = (VALUE)value;
if (DYNAMIC_SYM_P(sym) && !SYMBOL_PINNED_P(sym) && rb_objspace_garbage_object_p(sym)) { if (STATIC_SYM_P(sym)) {
rb_ary_push(ary, sym);
return ST_CONTINUE;
}
else if (!DYNAMIC_SYM_P(sym)) {
rb_bug("invalid symbol: %s", RSTRING_PTR((VALUE)key));
}
else if (!SYMBOL_PINNED_P(sym) && rb_objspace_garbage_object_p(sym)) {
RSYMBOL(sym)->fstr = 0; RSYMBOL(sym)->fstr = 0;
unregister_sym_id(sym);
return ST_DELETE; return ST_DELETE;
} }
else { else {
@ -918,8 +826,8 @@ symbols_i(st_data_t key, st_data_t value, st_data_t arg)
VALUE VALUE
rb_sym_all_symbols(void) rb_sym_all_symbols(void)
{ {
VALUE ary = rb_ary_new2(global_symbols.str_id->num_entries); VALUE ary = rb_ary_new2(global_symbols.str_sym->num_entries);
st_foreach(global_symbols.str_id, symbols_i, ary); st_foreach(global_symbols.str_sym, symbols_i, ary);
return ary; return ary;
} }
@ -979,7 +887,6 @@ rb_is_junk_id(ID id)
ID ID
rb_check_id(volatile VALUE *namep) rb_check_id(volatile VALUE *namep)
{ {
ID id;
VALUE tmp; VALUE tmp;
VALUE name = *namep; VALUE name = *namep;
@ -988,7 +895,7 @@ rb_check_id(volatile VALUE *namep)
} }
else if (DYNAMIC_SYM_P(name)) { else if (DYNAMIC_SYM_P(name)) {
if (SYMBOL_PINNED_P(name)) { if (SYMBOL_PINNED_P(name)) {
return (ID)name; return RSYMBOL(name)->id;
} }
else { else {
*namep = RSYMBOL(name)->fstr; *namep = RSYMBOL(name)->fstr;
@ -1008,16 +915,7 @@ rb_check_id(volatile VALUE *namep)
sym_check_asciionly(name); sym_check_asciionly(name);
if ((id = lookup_str_id(name)) != 0) { return lookup_str_id(name);
return id;
}
{
ID gid = attrsetname_to_attr(name);
if (gid) return rb_id_attrset(gid);
}
return (ID)0;
} }
VALUE VALUE
@ -1027,7 +925,14 @@ rb_check_symbol(volatile VALUE *namep)
VALUE tmp; VALUE tmp;
VALUE name = *namep; VALUE name = *namep;
if (SYMBOL_P(name)) { if (STATIC_SYM_P(name)) {
return name;
}
else if (DYNAMIC_SYM_P(name)) {
if (!SYMBOL_PINNED_P(name)) {
name = dsymbol_check(name);
*namep = name;
}
return name; return name;
} }
else if (!RB_TYPE_P(name, T_STRING)) { else if (!RB_TYPE_P(name, T_STRING)) {
@ -1047,35 +952,18 @@ rb_check_symbol(volatile VALUE *namep)
return sym; return sym;
} }
{
ID gid = attrsetname_to_attr(name);
if (gid) return ID2SYM(rb_id_attrset(gid));
}
return Qnil; return Qnil;
} }
ID ID
rb_check_id_cstr(const char *ptr, long len, rb_encoding *enc) rb_check_id_cstr(const char *ptr, long len, rb_encoding *enc)
{ {
ID id;
struct RString fake_str; struct RString fake_str;
const VALUE name = rb_setup_fake_str(&fake_str, ptr, len, enc); const VALUE name = rb_setup_fake_str(&fake_str, ptr, len, enc);
sym_check_asciionly(name); sym_check_asciionly(name);
if ((id = lookup_str_id(name)) != 0) { return lookup_str_id(name);
return id;
}
if (rb_is_attrset_name(name)) {
fake_str.as.heap.len = len - 1;
if ((id = lookup_str_id(name)) != 0) {
return rb_id_attrset(id);
}
}
return (ID)0;
} }
VALUE VALUE
@ -1091,13 +979,6 @@ rb_check_symbol_cstr(const char *ptr, long len, rb_encoding *enc)
return sym; return sym;
} }
if (rb_is_attrset_name(name)) {
fake_str.as.heap.len = len - 1;
if ((sym = lookup_str_sym(name)) != 0) {
return ID2SYM(rb_id_attrset(SYM2ID(sym)));
}
}
return Qnil; return Qnil;
} }

Просмотреть файл

@ -17,7 +17,7 @@
struct RSymbol { struct RSymbol {
struct RBasic basic; struct RBasic basic;
VALUE fstr; VALUE fstr;
ID type; ID id;
}; };
#define RSYMBOL(obj) (R_CAST(RSymbol)(obj)) #define RSYMBOL(obj) (R_CAST(RSymbol)(obj))
@ -28,13 +28,7 @@ id_type(ID id)
if (id<=tLAST_OP_ID) { if (id<=tLAST_OP_ID) {
return -1; return -1;
} }
if (id&ID_STATIC_SYM) { return (int)(id&ID_SCOPE_MASK);
return (int)((id)&ID_SCOPE_MASK);
}
else {
VALUE dsym = (VALUE)id;
return (int)(RSYMBOL(dsym)->type);
}
} }
#define is_notop_id(id) ((id)>tLAST_OP_ID) #define is_notop_id(id) ((id)>tLAST_OP_ID)
@ -46,6 +40,30 @@ id_type(ID id)
#define is_class_id(id) (id_type(id)==ID_CLASS) #define is_class_id(id) (id_type(id)==ID_CLASS)
#define is_junk_id(id) (id_type(id)==ID_JUNK) #define is_junk_id(id) (id_type(id)==ID_JUNK)
static inline int
sym_type(VALUE sym)
{
ID id;
if (STATIC_SYM_P(sym)) {
id = RSHIFT(sym, RUBY_SPECIAL_SHIFT);
if (id<=tLAST_OP_ID) {
return -1;
}
}
else {
id = RSYMBOL(sym)->id;
}
return (int)(id&ID_SCOPE_MASK);
}
#define is_local_sym(sym) (sym_type(sym)==SYM_LOCAL)
#define is_global_sym(sym) (sym_type(sym)==SYM_GLOBAL)
#define is_instance_sym(sym) (sym_type(sym)==SYM_INSTANCE)
#define is_attrset_sym(sym) (sym_type(sym)==SYM_ATTRSET)
#define is_const_sym(sym) (sym_type(sym)==SYM_CONST)
#define is_class_sym(sym) (sym_type(sym)==SYM_CLASS)
#define is_junk_sym(sym) (sym_type(sym)==SYM_JUNK)
RUBY_FUNC_EXPORTED const unsigned int ruby_global_name_punct_bits[(0x7e - 0x20 + 31) / 32]; RUBY_FUNC_EXPORTED const unsigned int ruby_global_name_punct_bits[(0x7e - 0x20 + 31) / 32];
static inline int static inline int