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