1 /**********************************************************************
6 created at: Tue Jul 8 15:49:54 JST 2014
8 Copyright (C) 2014 Yukihiro Matsumoto
10 **********************************************************************/
14 #include "internal/error.h"
15 #include "internal/gc.h"
16 #include "internal/hash.h"
17 #include "internal/object.h"
18 #include "internal/symbol.h"
19 #include "internal/vm.h"
21 #include "ruby/encoding.h"
27 # define USE_SYMBOL_GC 1
30 # define SYMBOL_DEBUG 0
32 #ifndef CHECK_ID_SERIAL
33 # define CHECK_ID_SERIAL SYMBOL_DEBUG
36 #define SYMBOL_PINNED_P(sym) (RSYMBOL(sym)->id&~ID_SCOPE_MASK)
38 #define STATIC_SYM2ID(sym) RSHIFT((VALUE)(sym), RUBY_SPECIAL_SHIFT)
40 static ID
register_static_symid(ID
, const char *, long, rb_encoding
*);
41 static ID
register_static_symid_str(ID
, VALUE
);
42 #define REGISTER_SYMID(id, name) register_static_symid((id), (name), strlen(name), enc)
45 #define is_identchar(p,e,enc) (ISALNUM((unsigned char)*(p)) || (*(p)) == '_' || !ISASCII(*(p)))
47 #define op_tbl_count numberof(op_tbl)
48 STATIC_ASSERT(op_tbl_name_size
, sizeof(op_tbl
[0].name
) == 3);
49 #define op_tbl_len(i) (!op_tbl[i].name[1] ? 1 : !op_tbl[i].name[2] ? 2 : 3)
55 rb_encoding
*const enc
= rb_usascii_encoding();
57 for (i
= '!'; i
<= '~'; ++i
) {
58 if (!ISALNUM(i
) && i
!= '_') {
60 register_static_symid(i
, &c
, 1, enc
);
63 for (i
= 0; i
< op_tbl_count
; ++i
) {
64 register_static_symid(op_tbl
[i
].token
, op_tbl
[i
].name
, op_tbl_len(i
), enc
);
68 static const int ID_ENTRY_UNIT
= 512;
76 rb_symbols_t ruby_global_symbols
= {tNEXT_ID
-1};
78 static const struct st_hash_type symhash
= {
86 rb_symbols_t
*symbols
= &ruby_global_symbols
;
88 VALUE dsym_fstrs
= rb_ident_hash_new();
89 symbols
->dsymbol_fstr_hash
= dsym_fstrs
;
90 rb_gc_register_mark_object(dsym_fstrs
);
91 rb_obj_hide(dsym_fstrs
);
93 symbols
->str_sym
= st_init_table_with_size(&symhash
, 1000);
94 symbols
->ids
= rb_ary_tmp_new(0);
95 rb_gc_register_mark_object(symbols
->ids
);
101 WARN_UNUSED_RESULT(static VALUE
dsymbol_alloc(rb_symbols_t
*symbols
, const VALUE klass
, const VALUE str
, rb_encoding
*const enc
, const ID type
));
102 WARN_UNUSED_RESULT(static VALUE
dsymbol_check(rb_symbols_t
*symbols
, const VALUE sym
));
103 WARN_UNUSED_RESULT(static ID
lookup_str_id(VALUE str
));
104 WARN_UNUSED_RESULT(static VALUE
lookup_str_sym_with_lock(rb_symbols_t
*symbols
, const VALUE str
));
105 WARN_UNUSED_RESULT(static VALUE
lookup_str_sym(const VALUE str
));
106 WARN_UNUSED_RESULT(static VALUE
lookup_id_str(ID id
));
107 WARN_UNUSED_RESULT(static ID
intern_str(VALUE str
, int mutable));
109 #define GLOBAL_SYMBOLS_ENTER(symbols) rb_symbols_t *symbols = &ruby_global_symbols; RB_VM_LOCK_ENTER()
110 #define GLOBAL_SYMBOLS_LEAVE() RB_VM_LOCK_LEAVE()
118 if (!is_notop_id(id
)) {
120 case tAREF
: case tASET
:
121 return tASET
; /* only exception */
123 rb_name_error(id
, "cannot make operator ID :%"PRIsVALUE
" attrset",
129 case ID_LOCAL
: case ID_INSTANCE
: case ID_GLOBAL
:
130 case ID_CONST
: case ID_CLASS
: case ID_JUNK
:
136 if ((str
= lookup_id_str(id
)) != 0) {
137 rb_name_error(id
, "cannot make unknown type ID %d:%"PRIsVALUE
" attrset",
141 rb_name_error_str(Qnil
, "cannot make unknown type anonymous ID %d:%"PRIxVALUE
" attrset",
148 /* make new symbol and ID */
149 if (!(str
= lookup_id_str(id
))) {
150 static const char id_types
[][8] = {
160 rb_name_error(id
, "cannot make anonymous %.*s ID %"PRIxVALUE
" attrset",
161 (int)sizeof(id_types
[0]), id_types
[scope
], (VALUE
)id
);
163 str
= rb_str_dup(str
);
164 rb_str_cat(str
, "=", 1);
165 sym
= lookup_str_sym(str
);
166 id
= sym
? rb_sym2id(sym
) : intern_str(str
, 1);
171 is_special_global_name(const char *m
, const char *e
, rb_encoding
*enc
)
175 if (m
>= e
) return 0;
176 if (is_global_name_punct(*m
)) {
179 else if (*m
== '-') {
180 if (++m
>= e
) return 0;
181 if (is_identchar(m
, e
, enc
)) {
182 if (!ISASCII(*m
)) mb
= 1;
183 m
+= rb_enc_mbclen(m
, e
, enc
);
187 if (!ISDIGIT(*m
)) return 0;
189 if (!ISASCII(*m
)) mb
= 1;
191 } while (m
< e
&& ISDIGIT(*m
));
193 return m
== e
? mb
+ 1 : 0;
197 rb_symname_p(const char *name
)
199 return rb_enc_symname_p(name
, rb_ascii8bit_encoding());
203 rb_enc_symname_p(const char *name
, rb_encoding
*enc
)
205 return rb_enc_symname2_p(name
, strlen(name
), enc
);
209 rb_sym_constant_char_p(const char *name
, long nlen
, rb_encoding
*enc
)
212 const char *end
= name
+ nlen
;
214 if (nlen
< 1) return FALSE
;
215 if (ISASCII(*name
)) return ISUPPER(*name
);
216 c
= rb_enc_precise_mbclen(name
, end
, enc
);
217 if (!MBCLEN_CHARFOUND_P(c
)) return FALSE
;
218 len
= MBCLEN_CHARFOUND_LEN(c
);
219 c
= rb_enc_mbc_to_codepoint(name
, end
, enc
);
220 if (ONIGENC_IS_UNICODE(enc
)) {
221 static int ctype_titlecase
= 0;
222 if (rb_enc_isupper(c
, enc
)) return TRUE
;
223 if (rb_enc_islower(c
, enc
)) return FALSE
;
224 if (!ctype_titlecase
) {
225 static const UChar cname
[] = "titlecaseletter";
226 static const UChar
*const end
= cname
+ sizeof(cname
) - 1;
227 ctype_titlecase
= ONIGENC_PROPERTY_NAME_TO_CTYPE(enc
, cname
, end
);
229 if (rb_enc_isctype(c
, ctype_titlecase
, enc
)) return TRUE
;
232 /* fallback to case-folding */
233 OnigUChar fold
[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM
];
234 const OnigUChar
*beg
= (const OnigUChar
*)name
;
235 int r
= enc
->mbc_case_fold(ONIGENC_CASE_FOLD
,
236 &beg
, (const OnigUChar
*)end
,
238 if (r
> 0 && (r
!= len
|| memcmp(fold
, name
, r
)))
244 #define IDSET_ATTRSET_FOR_SYNTAX ((1U<<ID_LOCAL)|(1U<<ID_CONST))
245 #define IDSET_ATTRSET_FOR_INTERN (~(~0U<<(1<<ID_SCOPE_SHIFT)) & ~(1U<<ID_ATTRSET))
247 struct enc_synmane_type_leading_chars_tag
{
248 const enum { invalid
, stophere
, needmore
, } kind
;
249 const enum ruby_id_types type
;
253 #define t struct enc_synmane_type_leading_chars_tag
255 static struct enc_synmane_type_leading_chars_tag
256 enc_synmane_type_leading_chars(const char *name
, long len
, rb_encoding
*enc
, int allowed_attrset
)
258 const char *m
= name
;
259 const char *e
= m
+ len
;
261 if (! rb_enc_asciicompat(enc
)) {
262 return (t
) { invalid
, 0, 0, };
265 return (t
) { invalid
, 0, 0, };
267 else if ( len
<= 0 ) {
268 return (t
) { invalid
, 0, 0, };
272 return (t
) { invalid
, 0, 0, };
275 if (is_special_global_name(++m
, e
, enc
)) {
276 return (t
) { stophere
, ID_GLOBAL
, len
, };
279 return (t
) { needmore
, ID_GLOBAL
, 1, };
284 default: return (t
) { needmore
, ID_INSTANCE
, 1, };
285 case '@': return (t
) { needmore
, ID_CLASS
, 2, };
290 default: return (t
) { stophere
, ID_JUNK
, 1, };
291 case '<': return (t
) { stophere
, ID_JUNK
, 2, };
294 default: return (t
) { stophere
, ID_JUNK
, 2, };
295 case '>': return (t
) { stophere
, ID_JUNK
, 3, };
301 default: return (t
) { stophere
, ID_JUNK
, 1, };
302 case '>': case '=': return (t
) { stophere
, ID_JUNK
, 2, };
307 default: return (t
) { invalid
, 0, 1, };
308 case '~': return (t
) { stophere
, ID_JUNK
, 2, };
311 default: return (t
) { stophere
, ID_JUNK
, 2, };
312 case '=': return (t
) { stophere
, ID_JUNK
, 3, };
318 default: return (t
) { stophere
, ID_JUNK
, 1, };
319 case '*': return (t
) { stophere
, ID_JUNK
, 2, };
324 default: return (t
) { stophere
, ID_JUNK
, 1, };
325 case '@': return (t
) { stophere
, ID_JUNK
, 2, };
328 case '|': case '^': case '&': case '/': case '%': case '~': case '`':
329 return (t
) { stophere
, ID_JUNK
, 1, };
333 default: return (t
) { needmore
, ID_JUNK
, 0, };
336 default: return (t
) { stophere
, ID_JUNK
, 2, };
337 case '=': return (t
) { stophere
, ID_JUNK
, 3, };
343 case '=': case '~': return (t
) { stophere
, ID_JUNK
, 2, };
345 if (allowed_attrset
& (1U << ID_JUNK
)) {
346 return (t
) { needmore
, ID_JUNK
, 1, };
349 return (t
) { stophere
, ID_JUNK
, 1, };
354 if (rb_sym_constant_char_p(name
, len
, enc
)) {
355 return (t
) { needmore
, ID_CONST
, 0, };
358 return (t
) { needmore
, ID_LOCAL
, 0, };
365 rb_enc_symname_type(const char *name
, long len
, rb_encoding
*enc
, unsigned int allowed_attrset
)
367 const struct enc_synmane_type_leading_chars_tag f
=
368 enc_synmane_type_leading_chars(name
, len
, enc
, allowed_attrset
);
369 const char *m
= name
+ f
.nread
;
370 const char *e
= name
+ len
;
371 int type
= (int)f
.type
;
374 case invalid
: return -1;
375 case stophere
: break;
378 if (m
>= e
|| (*m
!= '_' && !ISALPHA(*m
) && ISASCII(*m
))) {
379 if (len
> 1 && *(e
-1) == '=') {
380 type
= rb_enc_symname_type(name
, len
-1, enc
, allowed_attrset
);
381 if (type
!= ID_ATTRSET
) return ID_ATTRSET
;
385 while (m
< e
&& is_identchar(m
, e
, enc
)) m
+= rb_enc_mbclen(m
, e
, enc
);
389 if (type
== ID_GLOBAL
|| type
== ID_CLASS
|| type
== ID_INSTANCE
) return -1;
392 if (m
+ 1 < e
|| *m
!= '=') break;
395 if (!(allowed_attrset
& (1U << type
))) return -1;
402 return m
== e
? type
: -1;
406 rb_enc_symname2_p(const char *name
, long len
, rb_encoding
*enc
)
408 return rb_enc_symname_type(name
, len
, enc
, IDSET_ATTRSET_FOR_SYNTAX
) != -1;
412 rb_str_symname_type(VALUE name
, unsigned int allowed_attrset
)
414 const char *ptr
= StringValuePtr(name
);
415 long len
= RSTRING_LEN(name
);
416 int type
= rb_enc_symname_type(ptr
, len
, rb_enc_get(name
), allowed_attrset
);
422 set_id_entry(rb_symbols_t
*symbols
, rb_id_serial_t num
, VALUE str
, VALUE sym
)
425 size_t idx
= num
/ ID_ENTRY_UNIT
;
427 VALUE ary
, ids
= symbols
->ids
;
428 if (idx
>= (size_t)RARRAY_LEN(ids
) || NIL_P(ary
= rb_ary_entry(ids
, (long)idx
))) {
429 ary
= rb_ary_tmp_new(ID_ENTRY_UNIT
* ID_ENTRY_SIZE
);
430 rb_ary_store(ids
, (long)idx
, ary
);
432 idx
= (num
% ID_ENTRY_UNIT
) * ID_ENTRY_SIZE
;
433 rb_ary_store(ary
, (long)idx
+ ID_ENTRY_STR
, str
);
434 rb_ary_store(ary
, (long)idx
+ ID_ENTRY_SYM
, sym
);
438 get_id_serial_entry(rb_id_serial_t num
, ID id
, const enum id_entry_type t
)
442 GLOBAL_SYMBOLS_ENTER(symbols
);
444 if (num
&& num
<= symbols
->last_id
) {
445 size_t idx
= num
/ ID_ENTRY_UNIT
;
446 VALUE ids
= symbols
->ids
;
448 if (idx
< (size_t)RARRAY_LEN(ids
) && !NIL_P(ary
= rb_ary_entry(ids
, (long)idx
))) {
449 long pos
= (long)(num
% ID_ENTRY_UNIT
) * ID_ENTRY_SIZE
;
450 result
= rb_ary_entry(ary
, pos
+ t
);
459 if (t
!= ID_ENTRY_SYM
)
460 sym
= rb_ary_entry(ary
, pos
+ ID_ENTRY_SYM
);
461 if (STATIC_SYM_P(sym
)) {
462 if (STATIC_SYM2ID(sym
) != id
) result
= 0;
465 if (RSYMBOL(sym
)->id
!= id
) result
= 0;
473 GLOBAL_SYMBOLS_LEAVE();
479 get_id_entry(ID id
, const enum id_entry_type t
)
481 return get_id_serial_entry(rb_id_to_serial(id
), id
, t
);
485 rb_id_serial_to_id(rb_id_serial_t num
)
487 if (is_notop_id((ID
)num
)) {
488 VALUE sym
= get_id_serial_entry(num
, 0, ID_ENTRY_SYM
);
489 if (sym
) return SYM2ID(sym
);
490 return ((ID
)num
<< ID_SCOPE_SHIFT
) | ID_INTERNAL
| ID_STATIC_SYM
;
499 register_sym_update_callback(st_data_t
*key
, st_data_t
*value
, st_data_t arg
, int existing
)
502 rb_fatal("symbol :% "PRIsVALUE
" is already registered with %"PRIxVALUE
,
503 (VALUE
)*key
, (VALUE
)*value
);
511 register_sym(rb_symbols_t
*symbols
, VALUE str
, VALUE sym
)
516 st_update(symbols
->str_sym
, (st_data_t
)str
,
517 register_sym_update_callback
, (st_data_t
)sym
);
519 st_add_direct(symbols
->str_sym
, (st_data_t
)str
, (st_data_t
)sym
);
524 unregister_sym(rb_symbols_t
*symbols
, VALUE str
, VALUE sym
)
528 st_data_t str_data
= (st_data_t
)str
;
529 if (!st_delete(symbols
->str_sym
, &str_data
, NULL
)) {
530 rb_bug("%p can't remove str from str_id (%s)", (void *)sym
, RSTRING_PTR(str
));
535 register_static_symid(ID id
, const char *name
, long len
, rb_encoding
*enc
)
537 VALUE str
= rb_enc_str_new(name
, len
, enc
);
538 return register_static_symid_str(id
, str
);
542 register_static_symid_str(ID id
, VALUE str
)
544 rb_id_serial_t num
= rb_id_to_serial(id
);
545 VALUE sym
= STATIC_ID2SYM(id
);
548 str
= rb_fstring(str
);
550 RUBY_DTRACE_CREATE_HOOK(SYMBOL
, RSTRING_PTR(str
));
552 GLOBAL_SYMBOLS_ENTER(symbols
)
554 register_sym(symbols
, str
, sym
);
555 set_id_entry(symbols
, num
, str
, sym
);
557 GLOBAL_SYMBOLS_LEAVE();
563 sym_check_asciionly(VALUE str
)
565 if (!rb_enc_asciicompat(rb_enc_get(str
))) return FALSE
;
566 switch (rb_enc_str_coderange(str
)) {
567 case ENC_CODERANGE_BROKEN
:
568 rb_raise(rb_eEncodingError
, "invalid symbol in encoding %s :%+"PRIsVALUE
,
569 rb_enc_name(rb_enc_get(str
)), str
);
570 case ENC_CODERANGE_7BIT
:
578 * _str_ itself will be registered at the global symbol table. _str_
579 * can be modified before the registration, since the encoding will be
580 * set to ASCII-8BIT if it is a special global name.
584 must_be_dynamic_symbol(VALUE x
)
586 if (UNLIKELY(!DYNAMIC_SYM_P(x
))) {
587 if (STATIC_SYM_P(x
)) {
588 VALUE str
= lookup_id_str(RSHIFT((unsigned long)(x
),RUBY_SPECIAL_SHIFT
));
591 rb_bug("wrong argument: %s (inappropriate Symbol)", RSTRING_PTR(str
));
594 rb_bug("wrong argument: inappropriate Symbol (%p)", (void *)x
);
598 rb_bug("wrong argument type %s (expected Symbol)", rb_builtin_class_name(x
));
605 dsymbol_alloc(rb_symbols_t
*symbols
, const VALUE klass
, const VALUE str
, rb_encoding
* const enc
, const ID type
)
609 const VALUE dsym
= rb_newobj_of(klass
, T_SYMBOL
| FL_WB_PROTECTED
);
612 rb_enc_set_index(dsym
, rb_enc_to_index(enc
));
614 RB_OBJ_WRITE(dsym
, &RSYMBOL(dsym
)->fstr
, str
);
615 RSYMBOL(dsym
)->id
= type
;
617 /* we want hashval to be in Fixnum range [ruby-core:15713] r15672 */
618 hashval
= (long)rb_str_hash(str
);
619 RSYMBOL(dsym
)->hashval
= RSHIFT((long)hashval
, 1);
620 register_sym(symbols
, str
, dsym
);
621 rb_hash_aset(symbols
->dsymbol_fstr_hash
, str
, Qtrue
);
622 RUBY_DTRACE_CREATE_HOOK(SYMBOL
, RSTRING_PTR(RSYMBOL(dsym
)->fstr
));
628 dsymbol_check(rb_symbols_t
*symbols
, const VALUE sym
)
632 if (UNLIKELY(rb_objspace_garbage_object_p(sym
))) {
633 const VALUE fstr
= RSYMBOL(sym
)->fstr
;
634 const ID type
= RSYMBOL(sym
)->id
& ID_SCOPE_MASK
;
635 RSYMBOL(sym
)->fstr
= 0;
636 unregister_sym(symbols
, fstr
, sym
);
637 return dsymbol_alloc(symbols
, rb_cSymbol
, fstr
, rb_enc_get(fstr
), type
);
645 lookup_str_id(VALUE str
)
650 GLOBAL_SYMBOLS_ENTER(symbols
);
652 found
= st_lookup(symbols
->str_sym
, (st_data_t
)str
, &sym_data
);
654 GLOBAL_SYMBOLS_LEAVE();
657 const VALUE sym
= (VALUE
)sym_data
;
659 if (STATIC_SYM_P(sym
)) {
660 return STATIC_SYM2ID(sym
);
662 else if (DYNAMIC_SYM_P(sym
)) {
663 ID id
= RSYMBOL(sym
)->id
;
664 if (id
& ~ID_SCOPE_MASK
) return id
;
667 rb_bug("non-symbol object %s:%"PRIxVALUE
" for %"PRIsVALUE
" in symbol table",
668 rb_builtin_class_name(sym
), sym
, str
);
675 lookup_str_sym_with_lock(rb_symbols_t
*symbols
, const VALUE str
)
678 if (st_lookup(symbols
->str_sym
, (st_data_t
)str
, &sym_data
)) {
679 VALUE sym
= (VALUE
)sym_data
;
680 if (DYNAMIC_SYM_P(sym
)) {
681 sym
= dsymbol_check(symbols
, sym
);
691 lookup_str_sym(const VALUE str
)
695 GLOBAL_SYMBOLS_ENTER(symbols
);
697 sym
= lookup_str_sym_with_lock(symbols
, str
);
699 GLOBAL_SYMBOLS_LEAVE();
707 return get_id_entry(id
, ID_ENTRY_STR
);
711 rb_intern3(const char *name
, long len
, rb_encoding
*enc
)
714 struct RString fake_str
;
715 VALUE str
= rb_setup_fake_str(&fake_str
, name
, len
, enc
);
717 sym
= lookup_str_sym(str
);
718 if (sym
) return rb_sym2id(sym
);
719 str
= rb_enc_str_new(name
, len
, enc
); /* make true string */
720 return intern_str(str
, 1);
724 next_id_base_with_lock(rb_symbols_t
*symbols
)
727 rb_id_serial_t next_serial
= symbols
->last_id
+ 1;
729 if (next_serial
== 0) {
733 const size_t num
= ++symbols
->last_id
;
734 id
= num
<< ID_SCOPE_SHIFT
;
744 GLOBAL_SYMBOLS_ENTER(symbols
);
746 id
= next_id_base_with_lock(symbols
);
748 GLOBAL_SYMBOLS_LEAVE();
753 intern_str(VALUE str
, int mutable)
758 id
= rb_str_symname_type(str
, IDSET_ATTRSET_FOR_INTERN
);
759 if (id
== (ID
)-1) id
= ID_JUNK
;
760 if (sym_check_asciionly(str
)) {
761 if (!mutable) str
= rb_str_dup(str
);
762 rb_enc_associate(str
, rb_usascii_encoding());
764 if ((nid
= next_id_base()) == (ID
)-1) {
765 str
= rb_str_ellipsize(str
, 20);
766 rb_raise(rb_eRuntimeError
, "symbol table overflow (symbol %"PRIsVALUE
")",
771 return register_static_symid_str(id
, str
);
775 rb_intern2(const char *name
, long len
)
777 return rb_intern3(name
, len
, rb_usascii_encoding());
782 rb_intern(const char *name
)
784 return rb_intern2(name
, strlen(name
));
788 rb_intern_str(VALUE str
)
790 VALUE sym
= lookup_str_sym(str
);
796 return intern_str(str
, 0);
800 rb_gc_free_dsymbol(VALUE sym
)
802 VALUE str
= RSYMBOL(sym
)->fstr
;
805 RSYMBOL(sym
)->fstr
= 0;
807 GLOBAL_SYMBOLS_ENTER(symbols
);
809 unregister_sym(symbols
, str
, sym
);
810 rb_hash_delete_entry(symbols
->dsymbol_fstr_hash
, str
);
812 GLOBAL_SYMBOLS_LEAVE();
818 * str.intern -> symbol
819 * str.to_sym -> symbol
821 * Returns the Symbol corresponding to <i>str</i>, creating the
822 * symbol if it did not previously exist. See Symbol#id2name.
824 * "Koala".intern #=> :Koala
825 * s = 'cat'.to_sym #=> :cat
827 * s = '@cat'.to_sym #=> :@cat
828 * s == :@cat #=> true
830 * This can also be used to create symbols that cannot be represented using the
831 * <code>:xxx</code> notation.
833 * 'cat and dog'.to_sym #=> :"cat and dog"
837 rb_str_intern(VALUE str
)
841 rb_encoding
*enc
, *ascii
;
846 GLOBAL_SYMBOLS_ENTER(symbols
);
848 sym
= lookup_str_sym_with_lock(symbols
, str
);
855 enc
= rb_enc_get(str
);
856 ascii
= rb_usascii_encoding();
857 if (enc
!= ascii
&& sym_check_asciionly(str
)) {
858 str
= rb_str_dup(str
);
859 rb_enc_associate(str
, ascii
);
864 str
= rb_str_dup(str
);
867 str
= rb_fstring(str
);
868 type
= rb_str_symname_type(str
, IDSET_ATTRSET_FOR_INTERN
);
869 if (type
< 0) type
= ID_JUNK
;
870 sym
= dsymbol_alloc(symbols
, rb_cSymbol
, str
, enc
, type
);
872 id
= intern_str(str
, 0);
877 GLOBAL_SYMBOLS_LEAVE();
885 if (STATIC_SYM_P(sym
)) {
886 id
= STATIC_SYM2ID(sym
);
888 else if (DYNAMIC_SYM_P(sym
)) {
889 GLOBAL_SYMBOLS_ENTER(symbols
);
891 sym
= dsymbol_check(symbols
, sym
);
892 id
= RSYMBOL(sym
)->id
;
894 if (UNLIKELY(!(id
& ~ID_SCOPE_MASK
))) {
895 VALUE fstr
= RSYMBOL(sym
)->fstr
;
896 ID num
= next_id_base_with_lock(symbols
);
898 RSYMBOL(sym
)->id
= id
|= num
;
899 /* make it permanent object */
901 set_id_entry(symbols
, rb_id_to_serial(num
), fstr
, sym
);
902 rb_hash_delete_entry(symbols
->dsymbol_fstr_hash
, fstr
);
905 GLOBAL_SYMBOLS_LEAVE();
908 rb_raise(rb_eTypeError
, "wrong argument type %s (expected Symbol)",
909 rb_builtin_class_name(sym
));
918 if (!DYNAMIC_ID_P(x
)) return STATIC_ID2SYM(x
);
919 return get_id_entry(x
, ID_ENTRY_SYM
);
924 rb_sym2str(VALUE sym
)
926 if (DYNAMIC_SYM_P(sym
)) {
927 return RSYMBOL(sym
)->fstr
;
930 return rb_id2str(STATIC_SYM2ID(sym
));
937 return lookup_id_str(id
);
943 VALUE str
= rb_id2str(id
);
946 return RSTRING_PTR(str
);
950 rb_make_internal_id(void)
952 return next_id_base() | ID_INTERNAL
| ID_STATIC_SYM
;
956 rb_make_temporary_id(size_t n
)
958 const ID max_id
= RB_ID_SERIAL_MAX
& ~0xffff;
959 const ID id
= max_id
- (ID
)n
;
960 if (id
<= ruby_global_symbols
.last_id
) {
961 rb_raise(rb_eRuntimeError
, "too big to make temporary ID: %" PRIdSIZE
, n
);
963 return (id
<< ID_SCOPE_SHIFT
) | ID_STATIC_SYM
| ID_INTERNAL
;
967 symbols_i(st_data_t key
, st_data_t value
, st_data_t arg
)
969 VALUE ary
= (VALUE
)arg
;
970 VALUE sym
= (VALUE
)value
;
972 if (STATIC_SYM_P(sym
)) {
973 rb_ary_push(ary
, sym
);
976 else if (!DYNAMIC_SYM_P(sym
)) {
977 rb_bug("invalid symbol: %s", RSTRING_PTR((VALUE
)key
));
979 else if (!SYMBOL_PINNED_P(sym
) && rb_objspace_garbage_object_p(sym
)) {
980 RSYMBOL(sym
)->fstr
= 0;
984 rb_ary_push(ary
, sym
);
991 rb_sym_all_symbols(void)
995 GLOBAL_SYMBOLS_ENTER(symbols
);
997 ary
= rb_ary_new2(symbols
->str_sym
->num_entries
);
998 st_foreach(symbols
->str_sym
, symbols_i
, ary
);
1000 GLOBAL_SYMBOLS_LEAVE();
1006 rb_sym_immortal_count(void)
1008 return (size_t)ruby_global_symbols
.last_id
;
1012 rb_is_const_id(ID id
)
1014 return is_const_id(id
);
1018 rb_is_class_id(ID id
)
1020 return is_class_id(id
);
1024 rb_is_global_id(ID id
)
1026 return is_global_id(id
);
1030 rb_is_instance_id(ID id
)
1032 return is_instance_id(id
);
1036 rb_is_attrset_id(ID id
)
1038 return is_attrset_id(id
);
1042 rb_is_local_id(ID id
)
1044 return is_local_id(id
);
1048 rb_is_junk_id(ID id
)
1050 return is_junk_id(id
);
1054 rb_is_const_sym(VALUE sym
)
1056 return is_const_sym(sym
);
1060 rb_is_attrset_sym(VALUE sym
)
1062 return is_attrset_sym(sym
);
1066 rb_check_id(volatile VALUE
*namep
)
1069 VALUE name
= *namep
;
1071 if (STATIC_SYM_P(name
)) {
1072 return STATIC_SYM2ID(name
);
1074 else if (DYNAMIC_SYM_P(name
)) {
1075 if (SYMBOL_PINNED_P(name
)) {
1076 return RSYMBOL(name
)->id
;
1079 *namep
= RSYMBOL(name
)->fstr
;
1083 else if (!RB_TYPE_P(name
, T_STRING
)) {
1084 tmp
= rb_check_string_type(name
);
1086 rb_raise(rb_eTypeError
, "%+"PRIsVALUE
" is not a symbol nor a string",
1093 sym_check_asciionly(name
);
1095 return lookup_str_id(name
);
1099 rb_check_symbol(volatile VALUE
*namep
)
1103 VALUE name
= *namep
;
1105 if (STATIC_SYM_P(name
)) {
1108 else if (DYNAMIC_SYM_P(name
)) {
1109 if (!SYMBOL_PINNED_P(name
)) {
1110 GLOBAL_SYMBOLS_ENTER(symbols
);
1112 name
= dsymbol_check(symbols
, name
);
1114 GLOBAL_SYMBOLS_LEAVE();
1120 else if (!RB_TYPE_P(name
, T_STRING
)) {
1121 tmp
= rb_check_string_type(name
);
1123 rb_raise(rb_eTypeError
, "%+"PRIsVALUE
" is not a symbol nor a string",
1130 sym_check_asciionly(name
);
1132 if ((sym
= lookup_str_sym(name
)) != 0) {
1140 rb_check_id_cstr(const char *ptr
, long len
, rb_encoding
*enc
)
1142 struct RString fake_str
;
1143 const VALUE name
= rb_setup_fake_str(&fake_str
, ptr
, len
, enc
);
1145 sym_check_asciionly(name
);
1147 return lookup_str_id(name
);
1151 rb_check_symbol_cstr(const char *ptr
, long len
, rb_encoding
*enc
)
1154 struct RString fake_str
;
1155 const VALUE name
= rb_setup_fake_str(&fake_str
, ptr
, len
, enc
);
1157 sym_check_asciionly(name
);
1159 if ((sym
= lookup_str_sym(name
)) != 0) {
1166 #undef rb_sym_intern_ascii_cstr
1168 NOINLINE(VALUE
rb_sym_intern(const char *ptr
, long len
, rb_encoding
*enc
));
1170 FUNC_MINIMIZED(VALUE
rb_sym_intern(const char *ptr
, long len
, rb_encoding
*enc
));
1171 FUNC_MINIMIZED(VALUE
rb_sym_intern_ascii(const char *ptr
, long len
));
1172 FUNC_MINIMIZED(VALUE
rb_sym_intern_ascii_cstr(const char *ptr
));
1176 rb_sym_intern(const char *ptr
, long len
, rb_encoding
*enc
)
1178 struct RString fake_str
;
1179 const VALUE name
= rb_setup_fake_str(&fake_str
, ptr
, len
, enc
);
1180 return rb_str_intern(name
);
1184 rb_sym_intern_ascii(const char *ptr
, long len
)
1186 return rb_sym_intern(ptr
, len
, rb_usascii_encoding());
1190 rb_sym_intern_ascii_cstr(const char *ptr
)
1192 return rb_sym_intern_ascii(ptr
, strlen(ptr
));
1196 rb_to_symbol_type(VALUE obj
)
1198 return rb_convert_type_with_id(obj
, T_SYMBOL
, "Symbol", idTo_sym
);
1202 rb_is_const_name(VALUE name
)
1204 return rb_str_symname_type(name
, 0) == ID_CONST
;
1208 rb_is_class_name(VALUE name
)
1210 return rb_str_symname_type(name
, 0) == ID_CLASS
;
1214 rb_is_instance_name(VALUE name
)
1216 return rb_str_symname_type(name
, 0) == ID_INSTANCE
;
1220 rb_is_local_name(VALUE name
)
1222 return rb_str_symname_type(name
, 0) == ID_LOCAL
;
1225 #include "id_table.c"