Ruby 3.5.0dev (2025-02-20 revision 34098b669c0cbc024cd08e686891f1dfe0a10aaf)
symbol.c (34098b669c0cbc024cd08e686891f1dfe0a10aaf)
1/**********************************************************************
2
3 symbol.h -
4
5 $Author$
6 created at: Tue Jul 8 15:49:54 JST 2014
7
8 Copyright (C) 2014 Yukihiro Matsumoto
9
10**********************************************************************/
11
12#include "internal.h"
13#include "internal/error.h"
14#include "internal/gc.h"
15#include "internal/hash.h"
16#include "internal/object.h"
17#include "internal/symbol.h"
18#include "internal/vm.h"
19#include "probes.h"
20#include "ruby/encoding.h"
21#include "ruby/st.h"
22#include "symbol.h"
23#include "vm_sync.h"
24#include "builtin.h"
25
26#if defined(USE_SYMBOL_GC) && !(USE_SYMBOL_GC+0)
27# undef USE_SYMBOL_GC
28# define USE_SYMBOL_GC 0
29#else
30# undef USE_SYMBOL_GC
31# define USE_SYMBOL_GC 1
32#endif
33#if defined(SYMBOL_DEBUG) && (SYMBOL_DEBUG+0)
34# undef SYMBOL_DEBUG
35# define SYMBOL_DEBUG 1
36#else
37# undef SYMBOL_DEBUG
38# define SYMBOL_DEBUG 0
39#endif
40#ifndef CHECK_ID_SERIAL
41# define CHECK_ID_SERIAL SYMBOL_DEBUG
42#endif
43
44#define SYMBOL_PINNED_P(sym) (RSYMBOL(sym)->id&~ID_SCOPE_MASK)
45
46#define STATIC_SYM2ID(sym) RSHIFT((VALUE)(sym), RUBY_SPECIAL_SHIFT)
47
48static ID register_static_symid(ID, const char *, long, rb_encoding *);
49static ID register_static_symid_str(ID, VALUE);
50#define REGISTER_SYMID(id, name) register_static_symid((id), (name), strlen(name), enc)
51#include "id.c"
52
53#define is_identchar(p,e,enc) (ISALNUM((unsigned char)*(p)) || (*(p)) == '_' || !ISASCII(*(p)))
54
55#define op_tbl_count numberof(op_tbl)
56STATIC_ASSERT(op_tbl_name_size, sizeof(op_tbl[0].name) == 3);
57#define op_tbl_len(i) (!op_tbl[i].name[1] ? 1 : !op_tbl[i].name[2] ? 2 : 3)
58
59static void
60Init_op_tbl(void)
61{
62 int i;
63 rb_encoding *const enc = rb_usascii_encoding();
64
65 for (i = '!'; i <= '~'; ++i) {
66 if (!ISALNUM(i) && i != '_') {
67 char c = (char)i;
68 register_static_symid(i, &c, 1, enc);
69 }
70 }
71 for (i = 0; i < op_tbl_count; ++i) {
72 register_static_symid(op_tbl[i].token, op_tbl[i].name, op_tbl_len(i), enc);
73 }
74}
75
76static const int ID_ENTRY_UNIT = 512;
77
78enum id_entry_type {
79 ID_ENTRY_STR,
80 ID_ENTRY_SYM,
81 ID_ENTRY_SIZE
82};
83
84rb_symbols_t ruby_global_symbols = {tNEXT_ID-1};
85
86static const struct st_hash_type symhash = {
89};
90
91void
92Init_sym(void)
93{
94 rb_symbols_t *symbols = &ruby_global_symbols;
95
96 VALUE dsym_fstrs = rb_ident_hash_new();
97 symbols->dsymbol_fstr_hash = dsym_fstrs;
98 rb_obj_hide(dsym_fstrs);
99
100 symbols->str_sym = st_init_table_with_size(&symhash, 1000);
101 symbols->ids = rb_ary_hidden_new(0);
102
103 Init_op_tbl();
104 Init_id();
105}
106
107void
108rb_sym_global_symbols_mark(void)
109{
110 rb_symbols_t *symbols = &ruby_global_symbols;
111
112 rb_gc_mark_movable(symbols->ids);
113 rb_gc_mark_movable(symbols->dsymbol_fstr_hash);
114}
115
116void
117rb_sym_global_symbols_update_references(void)
118{
119 rb_symbols_t *symbols = &ruby_global_symbols;
120
121 symbols->ids = rb_gc_location(symbols->ids);
122 symbols->dsymbol_fstr_hash = rb_gc_location(symbols->dsymbol_fstr_hash);
123}
124
125WARN_UNUSED_RESULT(static VALUE dsymbol_alloc(rb_symbols_t *symbols, const VALUE klass, const VALUE str, rb_encoding *const enc, const ID type));
126WARN_UNUSED_RESULT(static VALUE dsymbol_check(rb_symbols_t *symbols, const VALUE sym));
127WARN_UNUSED_RESULT(static ID lookup_str_id(VALUE str));
128WARN_UNUSED_RESULT(static VALUE lookup_str_sym_with_lock(rb_symbols_t *symbols, const VALUE str));
129WARN_UNUSED_RESULT(static VALUE lookup_str_sym(const VALUE str));
130WARN_UNUSED_RESULT(static VALUE lookup_id_str(ID id));
131WARN_UNUSED_RESULT(static ID intern_str(VALUE str, int mutable));
132
133#define GLOBAL_SYMBOLS_ENTER(symbols) rb_symbols_t *symbols = &ruby_global_symbols; RB_VM_LOCK_ENTER()
134#define GLOBAL_SYMBOLS_LEAVE() RB_VM_LOCK_LEAVE()
135
136ID
137rb_id_attrset(ID id)
138{
139 VALUE str, sym;
140 int scope;
141
142 if (!is_notop_id(id)) {
143 switch (id) {
144 case tAREF: case tASET:
145 return tASET; /* only exception */
146 }
147 rb_name_error(id, "cannot make operator ID :%"PRIsVALUE" attrset",
148 rb_id2str(id));
149 }
150 else {
151 scope = id_type(id);
152 switch (scope) {
153 case ID_LOCAL: case ID_INSTANCE: case ID_GLOBAL:
154 case ID_CONST: case ID_CLASS: case ID_JUNK:
155 break;
156 case ID_ATTRSET:
157 return id;
158 default:
159 {
160 if ((str = lookup_id_str(id)) != 0) {
161 rb_name_error(id, "cannot make unknown type ID %d:%"PRIsVALUE" attrset",
162 scope, str);
163 }
164 else {
165 rb_name_error_str(Qnil, "cannot make unknown type anonymous ID %d:%"PRIxVALUE" attrset",
166 scope, (VALUE)id);
167 }
168 }
169 }
170 }
171
172 /* make new symbol and ID */
173 if (!(str = lookup_id_str(id))) {
174 static const char id_types[][8] = {
175 "local",
176 "instance",
177 "invalid",
178 "global",
179 "attrset",
180 "const",
181 "class",
182 "junk",
183 };
184 rb_name_error(id, "cannot make anonymous %.*s ID %"PRIxVALUE" attrset",
185 (int)sizeof(id_types[0]), id_types[scope], (VALUE)id);
186 }
187 str = rb_str_dup(str);
188 rb_str_cat(str, "=", 1);
189 sym = lookup_str_sym(str);
190 id = sym ? rb_sym2id(sym) : intern_str(str, 1);
191 return id;
192}
193
194static int
195is_special_global_name(const char *m, const char *e, rb_encoding *enc)
196{
197 int mb = 0;
198
199 if (m >= e) return 0;
200 if (is_global_name_punct(*m)) {
201 ++m;
202 }
203 else if (*m == '-') {
204 if (++m >= e) return 0;
205 if (is_identchar(m, e, enc)) {
206 if (!ISASCII(*m)) mb = 1;
207 m += rb_enc_mbclen(m, e, enc);
208 }
209 }
210 else {
211 if (!ISDIGIT(*m)) return 0;
212 do {
213 if (!ISASCII(*m)) mb = 1;
214 ++m;
215 } while (m < e && ISDIGIT(*m));
216 }
217 return m == e ? mb + 1 : 0;
218}
219
220int
221rb_symname_p(const char *name)
222{
223 return rb_enc_symname_p(name, rb_ascii8bit_encoding());
224}
225
226int
227rb_enc_symname_p(const char *name, rb_encoding *enc)
228{
229 return rb_enc_symname2_p(name, strlen(name), enc);
230}
231
232static int
233rb_sym_constant_char_p(const char *name, long nlen, rb_encoding *enc)
234{
235 int c, len;
236 const char *end = name + nlen;
237
238 if (nlen < 1) return FALSE;
239 if (ISASCII(*name)) return ISUPPER(*name);
240 c = rb_enc_precise_mbclen(name, end, enc);
241 if (!MBCLEN_CHARFOUND_P(c)) return FALSE;
243 c = rb_enc_mbc_to_codepoint(name, end, enc);
244 if (rb_enc_isupper(c, enc)) return TRUE;
245 if (rb_enc_islower(c, enc)) return FALSE;
246 if (ONIGENC_IS_UNICODE(enc)) {
247 static int ctype_titlecase = 0;
248 if (!ctype_titlecase) {
249 static const UChar cname[] = "titlecaseletter";
250 static const UChar *const end = cname + sizeof(cname) - 1;
251 ctype_titlecase = ONIGENC_PROPERTY_NAME_TO_CTYPE(enc, cname, end);
252 }
253 if (rb_enc_isctype(c, ctype_titlecase, enc)) return TRUE;
254 }
255 else {
256 /* fallback to case-folding */
257 OnigUChar fold[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM];
258 const OnigUChar *beg = (const OnigUChar *)name;
259 int r = enc->mbc_case_fold(ONIGENC_CASE_FOLD,
260 &beg, (const OnigUChar *)end,
261 fold, enc);
262 if (r > 0 && (r != len || memcmp(fold, name, r)))
263 return TRUE;
264 }
265 return FALSE;
266}
267
268#define IDSET_ATTRSET_FOR_SYNTAX ((1U<<ID_LOCAL)|(1U<<ID_CONST))
269#define IDSET_ATTRSET_FOR_INTERN (~(~0U<<(1<<ID_SCOPE_SHIFT)) & ~(1U<<ID_ATTRSET))
270
272 const enum { invalid, stophere, needmore, } kind;
273 const enum ruby_id_types type;
274 const long nread;
275};
276
277#define t struct enc_synmane_type_leading_chars_tag
278
280enc_synmane_type_leading_chars(const char *name, long len, rb_encoding *enc, int allowed_attrset)
281{
282 const char *m = name;
283 const char *e = m + len;
284
285 if (! rb_enc_asciicompat(enc)) {
286 return (t) { invalid, 0, 0, };
287 }
288 else if (! m) {
289 return (t) { invalid, 0, 0, };
290 }
291 else if ( len <= 0 ) {
292 return (t) { invalid, 0, 0, };
293 }
294 switch (*m) {
295 case '\0':
296 return (t) { invalid, 0, 0, };
297
298 case '$':
299 if (is_special_global_name(++m, e, enc)) {
300 return (t) { stophere, ID_GLOBAL, len, };
301 }
302 else {
303 return (t) { needmore, ID_GLOBAL, 1, };
304 }
305
306 case '@':
307 switch (*++m) {
308 default: return (t) { needmore, ID_INSTANCE, 1, };
309 case '@': return (t) { needmore, ID_CLASS, 2, };
310 }
311
312 case '<':
313 switch (*++m) {
314 default: return (t) { stophere, ID_JUNK, 1, };
315 case '<': return (t) { stophere, ID_JUNK, 2, };
316 case '=':
317 switch (*++m) {
318 default: return (t) { stophere, ID_JUNK, 2, };
319 case '>': return (t) { stophere, ID_JUNK, 3, };
320 }
321 }
322
323 case '>':
324 switch (*++m) {
325 default: return (t) { stophere, ID_JUNK, 1, };
326 case '>': case '=': return (t) { stophere, ID_JUNK, 2, };
327 }
328
329 case '=':
330 switch (*++m) {
331 default: return (t) { invalid, 0, 1, };
332 case '~': return (t) { stophere, ID_JUNK, 2, };
333 case '=':
334 switch (*++m) {
335 default: return (t) { stophere, ID_JUNK, 2, };
336 case '=': return (t) { stophere, ID_JUNK, 3, };
337 }
338 }
339
340 case '*':
341 switch (*++m) {
342 default: return (t) { stophere, ID_JUNK, 1, };
343 case '*': return (t) { stophere, ID_JUNK, 2, };
344 }
345
346 case '+': case '-':
347 switch (*++m) {
348 default: return (t) { stophere, ID_JUNK, 1, };
349 case '@': return (t) { stophere, ID_JUNK, 2, };
350 }
351
352 case '|': case '^': case '&': case '/': case '%': case '~': case '`':
353 return (t) { stophere, ID_JUNK, 1, };
354
355 case '[':
356 switch (*++m) {
357 default: return (t) { needmore, ID_JUNK, 0, };
358 case ']':
359 switch (*++m) {
360 default: return (t) { stophere, ID_JUNK, 2, };
361 case '=': return (t) { stophere, ID_JUNK, 3, };
362 }
363 }
364
365 case '!':
366 switch (*++m) {
367 case '=': case '~': return (t) { stophere, ID_JUNK, 2, };
368 default:
369 if (allowed_attrset & (1U << ID_JUNK)) {
370 return (t) { needmore, ID_JUNK, 1, };
371 }
372 else {
373 return (t) { stophere, ID_JUNK, 1, };
374 }
375 }
376
377 default:
378 if (rb_sym_constant_char_p(name, len, enc)) {
379 return (t) { needmore, ID_CONST, 0, };
380 }
381 else {
382 return (t) { needmore, ID_LOCAL, 0, };
383 }
384 }
385}
386#undef t
387
388int
389rb_enc_symname_type(const char *name, long len, rb_encoding *enc, unsigned int allowed_attrset)
390{
392 enc_synmane_type_leading_chars(name, len, enc, allowed_attrset);
393 const char *m = name + f.nread;
394 const char *e = name + len;
395 int type = (int)f.type;
396
397 switch (f.kind) {
398 case invalid: return -1;
399 case stophere: break;
400 case needmore:
401
402 if (m >= e || (*m != '_' && !ISALPHA(*m) && ISASCII(*m))) {
403 if (len > 1 && *(e-1) == '=') {
404 type = rb_enc_symname_type(name, len-1, enc, allowed_attrset);
405 if (allowed_attrset & (1U << type)) return ID_ATTRSET;
406 }
407 return -1;
408 }
409 while (m < e && is_identchar(m, e, enc)) m += rb_enc_mbclen(m, e, enc);
410 if (m >= e) break;
411 switch (*m) {
412 case '!': case '?':
413 if (type == ID_GLOBAL || type == ID_CLASS || type == ID_INSTANCE) return -1;
414 type = ID_JUNK;
415 ++m;
416 if (m + 1 < e || *m != '=') break;
417 /* fall through */
418 case '=':
419 if (!(allowed_attrset & (1U << type))) return -1;
420 type = ID_ATTRSET;
421 ++m;
422 break;
423 }
424 }
425
426 return m == e ? type : -1;
427}
428
429int
430rb_enc_symname2_p(const char *name, long len, rb_encoding *enc)
431{
432 return rb_enc_symname_type(name, len, enc, IDSET_ATTRSET_FOR_SYNTAX) != -1;
433}
434
435static int
436rb_str_symname_type(VALUE name, unsigned int allowed_attrset)
437{
438 const char *ptr = StringValuePtr(name);
439 long len = RSTRING_LEN(name);
440 int type = rb_enc_symname_type(ptr, len, rb_enc_get(name), allowed_attrset);
441 RB_GC_GUARD(name);
442 return type;
443}
444
445static void
446set_id_entry(rb_symbols_t *symbols, rb_id_serial_t num, VALUE str, VALUE sym)
447{
448 ASSERT_vm_locking();
451
452 size_t idx = num / ID_ENTRY_UNIT;
453
454 VALUE ary, ids = symbols->ids;
455 if (idx >= (size_t)RARRAY_LEN(ids) || NIL_P(ary = rb_ary_entry(ids, (long)idx))) {
456 ary = rb_ary_hidden_new(ID_ENTRY_UNIT * ID_ENTRY_SIZE);
457 rb_ary_store(ids, (long)idx, ary);
458 }
459 idx = (num % ID_ENTRY_UNIT) * ID_ENTRY_SIZE;
460 rb_ary_store(ary, (long)idx + ID_ENTRY_STR, str);
461 rb_ary_store(ary, (long)idx + ID_ENTRY_SYM, sym);
462}
463
464static VALUE
465get_id_serial_entry(rb_id_serial_t num, ID id, const enum id_entry_type t)
466{
467 VALUE result = 0;
468
469 GLOBAL_SYMBOLS_ENTER(symbols);
470 {
471 if (num && num <= symbols->last_id) {
472 size_t idx = num / ID_ENTRY_UNIT;
473 VALUE ids = symbols->ids;
474 VALUE ary;
475 if (idx < (size_t)RARRAY_LEN(ids) && !NIL_P(ary = rb_ary_entry(ids, (long)idx))) {
476 long pos = (long)(num % ID_ENTRY_UNIT) * ID_ENTRY_SIZE;
477 result = rb_ary_entry(ary, pos + t);
478
479 if (NIL_P(result)) {
480 result = 0;
481 }
482 else if (CHECK_ID_SERIAL) {
483 if (id) {
484 VALUE sym = result;
485 if (t != ID_ENTRY_SYM)
486 sym = rb_ary_entry(ary, pos + ID_ENTRY_SYM);
487 if (STATIC_SYM_P(sym)) {
488 if (STATIC_SYM2ID(sym) != id) result = 0;
489 }
490 else {
491 if (RSYMBOL(sym)->id != id) result = 0;
492 }
493 }
494 }
495 }
496 }
497 }
498 GLOBAL_SYMBOLS_LEAVE();
499
500 if (result) {
501 switch (t) {
502 case ID_ENTRY_STR:
504 break;
505 case ID_ENTRY_SYM:
507 break;
508 default:
509 break;
510 }
511 }
512
513 return result;
514}
515
516static VALUE
517get_id_entry(ID id, const enum id_entry_type t)
518{
519 return get_id_serial_entry(rb_id_to_serial(id), id, t);
520}
521
522int
523rb_static_id_valid_p(ID id)
524{
525 return STATIC_ID2SYM(id) == get_id_entry(id, ID_ENTRY_SYM);
526}
527
528static inline ID
529rb_id_serial_to_id(rb_id_serial_t num)
530{
531 if (is_notop_id((ID)num)) {
532 VALUE sym = get_id_serial_entry(num, 0, ID_ENTRY_SYM);
533 if (sym) return SYM2ID(sym);
534 return ((ID)num << ID_SCOPE_SHIFT) | ID_INTERNAL | ID_STATIC_SYM;
535 }
536 else {
537 return (ID)num;
538 }
539}
540
541static int
542register_sym_update_callback(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
543{
544 if (existing) {
545 rb_fatal("symbol :% "PRIsVALUE" is already registered with %"PRIxVALUE,
546 (VALUE)*key, (VALUE)*value);
547 }
548 *value = arg;
549 return ST_CONTINUE;
550}
551
552static void
553register_sym(rb_symbols_t *symbols, VALUE str, VALUE sym)
554{
555 ASSERT_vm_locking();
556
557 if (SYMBOL_DEBUG) {
558 st_update(symbols->str_sym, (st_data_t)str,
559 register_sym_update_callback, (st_data_t)sym);
560 }
561 else {
562 st_add_direct(symbols->str_sym, (st_data_t)str, (st_data_t)sym);
563 }
564}
565
566void
567rb_free_static_symid_str(void)
568{
569 GLOBAL_SYMBOLS_ENTER(symbols)
570 {
571 st_free_table(symbols->str_sym);
572 }
573 GLOBAL_SYMBOLS_LEAVE();
574}
575
576static void
577unregister_sym(rb_symbols_t *symbols, VALUE str, VALUE sym)
578{
579 ASSERT_vm_locking();
580
581 st_data_t str_data = (st_data_t)str;
582 if (!st_delete(symbols->str_sym, &str_data, NULL)) {
583 rb_bug("%p can't remove str from str_id (%s)", (void *)sym, RSTRING_PTR(str));
584 }
585}
586
587static ID
588register_static_symid(ID id, const char *name, long len, rb_encoding *enc)
589{
590 VALUE str = rb_enc_str_new(name, len, enc);
591 return register_static_symid_str(id, str);
592}
593
594static ID
595register_static_symid_str(ID id, VALUE str)
596{
597 rb_id_serial_t num = rb_id_to_serial(id);
598 VALUE sym = STATIC_ID2SYM(id);
599
600 OBJ_FREEZE(str);
601 str = rb_fstring(str);
602
603 RUBY_DTRACE_CREATE_HOOK(SYMBOL, RSTRING_PTR(str));
604
605 GLOBAL_SYMBOLS_ENTER(symbols)
606 {
607 register_sym(symbols, str, sym);
608 set_id_entry(symbols, num, str, sym);
609 }
610 GLOBAL_SYMBOLS_LEAVE();
611
612 return id;
613}
614
615static int
616sym_check_asciionly(VALUE str, bool fake_str)
617{
618 if (!rb_enc_asciicompat(rb_enc_get(str))) return FALSE;
619 switch (rb_enc_str_coderange(str)) {
621 if (fake_str) {
622 str = rb_enc_str_new(RSTRING_PTR(str), RSTRING_LEN(str), rb_enc_get(str));
623 }
624 rb_raise(rb_eEncodingError, "invalid symbol in encoding %s :%+"PRIsVALUE,
625 rb_enc_name(rb_enc_get(str)), str);
627 return TRUE;
628 }
629 return FALSE;
630}
631
632#if 0
633/*
634 * _str_ itself will be registered at the global symbol table. _str_
635 * can be modified before the registration, since the encoding will be
636 * set to ASCII-8BIT if it is a special global name.
637 */
638
639static inline void
640must_be_dynamic_symbol(VALUE x)
641{
642 if (UNLIKELY(!DYNAMIC_SYM_P(x))) {
643 if (STATIC_SYM_P(x)) {
644 VALUE str = lookup_id_str(RSHIFT((unsigned long)(x),RUBY_SPECIAL_SHIFT));
645
646 if (str) {
647 rb_bug("wrong argument: %s (inappropriate Symbol)", RSTRING_PTR(str));
648 }
649 else {
650 rb_bug("wrong argument: inappropriate Symbol (%p)", (void *)x);
651 }
652 }
653 else {
654 rb_bug("wrong argument type %s (expected Symbol)", rb_builtin_class_name(x));
655 }
656 }
657}
658#endif
659
660static VALUE
661dsymbol_alloc(rb_symbols_t *symbols, const VALUE klass, const VALUE str, rb_encoding * const enc, const ID type)
662{
663 ASSERT_vm_locking();
664
665 NEWOBJ_OF(obj, struct RSymbol, klass, T_SYMBOL | FL_WB_PROTECTED, sizeof(struct RSymbol), 0);
666
667 long hashval;
668
669 rb_enc_set_index((VALUE)obj, rb_enc_to_index(enc));
670 OBJ_FREEZE((VALUE)obj);
671 RB_OBJ_WRITE((VALUE)obj, &obj->fstr, str);
672 obj->id = type;
673
674 /* we want hashval to be in Fixnum range [ruby-core:15713] r15672 */
675 hashval = (long)rb_str_hash(str);
676 obj->hashval = RSHIFT((long)hashval, 1);
677 register_sym(symbols, str, (VALUE)obj);
678 rb_hash_aset(symbols->dsymbol_fstr_hash, str, Qtrue);
679 RUBY_DTRACE_CREATE_HOOK(SYMBOL, RSTRING_PTR(obj->fstr));
680
681 return (VALUE)obj;
682}
683
684static inline VALUE
685dsymbol_check(rb_symbols_t *symbols, const VALUE sym)
686{
687 ASSERT_vm_locking();
688
689 if (UNLIKELY(rb_objspace_garbage_object_p(sym))) {
690 const VALUE fstr = RSYMBOL(sym)->fstr;
691 const ID type = RSYMBOL(sym)->id & ID_SCOPE_MASK;
692 RSYMBOL(sym)->fstr = 0;
693 unregister_sym(symbols, fstr, sym);
694 return dsymbol_alloc(symbols, rb_cSymbol, fstr, rb_enc_get(fstr), type);
695 }
696 else {
697 return sym;
698 }
699}
700
701static ID
702lookup_str_id(VALUE str)
703{
704 st_data_t sym_data;
705 int found;
706
707 GLOBAL_SYMBOLS_ENTER(symbols);
708 {
709 found = st_lookup(symbols->str_sym, (st_data_t)str, &sym_data);
710 }
711 GLOBAL_SYMBOLS_LEAVE();
712
713 if (found) {
714 const VALUE sym = (VALUE)sym_data;
715
716 if (STATIC_SYM_P(sym)) {
717 return STATIC_SYM2ID(sym);
718 }
719 else if (DYNAMIC_SYM_P(sym)) {
720 ID id = RSYMBOL(sym)->id;
721 if (id & ~ID_SCOPE_MASK) return id;
722 }
723 else {
724 rb_bug("non-symbol object %s:%"PRIxVALUE" for %"PRIsVALUE" in symbol table",
725 rb_builtin_class_name(sym), sym, str);
726 }
727 }
728 return (ID)0;
729}
730
731static VALUE
732lookup_str_sym_with_lock(rb_symbols_t *symbols, const VALUE str)
733{
734 st_data_t sym_data;
735 if (st_lookup(symbols->str_sym, (st_data_t)str, &sym_data)) {
736 VALUE sym = (VALUE)sym_data;
737 if (DYNAMIC_SYM_P(sym)) {
738 sym = dsymbol_check(symbols, sym);
739 }
740 return sym;
741 }
742 else {
743 return Qfalse;
744 }
745}
746
747static VALUE
748lookup_str_sym(const VALUE str)
749{
750 VALUE sym;
751
752 GLOBAL_SYMBOLS_ENTER(symbols);
753 {
754 sym = lookup_str_sym_with_lock(symbols, str);
755 }
756 GLOBAL_SYMBOLS_LEAVE();
757
758 return sym;
759}
760
761static VALUE
762lookup_id_str(ID id)
763{
764 return get_id_entry(id, ID_ENTRY_STR);
765}
766
767ID
768rb_intern3(const char *name, long len, rb_encoding *enc)
769{
770 VALUE sym;
771 struct RString fake_str;
772 VALUE str = rb_setup_fake_str(&fake_str, name, len, enc);
773 OBJ_FREEZE(str);
774 sym = lookup_str_sym(str);
775 if (sym) return rb_sym2id(sym);
776 str = rb_enc_str_new(name, len, enc); /* make true string */
777 return intern_str(str, 1);
778}
779
780static ID
781next_id_base_with_lock(rb_symbols_t *symbols)
782{
783 ID id;
784 rb_id_serial_t next_serial = symbols->last_id + 1;
785
786 if (next_serial == 0) {
787 id = (ID)-1;
788 }
789 else {
790 const size_t num = ++symbols->last_id;
791 id = num << ID_SCOPE_SHIFT;
792 }
793
794 return id;
795}
796
797static ID
798next_id_base(void)
799{
800 ID id;
801 GLOBAL_SYMBOLS_ENTER(symbols);
802 {
803 id = next_id_base_with_lock(symbols);
804 }
805 GLOBAL_SYMBOLS_LEAVE();
806 return id;
807}
808
809static ID
810intern_str(VALUE str, int mutable)
811{
812 ID id;
813 ID nid;
814
815 id = rb_str_symname_type(str, IDSET_ATTRSET_FOR_INTERN);
816 if (id == (ID)-1) id = ID_JUNK;
817 if (sym_check_asciionly(str, false)) {
818 if (!mutable) str = rb_str_dup(str);
819 rb_enc_associate(str, rb_usascii_encoding());
820 }
821 if ((nid = next_id_base()) == (ID)-1) {
822 str = rb_str_ellipsize(str, 20);
823 rb_raise(rb_eRuntimeError, "symbol table overflow (symbol %"PRIsVALUE")",
824 str);
825 }
826 id |= nid;
827 id |= ID_STATIC_SYM;
828 return register_static_symid_str(id, str);
829}
830
831ID
832rb_intern2(const char *name, long len)
833{
834 return rb_intern3(name, len, rb_usascii_encoding());
835}
836
837#undef rb_intern
838ID
839rb_intern(const char *name)
840{
841 return rb_intern2(name, strlen(name));
842}
843
844ID
845rb_intern_str(VALUE str)
846{
847 VALUE sym = lookup_str_sym(str);
848
849 if (sym) {
850 return SYM2ID(sym);
851 }
852
853 return intern_str(str, 0);
854}
855
856void
857rb_gc_free_dsymbol(VALUE sym)
858{
859 VALUE str = RSYMBOL(sym)->fstr;
860
861 if (str) {
862 RSYMBOL(sym)->fstr = 0;
863
864 GLOBAL_SYMBOLS_ENTER(symbols);
865 {
866 unregister_sym(symbols, str, sym);
867 rb_hash_delete_entry(symbols->dsymbol_fstr_hash, str);
868 }
869 GLOBAL_SYMBOLS_LEAVE();
870 }
871}
872
873/*
874 * call-seq:
875 * str.intern -> symbol
876 * str.to_sym -> symbol
877 *
878 * Returns the +Symbol+ corresponding to <i>str</i>, creating the
879 * symbol if it did not previously exist. See Symbol#id2name.
880 *
881 * "Koala".intern #=> :Koala
882 * s = 'cat'.to_sym #=> :cat
883 * s == :cat #=> true
884 * s = '@cat'.to_sym #=> :@cat
885 * s == :@cat #=> true
886 *
887 * This can also be used to create symbols that cannot be represented using the
888 * <code>:xxx</code> notation.
889 *
890 * 'cat and dog'.to_sym #=> :"cat and dog"
891 */
892
893VALUE
895{
896 VALUE sym;
897
898 GLOBAL_SYMBOLS_ENTER(symbols);
899 {
900 sym = lookup_str_sym_with_lock(symbols, str);
901
902 if (sym) {
903 // ok
904 }
905 else if (USE_SYMBOL_GC) {
906 rb_encoding *enc = rb_enc_get(str);
907 rb_encoding *ascii = rb_usascii_encoding();
908 if (enc != ascii && sym_check_asciionly(str, false)) {
909 str = rb_str_dup(str);
910 rb_enc_associate(str, ascii);
911 OBJ_FREEZE(str);
912 enc = ascii;
913 }
914 else {
915 str = rb_str_dup(str);
916 OBJ_FREEZE(str);
917 }
918 str = rb_fstring(str);
919 int type = rb_str_symname_type(str, IDSET_ATTRSET_FOR_INTERN);
920 if (type < 0) type = ID_JUNK;
921 sym = dsymbol_alloc(symbols, rb_cSymbol, str, enc, type);
922 }
923 else {
924 ID id = intern_str(str, 0);
925 sym = ID2SYM(id);
926 }
927 }
928 GLOBAL_SYMBOLS_LEAVE();
929 return sym;
930}
931
932ID
934{
935 ID id;
936 if (STATIC_SYM_P(sym)) {
937 id = STATIC_SYM2ID(sym);
938 }
939 else if (DYNAMIC_SYM_P(sym)) {
940 GLOBAL_SYMBOLS_ENTER(symbols);
941 {
942 sym = dsymbol_check(symbols, sym);
943 id = RSYMBOL(sym)->id;
944
945 if (UNLIKELY(!(id & ~ID_SCOPE_MASK))) {
946 VALUE fstr = RSYMBOL(sym)->fstr;
947 ID num = next_id_base_with_lock(symbols);
948
949 RSYMBOL(sym)->id = id |= num;
950 /* make it permanent object */
951
952 set_id_entry(symbols, rb_id_to_serial(num), fstr, sym);
953 rb_hash_delete_entry(symbols->dsymbol_fstr_hash, fstr);
954 }
955 }
956 GLOBAL_SYMBOLS_LEAVE();
957 }
958 else {
959 rb_raise(rb_eTypeError, "wrong argument type %s (expected Symbol)",
960 rb_builtin_class_name(sym));
961 }
962 return id;
963}
964
965#undef rb_id2sym
966VALUE
968{
969 if (!DYNAMIC_ID_P(x)) return STATIC_ID2SYM(x);
970 return get_id_entry(x, ID_ENTRY_SYM);
971}
972
973/*
974 * call-seq:
975 * name -> string
976 *
977 * Returns a frozen string representation of +self+ (not including the leading colon):
978 *
979 * :foo.name # => "foo"
980 * :foo.name.frozen? # => true
981 *
982 * Related: Symbol#to_s, Symbol#inspect.
983 */
984
985VALUE
987{
988 VALUE str;
989 if (DYNAMIC_SYM_P(sym)) {
990 str = RSYMBOL(sym)->fstr;
992 }
993 else {
994 str = rb_id2str(STATIC_SYM2ID(sym));
995 if (str) RUBY_ASSERT_BUILTIN_TYPE(str, T_STRING);
996 }
997
998 return str;
999}
1000
1001VALUE
1002rb_id2str(ID id)
1003{
1004 return lookup_id_str(id);
1005}
1006
1007const char *
1008rb_id2name(ID id)
1009{
1010 VALUE str = rb_id2str(id);
1011
1012 if (!str) return 0;
1013 return RSTRING_PTR(str);
1014}
1015
1016ID
1017rb_make_internal_id(void)
1018{
1019 return next_id_base() | ID_INTERNAL | ID_STATIC_SYM;
1020}
1021
1022ID
1023rb_make_temporary_id(size_t n)
1024{
1025 const ID max_id = RB_ID_SERIAL_MAX & ~0xffff;
1026 const ID id = max_id - (ID)n;
1027 if (id <= ruby_global_symbols.last_id) {
1028 rb_raise(rb_eRuntimeError, "too big to make temporary ID: %" PRIdSIZE, n);
1029 }
1030 return (id << ID_SCOPE_SHIFT) | ID_STATIC_SYM | ID_INTERNAL;
1031}
1032
1033static int
1034symbols_i(st_data_t key, st_data_t value, st_data_t arg)
1035{
1036 VALUE ary = (VALUE)arg;
1037 VALUE sym = (VALUE)value;
1038
1039 if (STATIC_SYM_P(sym)) {
1040 rb_ary_push(ary, sym);
1041 return ST_CONTINUE;
1042 }
1043 else if (!DYNAMIC_SYM_P(sym)) {
1044 rb_bug("invalid symbol: %s", RSTRING_PTR((VALUE)key));
1045 }
1046 else if (!SYMBOL_PINNED_P(sym) && rb_objspace_garbage_object_p(sym)) {
1047 RSYMBOL(sym)->fstr = 0;
1048 return ST_DELETE;
1049 }
1050 else {
1051 rb_ary_push(ary, sym);
1052 return ST_CONTINUE;
1053 }
1054
1055}
1056
1057VALUE
1059{
1060 VALUE ary;
1061
1062 GLOBAL_SYMBOLS_ENTER(symbols);
1063 {
1064 ary = rb_ary_new2(symbols->str_sym->num_entries);
1065 st_foreach(symbols->str_sym, symbols_i, ary);
1066 }
1067 GLOBAL_SYMBOLS_LEAVE();
1068
1069 return ary;
1070}
1071
1072size_t
1073rb_sym_immortal_count(void)
1074{
1075 return (size_t)ruby_global_symbols.last_id;
1076}
1077
1078int
1080{
1081 return is_const_id(id);
1082}
1083
1084int
1086{
1087 return is_class_id(id);
1088}
1089
1090int
1092{
1093 return is_global_id(id);
1094}
1095
1096int
1098{
1099 return is_instance_id(id);
1100}
1101
1102int
1104{
1105 return is_attrset_id(id);
1106}
1107
1108int
1110{
1111 return is_local_id(id);
1112}
1113
1114int
1116{
1117 return is_junk_id(id);
1118}
1119
1120int
1121rb_is_const_sym(VALUE sym)
1122{
1123 return is_const_sym(sym);
1124}
1125
1126int
1127rb_is_attrset_sym(VALUE sym)
1128{
1129 return is_attrset_sym(sym);
1130}
1131
1132ID
1133rb_check_id(volatile VALUE *namep)
1134{
1135 VALUE tmp;
1136 VALUE name = *namep;
1137
1138 if (STATIC_SYM_P(name)) {
1139 return STATIC_SYM2ID(name);
1140 }
1141 else if (DYNAMIC_SYM_P(name)) {
1142 if (SYMBOL_PINNED_P(name)) {
1143 return RSYMBOL(name)->id;
1144 }
1145 else {
1146 *namep = RSYMBOL(name)->fstr;
1147 return 0;
1148 }
1149 }
1150 else if (!RB_TYPE_P(name, T_STRING)) {
1151 tmp = rb_check_string_type(name);
1152 if (NIL_P(tmp)) {
1153 rb_raise(rb_eTypeError, "%+"PRIsVALUE" is not a symbol nor a string",
1154 name);
1155 }
1156 name = tmp;
1157 *namep = name;
1158 }
1159
1160 sym_check_asciionly(name, false);
1161
1162 return lookup_str_id(name);
1163}
1164
1165// Used by yjit for handling .send without throwing exceptions
1166ID
1167rb_get_symbol_id(VALUE name)
1168{
1169 if (STATIC_SYM_P(name)) {
1170 return STATIC_SYM2ID(name);
1171 }
1172 else if (DYNAMIC_SYM_P(name)) {
1173 if (SYMBOL_PINNED_P(name)) {
1174 return RSYMBOL(name)->id;
1175 }
1176 else {
1177 return 0;
1178 }
1179 }
1180 else if (RB_TYPE_P(name, T_STRING)) {
1181 return lookup_str_id(name);
1182 }
1183 else {
1184 return 0;
1185 }
1186}
1187
1188
1189VALUE
1190rb_check_symbol(volatile VALUE *namep)
1191{
1192 VALUE sym;
1193 VALUE tmp;
1194 VALUE name = *namep;
1195
1196 if (STATIC_SYM_P(name)) {
1197 return name;
1198 }
1199 else if (DYNAMIC_SYM_P(name)) {
1200 if (!SYMBOL_PINNED_P(name)) {
1201 GLOBAL_SYMBOLS_ENTER(symbols);
1202 {
1203 name = dsymbol_check(symbols, name);
1204 }
1205 GLOBAL_SYMBOLS_LEAVE();
1206
1207 *namep = name;
1208 }
1209 return name;
1210 }
1211 else if (!RB_TYPE_P(name, T_STRING)) {
1212 tmp = rb_check_string_type(name);
1213 if (NIL_P(tmp)) {
1214 rb_raise(rb_eTypeError, "%+"PRIsVALUE" is not a symbol nor a string",
1215 name);
1216 }
1217 name = tmp;
1218 *namep = name;
1219 }
1220
1221 sym_check_asciionly(name, false);
1222
1223 if ((sym = lookup_str_sym(name)) != 0) {
1224 return sym;
1225 }
1226
1227 return Qnil;
1228}
1229
1230ID
1231rb_check_id_cstr(const char *ptr, long len, rb_encoding *enc)
1232{
1233 struct RString fake_str;
1234 const VALUE name = rb_setup_fake_str(&fake_str, ptr, len, enc);
1235
1236 sym_check_asciionly(name, true);
1237
1238 return lookup_str_id(name);
1239}
1240
1241VALUE
1242rb_check_symbol_cstr(const char *ptr, long len, rb_encoding *enc)
1243{
1244 VALUE sym;
1245 struct RString fake_str;
1246 const VALUE name = rb_setup_fake_str(&fake_str, ptr, len, enc);
1247
1248 sym_check_asciionly(name, true);
1249
1250 if ((sym = lookup_str_sym(name)) != 0) {
1251 return sym;
1252 }
1253
1254 return Qnil;
1255}
1256
1257#undef rb_sym_intern_ascii_cstr
1258#ifdef __clang__
1259NOINLINE(VALUE rb_sym_intern(const char *ptr, long len, rb_encoding *enc));
1260#else
1261FUNC_MINIMIZED(VALUE rb_sym_intern(const char *ptr, long len, rb_encoding *enc));
1262FUNC_MINIMIZED(VALUE rb_sym_intern_ascii(const char *ptr, long len));
1263FUNC_MINIMIZED(VALUE rb_sym_intern_ascii_cstr(const char *ptr));
1264#endif
1265
1266VALUE
1267rb_sym_intern(const char *ptr, long len, rb_encoding *enc)
1268{
1269 struct RString fake_str;
1270 const VALUE name = rb_setup_fake_str(&fake_str, ptr, len, enc);
1271 return rb_str_intern(name);
1272}
1273
1274VALUE
1275rb_sym_intern_ascii(const char *ptr, long len)
1276{
1277 return rb_sym_intern(ptr, len, rb_usascii_encoding());
1278}
1279
1280VALUE
1281rb_sym_intern_ascii_cstr(const char *ptr)
1282{
1283 return rb_sym_intern_ascii(ptr, strlen(ptr));
1284}
1285
1286VALUE
1287rb_to_symbol_type(VALUE obj)
1288{
1289 return rb_convert_type_with_id(obj, T_SYMBOL, "Symbol", idTo_sym);
1290}
1291
1292int
1293rb_is_const_name(VALUE name)
1294{
1295 return rb_str_symname_type(name, 0) == ID_CONST;
1296}
1297
1298int
1299rb_is_class_name(VALUE name)
1300{
1301 return rb_str_symname_type(name, 0) == ID_CLASS;
1302}
1303
1304int
1305rb_is_instance_name(VALUE name)
1306{
1307 return rb_str_symname_type(name, 0) == ID_INSTANCE;
1308}
1309
1310int
1311rb_is_local_name(VALUE name)
1312{
1313 return rb_str_symname_type(name, 0) == ID_LOCAL;
1314}
1315
1316#include "id_table.c"
1317#include "symbol.rbinc"
#define RUBY_ASSERT_BUILTIN_TYPE(obj, type)
A variant of RUBY_ASSERT that asserts when either RUBY_DEBUG or built-in type of obj is type.
Definition assert.h:291
static bool rb_enc_isupper(OnigCodePoint c, rb_encoding *enc)
Identical to rb_isupper(), except it additionally takes an encoding.
Definition ctype.h:124
static bool rb_enc_isctype(OnigCodePoint c, OnigCtype t, rb_encoding *enc)
Queries if the passed code point is of passed character type in the passed encoding.
Definition ctype.h:63
static bool rb_enc_islower(OnigCodePoint c, rb_encoding *enc)
Identical to rb_islower(), except it additionally takes an encoding.
Definition ctype.h:110
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define ISUPPER
Old name of rb_isupper.
Definition ctype.h:89
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:135
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
#define ISDIGIT
Old name of rb_isdigit.
Definition ctype.h:93
#define STATIC_SYM_P
Old name of RB_STATIC_SYM_P.
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:517
#define ISALPHA
Old name of rb_isalpha.
Definition ctype.h:92
#define ISASCII
Old name of rb_isascii.
Definition ctype.h:85
#define Qtrue
Old name of RUBY_Qtrue.
#define DYNAMIC_SYM_P
Old name of RB_DYNAMIC_SYM_P.
Definition value_type.h:86
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
#define NIL_P
Old name of RB_NIL_P.
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:516
#define FL_WB_PROTECTED
Old name of RUBY_FL_WB_PROTECTED.
Definition fl_type.h:59
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
#define ISALNUM
Old name of rb_isalnum.
Definition ctype.h:91
void rb_name_error(ID id, const char *fmt,...)
Raises an instance of rb_eNameError.
Definition error.c:2344
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1430
void rb_name_error_str(VALUE str, const char *fmt,...)
Identical to rb_name_error(), except it takes a VALUE instead of ID.
Definition error.c:2359
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
VALUE rb_eEncodingError
EncodingError exception.
Definition error.c:1436
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:104
VALUE rb_cSymbol
Symbol class.
Definition string.c:80
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:603
Encoding relates APIs.
int rb_enc_str_coderange(VALUE str)
Scans the passed string to collect its code range.
Definition string.c:901
int rb_enc_symname_p(const char *str, rb_encoding *enc)
Identical to rb_symname_p(), except it additionally takes an encoding.
Definition symbol.c:227
VALUE rb_check_symbol_cstr(const char *ptr, long len, rb_encoding *enc)
Identical to rb_check_id_cstr(), except for the return type.
Definition symbol.c:1242
int rb_enc_symname2_p(const char *name, long len, rb_encoding *enc)
Identical to rb_enc_symname_p(), except it additionally takes the passed string's length.
Definition symbol.c:430
ID rb_check_id_cstr(const char *ptr, long len, rb_encoding *enc)
Identical to rb_check_id(), except it takes a pointer to a memory region instead of Ruby's string.
Definition symbol.c:1231
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_sym_all_symbols(void)
Collects every single bits of symbols that have ever interned in the entire history of the current pr...
Definition symbol.c:1058
int rb_is_global_id(ID id)
Classifies the given ID, then sees if it is a global variable.
Definition symbol.c:1091
int rb_is_instance_id(ID id)
Classifies the given ID, then sees if it is an instance variable.
Definition symbol.c:1097
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1079
int rb_is_junk_id(ID)
Classifies the given ID, then sees if it is a junk ID.
Definition symbol.c:1115
int rb_symname_p(const char *str)
Sees if the passed C string constructs a valid syntactic symbol.
Definition symbol.c:221
int rb_is_class_id(ID id)
Classifies the given ID, then sees if it is a class variable.
Definition symbol.c:1085
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1103
int rb_is_local_id(ID id)
Classifies the given ID, then sees if it is a local variable.
Definition symbol.c:1109
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4046
VALUE rb_str_ellipsize(VALUE str, long len)
Shortens str and adds three dots, an ellipsis, if it is longer than len characters.
Definition string.c:11464
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1917
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4032
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3445
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2851
VALUE rb_str_intern(VALUE str)
Identical to rb_to_symbol(), except it assumes the receiver being an instance of RString.
Definition symbol.c:894
VALUE rb_check_symbol(volatile VALUE *namep)
Identical to rb_check_id(), except it returns an instance of rb_cSymbol instead.
Definition symbol.c:1190
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
Definition symbol.c:967
ID rb_check_id(volatile VALUE *namep)
Detects if the given name is already interned or not.
Definition symbol.c:1133
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:986
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:933
int len
Length of the buffer.
Definition io.h:8
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
VALUE type(ANYARGS)
ANYARGS-ed function type.
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:76
@ RUBY_SPECIAL_SHIFT
Least significant 8 bits are reserved.
Ruby's String.
Definition rstring.h:196
char * ptr
Pointer to the contents of the string.
Definition rstring.h:222
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376