Ruby 4.1.0dev (2026-09-21 revision 61de3dd727146cfcf24e8051595bb2fb842f37aa)
symbol.c (61de3dd727146cfcf24e8051595bb2fb842f37aa)
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 "darray.h"
13#include "internal.h"
14#include "internal/concurrent_set.h"
15#include "internal/error.h"
16#include "internal/gc.h"
17#include "internal/hash.h"
18#include "internal/object.h"
19#include "internal/symbol.h"
20#include "internal/vm.h"
21#include "probes.h"
22#include "ruby/atomic.h"
23#include "ruby/encoding.h"
24#include "ruby/ractor.h"
25#include "ruby/st.h"
26#include "symbol.h"
27#include "vm_core.h"
28#include "vm_sync.h"
29#include "builtin.h"
31
32#if defined(SYMBOL_DEBUG) && (SYMBOL_DEBUG+0)
33# undef SYMBOL_DEBUG
34# define SYMBOL_DEBUG 1
35#else
36# undef SYMBOL_DEBUG
37# define SYMBOL_DEBUG 0
38#endif
39#ifndef CHECK_ID_SERIAL
40# define CHECK_ID_SERIAL SYMBOL_DEBUG
41#endif
42
43#define IDSET_ATTRSET_FOR_SYNTAX ((1U<<ID_LOCAL)|(1U<<ID_CONST))
44#define IDSET_ATTRSET_FOR_INTERN (~(~0U<<(1<<ID_SCOPE_SHIFT)) & ~(1U<<ID_ATTRSET))
45
46#define STATIC_SYM2ID(sym) RSHIFT((VALUE)(sym), RUBY_SPECIAL_SHIFT)
47
48static ID register_static_symid(ID, const char *, long, rb_encoding *);
49#define REGISTER_SYMID(id, name) register_static_symid((id), (name), strlen(name), enc)
50#include "id.c"
51
52#define is_identchar(p,e,enc) (ISALNUM((unsigned char)*(p)) || (*(p)) == '_' || !ISASCII(*(p)))
53
54#define op_tbl_count numberof(op_tbl)
55STATIC_ASSERT(op_tbl_name_size, sizeof(op_tbl[0].name) == 3);
56#define op_tbl_len(i) (!op_tbl[i].name[1] ? 1 : !op_tbl[i].name[2] ? 2 : 3)
57
58
59#define GLOBAL_SYMBOLS_LOCKING(symbols) \
60 for (rb_symbols_t *symbols = &ruby_global_symbols, **locking = &symbols; \
61 locking; \
62 locking = NULL) \
63 RB_VM_LOCKING()
64
65static void
66Init_op_tbl(void)
67{
68 int i;
69 rb_encoding *const enc = rb_usascii_encoding();
70
71 for (i = '!'; i <= '~'; ++i) {
72 if (!ISALNUM(i) && i != '_') {
73 char c = (char)i;
74 register_static_symid(i, &c, 1, enc);
75 }
76 }
77 for (i = 0; i < op_tbl_count; ++i) {
78 register_static_symid(op_tbl[i].token, op_tbl[i].name, op_tbl_len(i), enc);
79 }
80}
81
82static const int ID_ENTRY_UNIT = 512;
83
84typedef struct {
85 rb_atomic_t next_id;
86 VALUE sym_set;
87
88 VALUE ids;
90
91rb_symbols_t ruby_global_symbols = {
92 .next_id = tNEXT_ID,
93};
94
96 VALUE sym;
97 VALUE str;
98};
99
100#define SYM_SET_SYM_STATIC_TAG 1
101
102static bool
103sym_set_sym_static_p(VALUE sym)
104{
105 return sym & SYM_SET_SYM_STATIC_TAG;
106}
107
108static VALUE
109sym_set_static_sym_tag(struct sym_set_static_sym_entry *sym)
110{
111 VALUE value = (VALUE)sym | SYM_SET_SYM_STATIC_TAG;
112 RUBY_ASSERT(IMMEDIATE_P(value));
113 RUBY_ASSERT(sym_set_sym_static_p(value));
114
115 return value;
116}
117
118static struct sym_set_static_sym_entry *
119sym_set_static_sym_untag(VALUE sym)
120{
121 RUBY_ASSERT(sym_set_sym_static_p(sym));
122
123 return (struct sym_set_static_sym_entry *)(sym & ~((VALUE)SYM_SET_SYM_STATIC_TAG));
124}
125
126static VALUE
127sym_set_sym_get_str(VALUE sym)
128{
129 VALUE str;
130 if (sym_set_sym_static_p(sym)) {
131 str = sym_set_static_sym_untag(sym)->str;
132 }
133 else {
135 str = RSYMBOL(sym)->fstr;
136 }
137
139
140 return str;
141}
142
143static VALUE
144sym_set_hash(VALUE sym)
145{
146 if (sym_set_sym_static_p(sym)) {
147 return (VALUE)rb_str_hash(sym_set_static_sym_untag(sym)->str);
148 }
149 else {
150 return (VALUE)RSYMBOL(sym)->hashval;
151 }
152}
153
154static bool
155sym_set_cmp(VALUE a, VALUE b)
156{
157 return rb_str_hash_cmp(sym_set_sym_get_str(a), sym_set_sym_get_str(b)) == false;
158}
159
161 VALUE sym;
162 VALUE str;
163};
164
165static void
166sym_id_entry_list_mark(void *ptr)
167{
168 rb_darray(struct sym_id_entry) ary = ptr;
169
170 struct sym_id_entry *entry;
171 rb_darray_foreach(ary, i, entry) {
172 // sym must be pinned because it may be used in places that don't
173 // support compaction
174 rb_gc_mark(entry->sym);
175 rb_gc_mark_movable(entry->str);
176 }
177}
178
179static void
180sym_id_entry_list_free(void *ptr)
181{
182 rb_darray_free_sized(ptr, struct sym_id_entry);
183}
184
185static size_t
186sym_id_entry_list_memsize(const void *ptr)
187{
188 const rb_darray(struct sym_id_entry) ary = ptr;
189
190 return rb_darray_memsize(ary);
191}
192
193static void
194sym_id_entry_list_compact(void *ptr)
195{
196 rb_darray(struct sym_id_entry) ary = ptr;
197
198 struct sym_id_entry *entry;
199 rb_darray_foreach(ary, i, entry) {
200 rb_gc_update_moved(&entry->str);
201 }
202}
203
204static const rb_data_type_t sym_id_entry_list_type = {
205 "symbol_id_entry_list",
206 {
207 sym_id_entry_list_mark,
208 sym_id_entry_list_free,
209 sym_id_entry_list_memsize,
210 sym_id_entry_list_compact,
211 },
212 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
213};
214
215/* Directory mapping an ID serial (via idx = serial / ID_ENTRY_UNIT) to its
216 * sym_id_entry bucket. */
218 long capa;
219 VALUE *entries;
220};
221
222static void
223id_entry_dir_mark(void *ptr)
224{
225 struct id_entry_dir *dir = ptr;
226 for (long i = 0; i < dir->capa; i++) {
227 if (dir->entries[i]) {
228 rb_gc_mark_movable(dir->entries[i]);
229 }
230 }
231}
232
233static void
234id_entry_dir_free(void *ptr)
235{
236 struct id_entry_dir *dir = ptr;
237 SIZED_FREE_N(dir->entries, dir->capa);
238 xfree(dir);
239}
240
241static size_t
242id_entry_dir_memsize(const void *ptr)
243{
244 const struct id_entry_dir *dir = ptr;
245 return sizeof(struct id_entry_dir) + dir->capa * sizeof(VALUE);
246}
247
248static void
249id_entry_dir_compact(void *ptr)
250{
251 struct id_entry_dir *dir = ptr;
252 for (long i = 0; i < dir->capa; i++) {
253 if (dir->entries[i]) {
254 rb_gc_update_moved(&dir->entries[i]);
255 }
256 }
257}
258
259static const rb_data_type_t id_entry_dir_type = {
260 "symbol_id_entry_directory",
261 {
262 id_entry_dir_mark,
263 id_entry_dir_free,
264 id_entry_dir_memsize,
265 id_entry_dir_compact,
266 },
267 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
268};
269
270static const long ID_ENTRY_DIR_INITIAL_CAPA = 16;
271
272static VALUE
273id_entry_dir_new(long capa)
274{
275 struct id_entry_dir *dir;
276 VALUE obj = TypedData_Make_Struct(0, struct id_entry_dir, &id_entry_dir_type, dir);
278 dir->entries = ZALLOC_N(VALUE, capa);
279 dir->capa = capa; // must be set after the allocation in case of GC
280 return obj;
281}
282
283static int
284sym_check_asciionly(VALUE str, bool fake_str)
285{
286 if (!rb_enc_asciicompat(rb_enc_get(str))) return FALSE;
287 switch (rb_enc_str_coderange(str)) {
289 if (fake_str) {
290 str = rb_enc_str_new(RSTRING_PTR(str), RSTRING_LEN(str), rb_enc_get(str));
291 }
292 rb_raise(rb_eEncodingError, "invalid symbol in encoding %s :%+"PRIsVALUE,
293 rb_enc_name(rb_enc_get(str)), str);
295 return TRUE;
296 }
297 return FALSE;
298}
299
300static VALUE
301dup_string_for_create(VALUE str)
302{
303 rb_encoding *enc = rb_enc_get(str);
304
305 str = rb_enc_str_new(RSTRING_PTR(str), RSTRING_LEN(str), enc);
306
307 rb_encoding *ascii = rb_usascii_encoding();
308 if (enc != ascii && sym_check_asciionly(str, false)) {
309 rb_enc_associate(str, ascii);
310 }
311 OBJ_FREEZE(str);
312
313 str = rb_fstring(str);
314 return str;
315}
316
317static int
318rb_str_symname_type(VALUE name, unsigned int allowed_attrset)
319{
320 const char *ptr = StringValuePtr(name);
321 long len = RSTRING_LEN(name);
322 int type = rb_enc_symname_type(ptr, len, rb_enc_get(name), allowed_attrset);
323 RB_GC_GUARD(name);
324 return type;
325}
326
327static ID
328next_id_base(void)
329{
330 rb_atomic_t serial = RUBY_ATOMIC_FETCH_ADD(ruby_global_symbols.next_id, 1);
331
332 return (ID)serial << ID_SCOPE_SHIFT;
333}
334
335static struct id_entry_dir *
336id_entry_dir_grow(rb_symbols_t *symbols, struct id_entry_dir *old_dir, size_t min_idx)
337{
338 ASSERT_vm_locking();
339
340 long new_capa = old_dir->capa ? old_dir->capa * 2 : ID_ENTRY_DIR_INITIAL_CAPA;
341 while ((size_t)new_capa <= min_idx) new_capa *= 2;
342
343 // id_entry_dir_new may trigger GC, but the old directory is still reachable
344 // via symbols->ids until we publish below, so it and its buckets stay marked.
345 VALUE new_obj = id_entry_dir_new(new_capa);
346 struct id_entry_dir *new_dir = RTYPEDDATA_GET_DATA(new_obj);
347
348 memcpy(new_dir->entries, old_dir->entries, old_dir->capa * sizeof(VALUE));
349 rb_gc_writebarrier_remember(new_obj);
350
351 // Publish: this release pairs with the acquire load in get_id_serial_entry.
352 // The old directory becomes unreachable from roots, but is kept alive for any
353 // in-flight lock-free reader by that reader's own machine stack
354 rbimpl_atomic_value_store(&symbols->ids, new_obj, RBIMPL_ATOMIC_RELEASE);
355
356 return new_dir;
357}
358
359static void
360set_id_entry(rb_symbols_t *symbols, rb_id_serial_t num, VALUE str, VALUE sym)
361{
362 ASSERT_vm_locking();
367
368 size_t idx = num / ID_ENTRY_UNIT;
369
370 struct id_entry_dir *dir = RTYPEDDATA_GET_DATA(symbols->ids);
371 if (idx >= (size_t)dir->capa) {
372 dir = id_entry_dir_grow(symbols, dir, idx);
373 }
374
375 VALUE bucket = dir->entries[idx];
376 rb_darray(struct sym_id_entry) entries;
377 if (!bucket) {
378 rb_darray_make(&entries, ID_ENTRY_UNIT);
379 bucket = TypedData_Wrap_Struct(0, &sym_id_entry_list_type, entries);
380 /* Reachable from every Ractor via the global symbol table, so mark it shareable. */
381 RB_OBJ_SET_SHAREABLE(bucket);
382 // Publish the (calloc-zeroed) bucket; release pairs with the reader's acquire load.
383 rbimpl_atomic_value_store(&dir->entries[idx], bucket, RBIMPL_ATOMIC_RELEASE);
384 RB_OBJ_WRITTEN(symbols->ids, Qundef, bucket);
385 }
386 else {
387 entries = RTYPEDDATA_GET_DATA(bucket);
388 }
389
390 idx = num % ID_ENTRY_UNIT;
391 struct sym_id_entry *entry = rb_darray_ref(entries, idx);
392 RUBY_ASSERT(entry->str == 0);
393 RUBY_ASSERT(entry->sym == 0);
394
395 RB_OBJ_WRITE(bucket, &entry->str, str);
396 RB_OBJ_WRITE(bucket, &entry->sym, sym);
397}
398
399static VALUE
400sym_set_create(VALUE sym, void *data)
401{
402 bool create_dynamic_symbol = (bool)data;
403
404 struct sym_set_static_sym_entry *static_sym_entry = sym_set_static_sym_untag(sym);
405
406 VALUE str = dup_string_for_create(static_sym_entry->str);
407
408 if (create_dynamic_symbol) {
409 NEWOBJ_OF(obj, struct RSymbol, rb_cSymbol, T_SYMBOL, sizeof(struct RSymbol));
410
411 rb_encoding *enc = rb_enc_get(str);
412 rb_enc_set_index((VALUE)obj, rb_enc_to_index(enc));
413 RB_OBJ_WRITE((VALUE)obj, &obj->fstr, str);
415
416 int id = rb_str_symname_type(str, IDSET_ATTRSET_FOR_INTERN);
417 if (id < 0) id = ID_INTERNAL;
418 obj->id = id;
419
420 obj->hashval = rb_str_hash(str);
421 RUBY_DTRACE_CREATE_HOOK(SYMBOL, RSTRING_PTR(obj->fstr));
422
423 return (VALUE)obj;
424 }
425 else {
426 struct sym_set_static_sym_entry *new_static_sym_entry = xmalloc(sizeof(struct sym_set_static_sym_entry));
427 new_static_sym_entry->str = str;
428
429 VALUE static_sym = static_sym_entry->sym;
430 if (static_sym == 0) {
431 ID id = rb_str_symname_type(str, IDSET_ATTRSET_FOR_INTERN);
432 if (id == (ID)-1) id = ID_INTERNAL;
433
434 id |= next_id_base();
435 id |= ID_STATIC_SYM;
436
437 static_sym = STATIC_ID2SYM(id);
438 }
439 new_static_sym_entry->sym = static_sym;
440
441 RB_VM_LOCKING() {
442 set_id_entry(&ruby_global_symbols, rb_id_to_serial(STATIC_SYM2ID(static_sym)), str, static_sym);
443 }
444
445 return sym_set_static_sym_tag(new_static_sym_entry);
446 }
447}
448
449static void
450sym_set_free(VALUE sym)
451{
452 if (sym_set_sym_static_p(sym)) {
453 xfree(sym_set_static_sym_untag(sym));
454 }
455}
456
457static const struct rb_concurrent_set_funcs sym_set_funcs = {
458 .hash = sym_set_hash,
459 .cmp = sym_set_cmp,
460 .create = sym_set_create,
461 .free = sym_set_free,
462};
463
464static VALUE
465sym_set_entry_to_sym(VALUE entry)
466{
467 if (sym_set_sym_static_p(entry)) {
468 RUBY_ASSERT(STATIC_SYM_P(sym_set_static_sym_untag(entry)->sym));
469
470 if (!STATIC_SYM_P(sym_set_static_sym_untag(entry)->sym)) rb_bug("not sym");
471
472 return sym_set_static_sym_untag(entry)->sym;
473 }
474 else {
476 if (!DYNAMIC_SYM_P(entry)) rb_bug("not sym");
477
478 return entry;
479 }
480}
481
482static VALUE
483sym_find_or_insert_dynamic_symbol(rb_symbols_t *symbols, const VALUE str)
484{
485 struct sym_set_static_sym_entry static_sym = {
486 .str = str
487 };
488 return sym_set_entry_to_sym(
489 rb_concurrent_set_find_or_insert(&symbols->sym_set, sym_set_static_sym_tag(&static_sym), (void *)true)
490 );
491}
492
493static VALUE
494sym_find_or_insert_static_symbol(rb_symbols_t *symbols, const VALUE str)
495{
496 struct sym_set_static_sym_entry static_sym = {
497 .str = str
498 };
499 return sym_set_entry_to_sym(
500 rb_concurrent_set_find_or_insert(&symbols->sym_set, sym_set_static_sym_tag(&static_sym), (void *)false)
501 );
502}
503
504static VALUE
505sym_find_or_insert_static_symbol_id(rb_symbols_t *symbols, const VALUE str, ID id)
506{
507 struct sym_set_static_sym_entry static_sym = {
508 .sym = STATIC_ID2SYM(id),
509 .str = str,
510 };
511 return sym_set_entry_to_sym(
512 rb_concurrent_set_find_or_insert(&symbols->sym_set, sym_set_static_sym_tag(&static_sym), (void *)false)
513 );
514}
515
516void
517Init_sym(void)
518{
519 rb_symbols_t *symbols = &ruby_global_symbols;
520
521 symbols->sym_set = rb_concurrent_set_new(&sym_set_funcs, 1024);
522 symbols->ids = id_entry_dir_new(ID_ENTRY_DIR_INITIAL_CAPA);
523
524 Init_op_tbl();
525 Init_id();
526}
527
528void
529rb_sym_global_symbols_mark_and_move(void)
530{
531 rb_symbols_t *symbols = &ruby_global_symbols;
532
533 rb_gc_mark_and_move(&symbols->sym_set);
534 rb_gc_mark_and_move(&symbols->ids);
535}
536
537static int
538rb_free_global_symbol_table_i(VALUE *sym_ptr, void *data)
539{
540 sym_set_free(*sym_ptr);
541
542 return ST_DELETE;
543}
544
545void
546rb_free_global_symbol_table(void)
547{
548 rb_concurrent_set_foreach_with_replace(ruby_global_symbols.sym_set, rb_free_global_symbol_table_i, NULL);
549}
550
551WARN_UNUSED_RESULT(static ID lookup_str_id(VALUE str));
552WARN_UNUSED_RESULT(static VALUE get_id_str(ID id));
553
554ID
555rb_id_attrset(ID id)
556{
557 int scope;
558
559 if (!is_notop_id(id)) {
560 switch (id) {
561 case tAREF: case tASET:
562 return tASET; /* only exception */
563 }
564 rb_name_error(id, "cannot make operator ID :%"PRIsVALUE" attrset",
565 rb_id2str(id));
566 }
567 else {
568 scope = id_type(id);
569 switch (scope) {
570 case ID_LOCAL: case ID_INSTANCE: case ID_GLOBAL:
571 case ID_CONST: case ID_CLASS: case ID_INTERNAL:
572 break;
573 case ID_ATTRSET:
574 return id;
575 default:
576 {
577 VALUE str = get_id_str(id);
578 if (str != 0) {
579 rb_name_error(id, "cannot make unknown type ID %d:%"PRIsVALUE" attrset",
580 scope, str);
581 }
582 else {
583 rb_name_error_str(Qnil, "cannot make unknown type anonymous ID %d:%"PRIxVALUE" attrset",
584 scope, (VALUE)id);
585 }
586 }
587 }
588 }
589
590 bool error = false;
591 /* make new symbol and ID */
592 VALUE str = get_id_str(id);
593 if (str) {
594 str = rb_str_dup(str);
595 rb_str_cat(str, "=", 1);
596 if (sym_check_asciionly(str, false)) {
597 rb_enc_associate(str, rb_usascii_encoding());
598 }
599
600 VALUE sym = sym_find_or_insert_static_symbol(&ruby_global_symbols, str);
601 id = rb_sym2id(sym);
602 }
603 else {
604 error = true;
605 }
606
607 if (error) {
608 RBIMPL_ATTR_NONSTRING_ARRAY() static const char id_types[][8] = {
609 "local",
610 "instance",
611 "invalid",
612 "global",
613 "attrset",
614 "const",
615 "class",
616 "internal",
617 };
618 rb_name_error(id, "cannot make anonymous %.*s ID %"PRIxVALUE" attrset",
619 (int)sizeof(id_types[0]), id_types[scope], (VALUE)id);
620 }
621
622 return id;
623}
624
625static int
626is_special_global_name(const char *m, const char *e, rb_encoding *enc)
627{
628 int mb = 0;
629
630 if (m >= e) return 0;
631 if (is_global_name_punct(*m)) {
632 ++m;
633 }
634 else if (*m == '-') {
635 if (++m >= e) return 0;
636 if (is_identchar(m, e, enc)) {
637 if (!ISASCII(*m)) mb = 1;
638 m += rb_enc_mbclen(m, e, enc);
639 }
640 }
641 else {
642 if (!ISDIGIT(*m)) return 0;
643 do {
644 if (!ISASCII(*m)) mb = 1;
645 ++m;
646 } while (m < e && ISDIGIT(*m));
647 }
648 return m == e ? mb + 1 : 0;
649}
650
651int
652rb_symname_p(const char *name)
653{
654 return rb_enc_symname_p(name, rb_ascii8bit_encoding());
655}
656
657int
658rb_enc_symname_p(const char *name, rb_encoding *enc)
659{
660 return rb_enc_symname2_p(name, strlen(name), enc);
661}
662
663static int
664rb_sym_constant_char_p(const char *name, long nlen, rb_encoding *enc)
665{
666 int c, len;
667 const char *end = name + nlen;
668
669 if (nlen < 1) return FALSE;
670 if (ISASCII(*name)) return ISUPPER(*name);
671 c = rb_enc_precise_mbclen(name, end, enc);
672 if (!MBCLEN_CHARFOUND_P(c)) return FALSE;
674 c = rb_enc_mbc_to_codepoint(name, end, enc);
675 if (rb_enc_isupper(c, enc)) return TRUE;
676 if (rb_enc_islower(c, enc)) return FALSE;
677 if (ONIGENC_IS_UNICODE(enc)) {
678 static int ctype_titlecase = 0;
679 if (!ctype_titlecase) {
680 static const UChar cname[] = "titlecaseletter";
681 static const UChar *const end = cname + sizeof(cname) - 1;
682 ctype_titlecase = ONIGENC_PROPERTY_NAME_TO_CTYPE(enc, cname, end);
683 }
684 if (rb_enc_isctype(c, ctype_titlecase, enc)) return TRUE;
685 }
686 else {
687 /* fallback to case-folding */
688 OnigUChar fold[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM];
689 const OnigUChar *beg = (const OnigUChar *)name;
690 int r = enc->mbc_case_fold(ONIGENC_CASE_FOLD,
691 &beg, (const OnigUChar *)end,
692 fold, enc);
693 if (r > 0 && (r != len || memcmp(fold, name, r)))
694 return TRUE;
695 }
696 return FALSE;
697}
698
700 const enum { invalid, stophere, needmore, } kind;
701 const enum ruby_id_types type;
702 const long nread;
703};
704
705#define t struct enc_synmane_type_leading_chars_tag
706
708enc_synmane_type_leading_chars(const char *name, long len, rb_encoding *enc, int allowed_attrset)
709{
710 const char *m = name;
711 const char *e = m + len;
712
713 if (! rb_enc_asciicompat(enc)) {
714 return (t) { invalid, 0, 0, };
715 }
716 else if (! m) {
717 return (t) { invalid, 0, 0, };
718 }
719 else if ( len <= 0 ) {
720 return (t) { invalid, 0, 0, };
721 }
722 switch (*m) {
723 case '\0':
724 return (t) { invalid, 0, 0, };
725
726 case '$':
727 if (is_special_global_name(++m, e, enc)) {
728 return (t) { stophere, ID_GLOBAL, len, };
729 }
730 else {
731 return (t) { needmore, ID_GLOBAL, 1, };
732 }
733
734 case '@':
735 switch (*++m) {
736 default: return (t) { needmore, ID_INSTANCE, 1, };
737 case '@': return (t) { needmore, ID_CLASS, 2, };
738 }
739
740 case '<':
741 switch (*++m) {
742 default: return (t) { stophere, ID_INTERNAL, 1, };
743 case '<': return (t) { stophere, ID_INTERNAL, 2, };
744 case '=':
745 switch (*++m) {
746 default: return (t) { stophere, ID_INTERNAL, 2, };
747 case '>': return (t) { stophere, ID_INTERNAL, 3, };
748 }
749 }
750
751 case '>':
752 switch (*++m) {
753 default: return (t) { stophere, ID_INTERNAL, 1, };
754 case '>': case '=': return (t) { stophere, ID_INTERNAL, 2, };
755 }
756
757 case '=':
758 switch (*++m) {
759 default: return (t) { invalid, 0, 1, };
760 case '~': return (t) { stophere, ID_INTERNAL, 2, };
761 case '=':
762 switch (*++m) {
763 default: return (t) { stophere, ID_INTERNAL, 2, };
764 case '=': return (t) { stophere, ID_INTERNAL, 3, };
765 }
766 }
767
768 case '*':
769 switch (*++m) {
770 default: return (t) { stophere, ID_INTERNAL, 1, };
771 case '*': return (t) { stophere, ID_INTERNAL, 2, };
772 }
773
774 case '+': case '-':
775 switch (*++m) {
776 default: return (t) { stophere, ID_INTERNAL, 1, };
777 case '@': return (t) { stophere, ID_INTERNAL, 2, };
778 }
779
780 case '|': case '^': case '&': case '/': case '%': case '~': case '`':
781 return (t) { stophere, ID_INTERNAL, 1, };
782
783 case '[':
784 switch (*++m) {
785 default: return (t) { needmore, ID_INTERNAL, 0, };
786 case ']':
787 switch (*++m) {
788 default: return (t) { stophere, ID_INTERNAL, 2, };
789 case '=': return (t) { stophere, ID_INTERNAL, 3, };
790 }
791 }
792
793 case '!':
794 switch (*++m) {
795 case '=': case '~': return (t) { stophere, ID_INTERNAL, 2, };
796 default:
797 if (allowed_attrset & (1U << ID_INTERNAL)) {
798 return (t) { needmore, ID_INTERNAL, 1, };
799 }
800 else {
801 return (t) { stophere, ID_INTERNAL, 1, };
802 }
803 }
804
805 default:
806 if (rb_sym_constant_char_p(name, len, enc)) {
807 return (t) { needmore, ID_CONST, 0, };
808 }
809 else {
810 return (t) { needmore, ID_LOCAL, 0, };
811 }
812 }
813}
814#undef t
815
816int
817rb_enc_symname_type(const char *name, long len, rb_encoding *enc, unsigned int allowed_attrset)
818{
820 enc_synmane_type_leading_chars(name, len, enc, allowed_attrset);
821 const char *m = name + f.nread;
822 const char *e = name + len;
823 int type = (int)f.type;
824
825 switch (f.kind) {
826 case invalid: return -1;
827 case stophere: break;
828 case needmore:
829
830 if (m >= e || (*m != '_' && !ISALPHA(*m) && ISASCII(*m))) {
831 if (len > 1 && *(e-1) == '=') {
832 type = rb_enc_symname_type(name, len-1, enc, allowed_attrset);
833 if (allowed_attrset & (1U << type)) return ID_ATTRSET;
834 }
835 return -1;
836 }
837 while (m < e && is_identchar(m, e, enc)) m += rb_enc_mbclen(m, e, enc);
838 if (m >= e) break;
839 switch (*m) {
840 case '!': case '?':
841 if (type == ID_GLOBAL || type == ID_CLASS || type == ID_INSTANCE) return -1;
842 type = ID_INTERNAL;
843 ++m;
844 if (m + 1 < e || *m != '=') break;
845 /* fall through */
846 case '=':
847 if (!(allowed_attrset & (1U << type))) return -1;
848 type = ID_ATTRSET;
849 ++m;
850 break;
851 }
852 }
853
854 return m == e ? type : -1;
855}
856
857int
858rb_enc_symname2_p(const char *name, long len, rb_encoding *enc)
859{
860 return rb_enc_symname_type(name, len, enc, IDSET_ATTRSET_FOR_SYNTAX) != -1;
861}
862
863static struct sym_id_entry *
864get_id_serial_entry(rb_id_serial_t num)
865{
866 struct sym_id_entry *entry = NULL;
867
868 if (num && num < RUBY_ATOMIC_LOAD(ruby_global_symbols.next_id)) {
869 size_t idx = num / ID_ENTRY_UNIT;
870
871 VALUE dir_obj = rbimpl_atomic_value_load(&ruby_global_symbols.ids, RBIMPL_ATOMIC_ACQUIRE);
872 struct id_entry_dir *dir = RTYPEDDATA_GET_DATA(dir_obj);
873
874 if (idx < (size_t)dir->capa) {
875 VALUE bucket = rbimpl_atomic_value_load(&dir->entries[idx], RBIMPL_ATOMIC_ACQUIRE);
876 if (bucket) {
877 rb_darray(struct sym_id_entry) entries = RTYPEDDATA_GET_DATA(bucket);
878
879 size_t pos = (size_t)(num % ID_ENTRY_UNIT);
880 RUBY_ASSERT(pos < rb_darray_size(entries));
881 entry = rb_darray_ref(entries, pos);
882 }
883 }
884
885 RB_GC_GUARD(dir_obj);
886 }
887
888 return entry;
889}
890
891static VALUE
892get_id_sym(ID id)
893{
894 struct sym_id_entry *entry = get_id_serial_entry(rb_id_to_serial(id));
895 return entry ? entry->sym : 0;
896}
897
898static VALUE
899get_id_str(ID id)
900{
901 struct sym_id_entry *entry = get_id_serial_entry(rb_id_to_serial(id));
902 return entry ? entry->str : 0;
903}
904
905int
906rb_static_id_valid_p(ID id)
907{
908 return STATIC_ID2SYM(id) == get_id_sym(id);
909}
910
911static inline ID
912rb_id_serial_to_id(rb_id_serial_t num)
913{
914 if (is_notop_id((ID)num)) {
915 struct sym_id_entry *entry = get_id_serial_entry(num);
916 if (entry && entry->sym != 0) {
917 return SYM2ID(entry->sym);
918 }
919 else {
920 return ((ID)num << ID_SCOPE_SHIFT) | ID_INTERNAL | ID_STATIC_SYM;
921 }
922 }
923 else {
924 return (ID)num;
925 }
926}
927
928static ID
929register_static_symid(ID id, const char *name, long len, rb_encoding *enc)
930{
931 VALUE str = rb_enc_str_new(name, len, enc);
932 OBJ_FREEZE(str);
933 str = rb_fstring(str);
934
935 RUBY_DTRACE_CREATE_HOOK(SYMBOL, RSTRING_PTR(str));
936
937 sym_find_or_insert_static_symbol_id(&ruby_global_symbols, str, id);
938
939 return id;
940}
941
942static VALUE
943sym_find(VALUE str)
944{
945 VALUE sym;
946
947 struct sym_set_static_sym_entry static_sym = {
948 .str = str
949 };
950 sym = rb_concurrent_set_find(&ruby_global_symbols.sym_set, sym_set_static_sym_tag(&static_sym));
951
952 if (sym) {
953 return sym_set_entry_to_sym(sym);
954 }
955 else {
956 return 0;
957 }
958}
959
960/* A dynamic symbol's id is assigned lazily by rb_sym2id, which performs a release store of
961 * id after set_id_entry has populated the serial->{str,sym} entry. */
962STATIC_ASSERT(value_id_same_width, sizeof(VALUE) == sizeof(ID));
963static inline ID
964sym_id_load_acquire(VALUE sym)
965{
966 return (ID)rbimpl_atomic_value_load((VALUE *)&RSYMBOL(sym)->id, RBIMPL_ATOMIC_ACQUIRE);
967}
968
969static ID
970lookup_str_id(VALUE str)
971{
972 VALUE sym = sym_find(str);
973
974 if (sym == 0) {
975 return (ID)0;
976 }
977
978 if (STATIC_SYM_P(sym)) {
979 return STATIC_SYM2ID(sym);
980 }
981 else if (DYNAMIC_SYM_P(sym)) {
982 ID id = sym_id_load_acquire(sym);
983 if (id & ~ID_SCOPE_MASK) return id;
984 }
985 else {
986 rb_bug("non-symbol object %s:%"PRIxVALUE" for %"PRIsVALUE" in symbol table",
987 rb_builtin_class_name(sym), sym, str);
988 }
989
990 return (ID)0;
991}
992
993ID
994rb_intern3(const char *name, long len, rb_encoding *enc)
995{
996 struct RString fake_str = {RBASIC_INIT};
997 VALUE str = rb_setup_fake_str(&fake_str, name, len, enc);
998 OBJ_FREEZE(str);
999
1000 VALUE sym = sym_find_or_insert_static_symbol(&ruby_global_symbols, str);
1001 return rb_sym2id(sym);
1002}
1003
1004ID
1005rb_intern2(const char *name, long len)
1006{
1007 return rb_intern3(name, len, rb_usascii_encoding());
1008}
1009
1010#undef rb_intern
1011ID
1012rb_intern(const char *name)
1013{
1014 return rb_intern2(name, strlen(name));
1015}
1016
1017ID
1018rb_intern_str(VALUE str)
1019{
1020 VALUE sym = sym_find_or_insert_static_symbol(&ruby_global_symbols, str);
1021 return SYM2ID(sym);
1022}
1023
1024bool
1025rb_obj_is_symbol_table(VALUE obj)
1026{
1027 return obj == ruby_global_symbols.sym_set;
1028}
1029
1031 int (*callback)(VALUE *key, void *data);
1032 void *data;
1033};
1034
1035static int
1036rb_sym_global_symbol_table_foreach_weak_reference_i(VALUE *key, void *d)
1037{
1039 VALUE sym = *key;
1040
1041 if (sym_set_sym_static_p(sym)) {
1042 struct sym_set_static_sym_entry *static_sym = sym_set_static_sym_untag(sym);
1043
1044 return data->callback(&static_sym->str, data->data);
1045 }
1046 else {
1047 return data->callback(key, data->data);
1048 }
1049}
1050
1051void
1052rb_sym_global_symbol_table_foreach_weak_reference(int (*callback)(VALUE *key, void *data), void *data)
1053{
1054 if (!ruby_global_symbols.sym_set) return;
1055
1057 .callback = callback,
1058 .data = data,
1059 };
1060
1061 rb_concurrent_set_foreach_with_replace(ruby_global_symbols.sym_set, rb_sym_global_symbol_table_foreach_weak_reference_i, &foreach_data);
1062}
1063
1064void
1065rb_gc_free_dsymbol(VALUE sym)
1066{
1067 VALUE str = RSYMBOL(sym)->fstr;
1068
1069 if (str) {
1070 rb_concurrent_set_delete_by_identity(ruby_global_symbols.sym_set, sym);
1071
1072 RSYMBOL(sym)->fstr = 0;
1073 }
1074}
1075
1076/*
1077 * call-seq:
1078 * intern -> symbol
1079 *
1080 * :include: doc/string/intern.rdoc
1081 *
1082 */
1083
1084VALUE
1086{
1087 return sym_find_or_insert_dynamic_symbol(&ruby_global_symbols, str);
1088}
1089
1090ID
1092{
1093 ID id = 0;
1094 if (STATIC_SYM_P(sym)) {
1095 id = STATIC_SYM2ID(sym);
1096 }
1097 else if (DYNAMIC_SYM_P(sym)) {
1098 id = sym_id_load_acquire(sym);
1099 if (LIKELY(id & ~ID_SCOPE_MASK)) {
1100 return id;
1101 }
1102
1103 GLOBAL_SYMBOLS_LOCKING(symbols) {
1104 RUBY_ASSERT(!rb_objspace_garbage_object_p(sym));
1105 id = RSYMBOL(sym)->id;
1106
1107 if (UNLIKELY(!(id & ~ID_SCOPE_MASK))) { // double-checked
1108 VALUE fstr = RSYMBOL(sym)->fstr;
1109 ID num = next_id_base();
1110 id |= num;
1111
1112 /* Populate the serial->{str,sym} entry before publishing the pinned id below.
1113 * The publish is a release store paired with the acquire in sym_id_load_acquire
1114 * so a lock-free reader that observes the pinned id is guaranteed to see this entry. */
1115 set_id_entry(symbols, rb_id_to_serial(num), fstr, sym);
1116 rbimpl_atomic_value_store((VALUE *)&RSYMBOL(sym)->id, (VALUE)id, RBIMPL_ATOMIC_RELEASE);
1117 }
1118 }
1119 }
1120 else {
1121 rb_raise(rb_eTypeError, "wrong argument type %s (expected Symbol)",
1122 rb_builtin_class_name(sym));
1123 }
1124 return id;
1125}
1126
1127#undef rb_id2sym
1128VALUE
1130{
1131 if (!DYNAMIC_ID_P(x)) return STATIC_ID2SYM(x);
1132 return get_id_sym(x);
1133}
1134
1135/*
1136 * call-seq:
1137 * name -> string
1138 *
1139 * Returns a frozen string representation of +self+ (not including the leading colon):
1140 *
1141 * :foo.name # => "foo"
1142 * :foo.name.frozen? # => true
1143 *
1144 * Related: Symbol#to_s, Symbol#inspect.
1145 */
1146
1147VALUE
1149{
1150 VALUE str;
1151 if (DYNAMIC_SYM_P(sym)) {
1152 str = RSYMBOL(sym)->fstr;
1154 }
1155 else {
1156 str = rb_id2str(STATIC_SYM2ID(sym));
1157 if (str) RUBY_ASSERT_BUILTIN_TYPE(str, T_STRING);
1158 }
1159
1160 return str;
1161}
1162
1163VALUE
1164rb_id2str(ID id)
1165{
1166 return get_id_str(id);
1167}
1168
1169const char *
1170rb_id2name(ID id)
1171{
1172 VALUE str = rb_id2str(id);
1173
1174 if (!str) return 0;
1175 return RSTRING_PTR(str);
1176}
1177
1178ID
1179rb_make_internal_id(void)
1180{
1181 return next_id_base() | ID_INTERNAL | ID_STATIC_SYM;
1182}
1183
1184ID
1185rb_make_temporary_id(size_t n)
1186{
1187 const ID max_id = RB_ID_SERIAL_MAX & ~0xffff;
1188 const ID id = max_id - (ID)n;
1189 if (id < RUBY_ATOMIC_LOAD(ruby_global_symbols.next_id)) {
1190 rb_raise(rb_eRuntimeError, "too big to make temporary ID: %" PRIdSIZE, n);
1191 }
1192 return (id << ID_SCOPE_SHIFT) | ID_STATIC_SYM | ID_INTERNAL;
1193}
1194
1195static int
1196symbols_i(VALUE *key, void *data)
1197{
1198 VALUE ary = (VALUE)data;
1199 VALUE sym = (VALUE)*key;
1200
1201 if (sym_set_sym_static_p(sym)) {
1202 rb_ary_push(ary, sym_set_static_sym_untag(sym)->sym);
1203 }
1204 else if (rb_objspace_garbage_object_p(sym)) {
1205 return ST_DELETE;
1206 }
1207 else {
1208 rb_ary_push(ary, sym);
1209 }
1210
1211 return ST_CONTINUE;
1212}
1213
1214VALUE
1216{
1217 VALUE ary;
1218
1219 GLOBAL_SYMBOLS_LOCKING(symbols) {
1220 rb_vm_barrier();
1221 ary = rb_ary_new2(rb_concurrent_set_size(symbols->sym_set));
1222 rb_concurrent_set_foreach_with_replace(symbols->sym_set, symbols_i, (void *)ary);
1223 }
1224
1225 return ary;
1226}
1227
1228size_t
1229rb_sym_immortal_count(void)
1230{
1231 return (size_t)(RUBY_ATOMIC_LOAD(ruby_global_symbols.next_id) - 1);
1232}
1233
1234int
1236{
1237 return is_const_id(id);
1238}
1239
1240int
1242{
1243 return is_class_id(id);
1244}
1245
1246int
1248{
1249 return is_global_id(id);
1250}
1251
1252int
1254{
1255 return is_instance_id(id);
1256}
1257
1258int
1260{
1261 return is_attrset_id(id);
1262}
1263
1264int
1266{
1267 return is_local_id(id);
1268}
1269
1270int
1272{
1273 return is_internal_id(id);
1274}
1275
1276int
1277rb_is_const_sym(VALUE sym)
1278{
1279 return is_const_sym(sym);
1280}
1281
1282int
1283rb_is_attrset_sym(VALUE sym)
1284{
1285 return is_attrset_sym(sym);
1286}
1287
1288ID
1289rb_check_id(volatile VALUE *namep)
1290{
1291 VALUE tmp;
1292 VALUE name = *namep;
1293
1294 if (STATIC_SYM_P(name)) {
1295 return STATIC_SYM2ID(name);
1296 }
1297 else if (DYNAMIC_SYM_P(name)) {
1298 ID id = sym_id_load_acquire(name);
1299 if (id & ~ID_SCOPE_MASK) {
1300 return id;
1301 }
1302 else {
1303 *namep = RSYMBOL(name)->fstr;
1304 return 0;
1305 }
1306 }
1307 else if (!RB_TYPE_P(name, T_STRING)) {
1308 tmp = rb_check_string_type(name);
1309 if (NIL_P(tmp)) {
1310 rb_raise(rb_eTypeError, "%+"PRIsVALUE" is not a symbol nor a string",
1311 name);
1312 }
1313 name = tmp;
1314 *namep = name;
1315 }
1316
1317 sym_check_asciionly(name, false);
1318
1319 return lookup_str_id(name);
1320}
1321
1322// Used by yjit for handling .send without throwing exceptions
1323ID
1324rb_get_symbol_id(VALUE name)
1325{
1326 if (STATIC_SYM_P(name)) {
1327 return STATIC_SYM2ID(name);
1328 }
1329 else if (DYNAMIC_SYM_P(name)) {
1330 ID id = sym_id_load_acquire(name);
1331 if (id & ~ID_SCOPE_MASK) {
1332 return id;
1333 }
1334 else {
1335 return 0;
1336 }
1337 }
1338 else if (RB_TYPE_P(name, T_STRING)) {
1339 return lookup_str_id(name);
1340 }
1341 else {
1342 return 0;
1343 }
1344}
1345
1346
1347VALUE
1348rb_check_symbol(volatile VALUE *namep)
1349{
1350 VALUE sym;
1351 VALUE tmp;
1352 VALUE name = *namep;
1353
1354 if (STATIC_SYM_P(name)) {
1355 return name;
1356 }
1357 else if (DYNAMIC_SYM_P(name)) {
1358 RUBY_ASSERT(!rb_objspace_garbage_object_p(name));
1359 return name;
1360 }
1361 else if (!RB_TYPE_P(name, T_STRING)) {
1362 tmp = rb_check_string_type(name);
1363 if (NIL_P(tmp)) {
1364 rb_raise(rb_eTypeError, "%+"PRIsVALUE" is not a symbol nor a string",
1365 name);
1366 }
1367 name = tmp;
1368 *namep = name;
1369 }
1370
1371 sym_check_asciionly(name, false);
1372
1373 if ((sym = sym_find(name)) != 0) {
1374 return sym;
1375 }
1376
1377 return Qnil;
1378}
1379
1380ID
1381rb_check_id_cstr(const char *ptr, long len, rb_encoding *enc)
1382{
1383 struct RString fake_str = {RBASIC_INIT};
1384 const VALUE name = rb_setup_fake_str(&fake_str, ptr, len, enc);
1385
1386 sym_check_asciionly(name, true);
1387
1388 return lookup_str_id(name);
1389}
1390
1391VALUE
1392rb_check_symbol_cstr(const char *ptr, long len, rb_encoding *enc)
1393{
1394 VALUE sym;
1395 struct RString fake_str = {RBASIC_INIT};
1396 const VALUE name = rb_setup_fake_str(&fake_str, ptr, len, enc);
1397
1398 sym_check_asciionly(name, true);
1399
1400 if ((sym = sym_find(name)) != 0) {
1401 return sym;
1402 }
1403
1404 return Qnil;
1405}
1406
1407#undef rb_sym_intern_ascii_cstr
1408#ifdef __clang__
1409NOINLINE(VALUE rb_sym_intern(const char *ptr, long len, rb_encoding *enc));
1410#else
1411FUNC_MINIMIZED(VALUE rb_sym_intern(const char *ptr, long len, rb_encoding *enc));
1412FUNC_MINIMIZED(VALUE rb_sym_intern_ascii(const char *ptr, long len));
1413FUNC_MINIMIZED(VALUE rb_sym_intern_ascii_cstr(const char *ptr));
1414#endif
1415
1416VALUE
1417rb_sym_intern(const char *ptr, long len, rb_encoding *enc)
1418{
1419 struct RString fake_str = {RBASIC_INIT};
1420 const VALUE name = rb_setup_fake_str(&fake_str, ptr, len, enc);
1421 return rb_str_intern(name);
1422}
1423
1424VALUE
1425rb_sym_intern_ascii(const char *ptr, long len)
1426{
1427 return rb_sym_intern(ptr, len, rb_usascii_encoding());
1428}
1429
1430VALUE
1431rb_sym_intern_ascii_cstr(const char *ptr)
1432{
1433 return rb_sym_intern_ascii(ptr, strlen(ptr));
1434}
1435
1436VALUE
1437rb_to_symbol_type(VALUE obj)
1438{
1439 return rb_convert_type_with_id(obj, T_SYMBOL, "Symbol", idTo_sym);
1440}
1441
1442int
1443rb_is_const_name(VALUE name)
1444{
1445 return rb_str_symname_type(name, 0) == ID_CONST;
1446}
1447
1448int
1449rb_is_class_name(VALUE name)
1450{
1451 return rb_str_symname_type(name, 0) == ID_CLASS;
1452}
1453
1454int
1455rb_is_instance_name(VALUE name)
1456{
1457 return rb_str_symname_type(name, 0) == ID_INSTANCE;
1458}
1459
1460int
1461rb_is_local_name(VALUE name)
1462{
1463 return rb_str_symname_type(name, 0) == ID_LOCAL;
1464}
1465
1466#include "id_table.c"
1467#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
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
Atomic operations.
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
#define RUBY_ATOMIC_FETCH_ADD(var, val)
Atomically replaces the value pointed by var with the result of addition of val to the old value of v...
Definition atomic.h:118
#define RUBY_ATOMIC_LOAD(var)
Atomic load.
Definition atomic.h:175
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 xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#define Qundef
Old name of RUBY_Qundef.
#define ISUPPER
Old name of rb_isupper.
Definition ctype.h:89
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:131
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define ISDIGIT
Old name of rb_isdigit.
Definition ctype.h:93
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition memory.h:401
#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 DYNAMIC_SYM_P
Old name of RB_DYNAMIC_SYM_P.
Definition value_type.h:86
#define Qnil
Old name of RUBY_Qnil.
#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 T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
#define IMMEDIATE_P
Old name of RB_IMMEDIATE_P.
#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:2446
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1463
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:2461
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1461
VALUE rb_eEncodingError
EncodingError exception.
Definition error.c:1469
VALUE rb_cSymbol
Symbol class.
Definition string.c:86
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:481
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:469
Encoding relates APIs.
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:658
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:1392
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:858
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:1381
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
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:1215
int rb_is_global_id(ID id)
Classifies the given ID, then sees if it is a global variable.
Definition symbol.c:1247
int rb_is_instance_id(ID id)
Classifies the given ID, then sees if it is an instance variable.
Definition symbol.c:1253
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1235
int rb_is_junk_id(ID)
Classifies the given ID, then sees if it is a junk ID.
Definition symbol.c:1271
int rb_symname_p(const char *str)
Sees if the passed C string constructs a valid syntactic symbol.
Definition symbol.c:652
int rb_is_class_id(ID id)
Classifies the given ID, then sees if it is a class variable.
Definition symbol.c:1241
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1259
int rb_is_local_id(ID id)
Classifies the given ID, then sees if it is a local variable.
Definition symbol.c:1265
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4261
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:2023
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4247
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3666
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:3032
VALUE rb_str_intern(VALUE str)
Identical to rb_to_symbol(), except it assumes the receiver being an instance of RString.
Definition symbol.c:1085
VALUE rb_check_symbol(volatile VALUE *namep)
Identical to rb_check_id(), except it returns an instance of rb_cSymbol instead.
Definition symbol.c:1348
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
Definition symbol.c:1129
ID rb_check_id(volatile VALUE *namep)
Detects if the given name is already interned or not.
Definition symbol.c:1289
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:1148
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:1091
int capa
Designed capacity of the buffer.
Definition io.h:11
int len
Length of the buffer.
Definition io.h:8
#define RB_OBJ_SET_SHAREABLE(obj)
Wrapper of rb_obj_set_shareable().
Definition ractor.h:290
#define RB_OBJ_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
Definition ractor.h:255
static VALUE RB_OBJ_SET_FROZEN_SHAREABLE(VALUE obj)
Freezes and marks the object as shareable.
Definition ractor.h:301
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
VALUE type(ANYARGS)
ANYARGS-ed function type.
Defines RBIMPL_ATTR_NONSTRING.
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:76
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:557
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:604
static bool RB_SPECIAL_CONST_P(VALUE obj)
Checks if the given object is of enum ruby_special_consts.
Ruby's String.
Definition rstring.h:196
char * ptr
Pointer to the contents of the string.
Definition rstring.h:222
Definition symbol.c:217
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:242
Definition symbol.c:160
Definition symbol.c:95
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