Ruby 4.1.0dev (2026-08-15 revision d1c079751b80352d347452c8d134ffb177838adb)
vm_method.c (d1c079751b80352d347452c8d134ffb177838adb)
1/*
2 * This file is included by vm.c
3 */
4
5#include "id_table.h"
6#include "yjit.h"
7
8#define METHOD_DEBUG 0
9
10static int vm_redefinition_check_flag(VALUE klass);
11static void rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me, VALUE klass);
12static inline rb_method_entry_t *lookup_method_table(VALUE klass, ID id);
13
14#define object_id idObject_id
15#define added idMethod_added
16#define singleton_added idSingleton_method_added
17#define removed idMethod_removed
18#define singleton_removed idSingleton_method_removed
19#define undefined idMethod_undefined
20#define singleton_undefined idSingleton_method_undefined
21
22#define ruby_running (GET_VM()->running)
23/* int ruby_running = 0; */
24
25static enum rb_id_table_iterator_result
26mark_cc_entry_i(VALUE ccs_ptr, void *data)
27{
28 struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr;
29
30 VM_ASSERT(vm_ccs_p(ccs));
31
32 if (METHOD_ENTRY_INVALIDATED(ccs->cme)) {
33 /* Never prune from a GC, only mark. A cc table walk (dup and friends) can trigger a
34 * GC from an allocation midway, so an xfree+DELETE while marking would derail the
35 * walking iterator into freed ccs. The mutator cleans up, under the VM lock. */
36 rb_gc_mark_movable((VALUE)ccs->cme);
37 for (int i = 0; i < ccs->len; i++) {
38 rb_gc_mark_movable((VALUE)ccs->entries[i].cc);
39 }
40 return ID_TABLE_CONTINUE;
41 }
42 else {
43 rb_gc_mark_movable((VALUE)ccs->cme);
44
45 for (int i = 0; i < ccs->len; i++) {
46 const struct rb_callcache *cc = ccs->entries[i].cc;
47 VM_ASSERT(cc->klass == Qundef || vm_cc_check_cme(cc, ccs->cme));
48
49 rb_gc_mark_movable((VALUE)cc);
50 }
51 return ID_TABLE_CONTINUE;
52 }
53}
54
55static void
56vm_cc_table_mark(void *data)
57{
58 struct rb_id_table *tbl = (struct rb_id_table *)data;
59 if (tbl) {
60 rb_id_table_foreach_values(tbl, mark_cc_entry_i, NULL);
61 }
62}
63
64static enum rb_id_table_iterator_result
65cc_table_free_i(VALUE ccs_ptr, void *data)
66{
67 struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr;
68 VM_ASSERT(vm_ccs_p(ccs));
69
70 ruby_xfree_sized(ccs, vm_ccs_alloc_size(ccs->capa));
71
72 return ID_TABLE_CONTINUE;
73}
74
75static void
76vm_cc_table_free(void *data)
77{
78 struct rb_id_table *tbl = (struct rb_id_table *)data;
79
80 rb_id_table_foreach_values(tbl, cc_table_free_i, NULL);
81 rb_managed_id_table_type.function.dfree(data);
82}
83
84static enum rb_id_table_iterator_result
85cc_table_memsize_i(VALUE ccs_ptr, void *data_ptr)
86{
87 size_t *total_size = data_ptr;
88 struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr;
89 *total_size += sizeof(*ccs);
90 *total_size += sizeof(ccs->entries[0]) * ccs->capa;
91 return ID_TABLE_CONTINUE;
92}
93
94static size_t
95vm_cc_table_memsize(const void *data)
96{
97 size_t memsize = rb_managed_id_table_type.function.dsize(data);
98 struct rb_id_table *tbl = (struct rb_id_table *)data;
99 rb_id_table_foreach_values(tbl, cc_table_memsize_i, &memsize);
100 return memsize;
101}
102
103static enum rb_id_table_iterator_result
104compact_cc_entry_i(VALUE ccs_ptr, void *data)
105{
106 struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr;
107
108 ccs->cme = (const struct rb_callable_method_entry_struct *)rb_gc_location((VALUE)ccs->cme);
109 VM_ASSERT(vm_ccs_p(ccs));
110
111 for (int i=0; i<ccs->len; i++) {
112 ccs->entries[i].cc = (const struct rb_callcache *)rb_gc_location((VALUE)ccs->entries[i].cc);
113 }
114
115 return ID_TABLE_CONTINUE;
116}
117
118static void
119vm_cc_table_compact(void *data)
120{
121 struct rb_id_table *tbl = (struct rb_id_table *)data;
122 rb_id_table_foreach_values(tbl, compact_cc_entry_i, NULL);
123}
124
125static const rb_data_type_t cc_table_type = {
126 .wrap_struct_name = "VM/cc_table",
127 .function = {
128 .dmark = vm_cc_table_mark,
129 .dfree = vm_cc_table_free,
130 .dsize = vm_cc_table_memsize,
131 .dcompact = vm_cc_table_compact,
132 },
133 .parent = &rb_managed_id_table_type,
134 .flags = RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
135};
136
137VALUE
138rb_vm_cc_table_create(size_t capa)
139{
140 return rb_managed_id_table_create(&cc_table_type, capa);
141}
142
143static enum rb_id_table_iterator_result
144vm_cc_table_dup_i(ID key, VALUE old_ccs_ptr, void *data)
145{
146 VALUE new_table = (VALUE)data;
147 struct rb_class_cc_entries *old_ccs = (struct rb_class_cc_entries *)old_ccs_ptr;
148
149 if (METHOD_ENTRY_INVALIDATED(old_ccs->cme)) {
150 // Invalidated CME. This entry will be removed from the old table on
151 // the next GC mark, so it's unsafe (and undesirable) to copy
152 return ID_TABLE_CONTINUE;
153 }
154
155 size_t memsize = vm_ccs_alloc_size(old_ccs->capa);
156 struct rb_class_cc_entries *new_ccs = ruby_xcalloc(1, memsize);
157 rb_managed_id_table_insert(new_table, key, (VALUE)new_ccs);
158
159 // We hold the VM lock, so invalidation should not have happened between
160 // our earlier invalidation check and now.
161 VM_ASSERT(!METHOD_ENTRY_INVALIDATED(old_ccs->cme));
162
163 memcpy(new_ccs, old_ccs, memsize);
164
165#if VM_CHECK_MODE > 0
166 new_ccs->debug_sig = ~(VALUE)new_ccs;
167#endif
168
169 RB_OBJ_WRITTEN(new_table, Qundef, (VALUE)new_ccs->cme);
170 for (int index = 0; index < new_ccs->len; index++) {
171 RB_OBJ_WRITTEN(new_table, Qundef, new_ccs->entries[index].cc);
172 }
173 return ID_TABLE_CONTINUE;
174}
175
176VALUE
177rb_vm_cc_table_dup(VALUE old_table)
178{
179 ASSERT_vm_locking();
180 VALUE new_table = rb_vm_cc_table_create(rb_managed_id_table_size(old_table));
181 rb_managed_id_table_foreach(old_table, vm_cc_table_dup_i, (void *)new_table);
182 return new_table;
183}
184
185static void
186vm_ccs_invalidate(struct rb_class_cc_entries *ccs)
187{
188 for (int i=0; i<ccs->len; i++) {
189 const struct rb_callcache *cc = ccs->entries[i].cc;
190 VM_ASSERT(!vm_cc_super_p(cc) && !vm_cc_refinement_p(cc));
191 vm_cc_invalidate(cc);
192 }
193}
194
195static void
196rb_vm_ccs_invalidate_and_free(struct rb_class_cc_entries *ccs)
197{
198 RB_DEBUG_COUNTER_INC(ccs_free);
199 vm_ccs_invalidate(ccs);
200 ruby_xfree_sized(ccs, vm_ccs_alloc_size(ccs->capa));
201}
202
203void
204rb_vm_cc_table_delete(VALUE table, ID mid)
205{
206 VALUE ccs_obj;
207 if (rb_managed_id_table_lookup(table, mid, &ccs_obj)) {
208 struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_obj;
209 rb_managed_id_table_delete(table, mid);
210 rb_vm_ccs_invalidate_and_free(ccs);
211 }
212}
213
214static enum rb_id_table_iterator_result
215vm_ccs_dump_i(ID mid, VALUE val, void *data)
216{
217 const struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)val;
218 fprintf(stderr, " | %s (len:%d) ", rb_id2name(mid), ccs->len);
219 rp(ccs->cme);
220
221 for (int i=0; i<ccs->len; i++) {
222 rp_m( " | \t", ccs->entries[i].cc);
223 }
224
225 return ID_TABLE_CONTINUE;
226}
227
228static void
229vm_ccs_dump(VALUE klass, ID target_mid)
230{
231 VALUE cc_tbl = RCLASS_WRITABLE_CC_TBL(klass);
232 if (cc_tbl) {
233 VALUE ccs;
234 if (target_mid) {
235 if (rb_managed_id_table_lookup(cc_tbl, target_mid, &ccs)) {
236 fprintf(stderr, " [CCTB] %p\n", (void *)cc_tbl);
237 vm_ccs_dump_i(target_mid, ccs, NULL);
238 }
239 }
240 else {
241 fprintf(stderr, " [CCTB] %p\n", (void *)cc_tbl);
242 rb_managed_id_table_foreach(cc_tbl, vm_ccs_dump_i, (void *)target_mid);
243 }
244 }
245}
246
247static enum rb_id_table_iterator_result
248vm_cme_dump_i(ID mid, VALUE val, void *data)
249{
250 ID target_mid = (ID)data;
251 if (target_mid == 0 || mid == target_mid) {
252 rp_m(" > ", val);
253 }
254 return ID_TABLE_CONTINUE;
255}
256
257static VALUE
258vm_mtbl_dump(VALUE klass, ID target_mid)
259{
260 fprintf(stderr, "# vm_mtbl\n");
261 while (klass) {
262 rp_m(" -> ", klass);
263 VALUE me;
264
265 if (RCLASS_M_TBL(klass)) {
266 if (target_mid != 0) {
267 if (rb_id_table_lookup(RCLASS_M_TBL(klass), target_mid, &me)) {
268 rp_m(" [MTBL] ", me);
269 }
270 }
271 else {
272 fprintf(stderr, " ## RCLASS_M_TBL (%p)\n", (void *)RCLASS_M_TBL(klass));
273 rb_id_table_foreach(RCLASS_M_TBL(klass), vm_cme_dump_i, NULL);
274 }
275 }
276 else {
277 fprintf(stderr, " MTBL: NULL\n");
278 }
279 if (RCLASS_WRITABLE_CALLABLE_M_TBL(klass)) {
280 if (target_mid != 0) {
281 if (rb_id_table_lookup(RCLASS_WRITABLE_CALLABLE_M_TBL(klass), target_mid, &me)) {
282 rp_m(" [CM**] ", me);
283 }
284 }
285 else {
286 fprintf(stderr, " ## RCLASS_CALLABLE_M_TBL\n");
287 rb_id_table_foreach(RCLASS_WRITABLE_CALLABLE_M_TBL(klass), vm_cme_dump_i, NULL);
288 }
289 }
290 if (RCLASS_WRITABLE_CC_TBL(klass)) {
291 vm_ccs_dump(klass, target_mid);
292 }
293 klass = RCLASS_SUPER(klass);
294 }
295 return Qnil;
296}
297
298void
299rb_vm_mtbl_dump(const char *msg, VALUE klass, ID target_mid)
300{
301 fprintf(stderr, "[%s] ", msg);
302 vm_mtbl_dump(klass, target_mid);
303}
304
305static inline void
306vm_cme_invalidate(rb_callable_method_entry_t *cme)
307{
308 VM_ASSERT(IMEMO_TYPE_P(cme, imemo_ment), "cme: %d", imemo_type((VALUE)cme));
309 VM_ASSERT(callable_method_entry_p(cme));
310 METHOD_ENTRY_INVALIDATED_SET(cme);
311 RB_DEBUG_COUNTER_INC(cc_cme_invalidate);
312
313 rb_yjit_cme_invalidate(cme);
314 rb_zjit_cme_invalidate(cme);
315}
316
317static int
318rb_clear_constant_cache_for_id_i(st_data_t ic, st_data_t arg)
319{
320 ((IC) ic)->entry = NULL;
321 return ST_CONTINUE;
322}
323
324void
326{
327 VALUE lookup_result;
328 rb_vm_t *vm = GET_VM();
329
330 if (rb_id_table_lookup(&vm->constant_cache, id, &lookup_result)) {
331 set_table *ics = (set_table *)lookup_result;
332 set_table_foreach(ics, rb_clear_constant_cache_for_id_i, (st_data_t) NULL);
333 ruby_vm_constant_cache_invalidations += ics->num_entries;
334 }
335
336 rb_yjit_constant_state_changed(id);
337 rb_zjit_constant_state_changed(id);
338}
339
340static void
341invalidate_negative_cache(ID mid)
342{
343 VALUE cme;
344 rb_vm_t *vm = GET_VM();
345
346 if (rb_id_table_lookup(&vm->negative_cme_table, mid, &cme)) {
347 rb_id_table_delete(&vm->negative_cme_table, mid);
348 vm_cme_invalidate((rb_callable_method_entry_t *)cme);
349 RB_DEBUG_COUNTER_INC(cc_invalidate_negative);
350 }
351}
352
353const rb_method_entry_t * rb_method_entry_clone(const rb_method_entry_t *src_me);
354static const rb_callable_method_entry_t *complemented_callable_method_entry(VALUE klass, ID id);
355static const rb_callable_method_entry_t *lookup_overloaded_cme(const rb_callable_method_entry_t *cme);
356
357static void
358invalidate_method_cache_in_cc_table(VALUE tbl, ID mid)
359{
360 VALUE ccs_data;
361 if (tbl && rb_managed_id_table_lookup(tbl, mid, &ccs_data)) {
362 struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_data;
363 rb_yjit_cme_invalidate((rb_callable_method_entry_t *)ccs->cme);
364 rb_zjit_cme_invalidate((rb_callable_method_entry_t *)ccs->cme);
365 if (NIL_P(ccs->cme->owner)) invalidate_negative_cache(mid);
366 rb_vm_ccs_invalidate_and_free(ccs);
367 rb_managed_id_table_delete(tbl, mid);
368 RB_DEBUG_COUNTER_INC(cc_invalidate_leaf_ccs);
369 }
370}
371
372static void
373invalidate_callable_method_entry_in_callable_m_table(struct rb_id_table *tbl, ID mid)
374{
375 VALUE cme;
376 if (tbl && rb_id_table_lookup(tbl, mid, &cme)) {
377 rb_yjit_cme_invalidate((rb_callable_method_entry_t *)cme);
378 rb_zjit_cme_invalidate((rb_callable_method_entry_t *)cme);
379 rb_id_table_delete(tbl, mid);
380 RB_DEBUG_COUNTER_INC(cc_invalidate_leaf_callable);
381 }
382}
383
385 VALUE klass;
386 ID mid;
387 const rb_method_entry_t *cme;
388 const rb_method_entry_t *newer;
389};
390
391static void
392invalidate_callable_method_entry_in_every_m_table_i(rb_classext_t *ext, bool is_prime, VALUE box_value, void *data)
393{
394 st_data_t me;
396 struct rb_id_table *tbl = RCLASSEXT_M_TBL(ext);
397
398 if (rb_id_table_lookup(tbl, arg->mid, &me) && arg->cme == (const rb_method_entry_t *)me) {
399 rb_method_table_insert(arg->klass, tbl, arg->mid, arg->newer);
400 }
401}
402
404 VALUE owner;
405 VALUE klass_housing_cme;
406 VALUE origins; // Array of origins
407};
408
409static void
410collect_per_box_origins_i(rb_classext_t *ext, bool is_prime, VALUE box_value, void *data)
411{
412 struct collect_per_box_origins_arg *arg = (struct collect_per_box_origins_arg *)data;
413 VALUE origin = RCLASSEXT_ORIGIN(ext);
414
415 if (origin == arg->owner || origin == arg->klass_housing_cme) {
416 return;
417 }
418 long len = RARRAY_LEN(arg->origins);
419 for (long i = 0; i < len; i++) {
420 if (RARRAY_AREF(arg->origins, i) == origin) {
421 return;
422 }
423 }
424 rb_ary_push(arg->origins, origin);
425}
426
427static void
428invalidate_callable_method_entry_in_every_m_table(VALUE klass, ID mid, const rb_callable_method_entry_t *cme)
429{
430 // The argument cme must be invalidated later in the caller side
431 const rb_method_entry_t *newer = rb_method_entry_clone((const rb_method_entry_t *)cme);
433 .klass = klass,
434 .mid = mid,
435 .cme = (const rb_method_entry_t *) cme,
436 .newer = newer,
437 };
438 rb_class_classext_foreach(klass, invalidate_callable_method_entry_in_every_m_table_i, (void *)&arg);
439}
440
441static void
442invalidate_complemented_method_entry_in_callable_m_table(struct rb_id_table *tbl, ID mid)
443{
444 VALUE cme;
445 if (tbl && rb_id_table_lookup(tbl, mid, &cme)) {
446 rb_yjit_cme_invalidate((rb_callable_method_entry_t *)cme);
447 rb_zjit_cme_invalidate((rb_callable_method_entry_t *)cme);
448 rb_id_table_delete(tbl, mid);
449 RB_DEBUG_COUNTER_INC(cc_invalidate_tree_callable);
450 }
451}
452
453static void
454clear_method_cache_by_id_in_class(VALUE klass, ID mid)
455{
456 VM_ASSERT_TYPE2(klass, T_CLASS, T_ICLASS);
457 if (rb_objspace_garbage_object_p(klass)) return;
458
459 RB_VM_LOCKING() {
460 rb_vm_barrier();
461
462 if (LIKELY(!RCLASS_SUBCLASSES(klass)) &&
463 !FL_TEST_RAW(klass, RCLASS_HAS_SUBCLASSES) &&
464 // Non-refinement ICLASSes (from module inclusion) previously had
465 // subclasses reparented onto them, so they need the tree path for
466 // broader cme-based invalidation even though they now have no subclasses.
467 !(RB_TYPE_P(klass, T_ICLASS) && NIL_P(RCLASS_REFINED_CLASS(klass)))) {
468 // no subclasses
469 // check only current class
470
471 // invalidate CCs
472 VALUE cc_tbl = RCLASS_WRITABLE_CC_TBL(klass);
473 invalidate_method_cache_in_cc_table(cc_tbl, mid);
474 if (RCLASS_CC_TBL_NOT_PRIME_P(klass, cc_tbl)) {
475 invalidate_method_cache_in_cc_table(RCLASS_PRIME_CC_TBL(klass), mid);
476 }
477
478 // remove from callable_m_tbl, if exists
479 struct rb_id_table *cm_tbl = RCLASS_WRITABLE_CALLABLE_M_TBL(klass);
480 invalidate_callable_method_entry_in_callable_m_table(cm_tbl, mid);
481 if (RCLASS_CALLABLE_M_TBL_NOT_PRIME_P(klass, cm_tbl)) {
482 invalidate_callable_method_entry_in_callable_m_table(RCLASS_PRIME_CALLABLE_M_TBL(klass), mid);
483 }
484
485 RB_DEBUG_COUNTER_INC(cc_invalidate_leaf);
486 }
487 else {
488 const rb_callable_method_entry_t *cme = complemented_callable_method_entry(klass, mid);
489
490 if (cme) {
491 // invalidate cme if found to invalidate the inline method cache.
492 if (METHOD_ENTRY_CACHED(cme)) {
493 if (METHOD_ENTRY_COMPLEMENTED(cme)) {
494 // do nothing
495 }
496 else {
497 // invalidate cc by invalidating cc->cme
498 VALUE owner = cme->owner;
499 VM_ASSERT_TYPE(owner, T_CLASS);
500 VALUE klass_housing_cme;
501 if (cme->def->type == VM_METHOD_TYPE_REFINED && !cme->def->body.refined.orig_me) {
502 klass_housing_cme = owner;
503 }
504 else {
505 klass_housing_cme = RCLASS_ORIGIN(owner);
506 }
507
508 // replace the cme that will be invalid in the all classexts
509 invalidate_callable_method_entry_in_every_m_table(klass_housing_cme, mid, cme);
510 // owner may be a boxable class with per-box classext copies of its m_tbl
511 // (klass_housing_cme may be a non-boxable origin ICLASS that doesn't cover them)
512 if (klass_housing_cme != owner) {
513 invalidate_callable_method_entry_in_every_m_table(owner, mid, cme);
514 }
515 // Also update per-box origin ICLASSes. When ensure_origin is called in
516 // one box's context, it creates a per-box origin ICLASS whose m_tbl is
517 // a copy of owner's m_tbl at that time. The current execution box may
518 // not see these origins via RCLASS_ORIGIN(owner), so we find them by
519 // iterating all of owner's classexts and checking their origin_ fields.
520 {
521 VALUE origins = rb_ary_hidden_new(1);
522 struct collect_per_box_origins_arg origins_arg = {
523 .owner = owner,
524 .klass_housing_cme = klass_housing_cme,
525 .origins = origins,
526 };
527 rb_class_classext_foreach(owner, collect_per_box_origins_i, &origins_arg);
528 for (long i = 0; i < RARRAY_LEN(origins); i++) {
529 invalidate_callable_method_entry_in_every_m_table(RARRAY_AREF(origins, i), mid, cme);
530 }
531 RB_GC_GUARD(origins);
532 }
533 }
534
535 vm_cme_invalidate((rb_callable_method_entry_t *)cme);
536 RB_DEBUG_COUNTER_INC(cc_invalidate_tree_cme);
537
538 // In case of refinement ME, also invalidate the wrapped ME that
539 // could be cached at some callsite and is unreachable from any
540 // RCLASS_WRITABLE_CC_TBL.
541 if (cme->def->type == VM_METHOD_TYPE_REFINED && cme->def->body.refined.orig_me) {
542 vm_cme_invalidate((rb_callable_method_entry_t *)cme->def->body.refined.orig_me);
543 }
544
545 if (cme->def->iseq_overload) {
546 rb_callable_method_entry_t *monly_cme = (rb_callable_method_entry_t *)lookup_overloaded_cme(cme);
547 if (monly_cme) {
548 vm_cme_invalidate(monly_cme);
549 }
550 }
551 }
552
553 // invalidate complement tbl
554 if (METHOD_ENTRY_COMPLEMENTED(cme)) {
555 VALUE defined_class = cme->defined_class;
556 struct rb_id_table *cm_tbl = RCLASS_WRITABLE_CALLABLE_M_TBL(defined_class);
557 invalidate_complemented_method_entry_in_callable_m_table(cm_tbl, mid);
558 if (RCLASS_CALLABLE_M_TBL_NOT_PRIME_P(defined_class, cm_tbl)) {
559 struct rb_id_table *prime_cm_table = RCLASS_PRIME_CALLABLE_M_TBL(defined_class);
560 invalidate_complemented_method_entry_in_callable_m_table(prime_cm_table, mid);
561 }
562 }
563
564 RB_DEBUG_COUNTER_INC(cc_invalidate_tree);
565 }
566 else {
567 invalidate_negative_cache(mid);
568 }
569 }
570
571 rb_gccct_clear_table();
572 }
573}
574
575static void
576clear_iclass_method_cache_by_id(VALUE iclass, VALUE d)
577{
578 VM_ASSERT_TYPE(iclass, T_ICLASS);
579 ID mid = (ID)d;
580 clear_method_cache_by_id_in_class(iclass, mid);
581}
582
583static void
584clear_iclass_method_cache_by_id_for_refinements(VALUE klass, VALUE d)
585{
586 if (RB_TYPE_P(klass, T_ICLASS)) {
587 ID mid = (ID)d;
588 clear_method_cache_by_id_in_class(klass, mid);
589 }
590}
591
592void
593rb_clear_method_cache(VALUE klass_or_module, ID mid)
594{
595 if (RB_TYPE_P(klass_or_module, T_MODULE)) {
596 VALUE module = klass_or_module; // alias
597
598 if (FL_TEST(module, RMODULE_IS_REFINEMENT)) {
599 VALUE refined_class = rb_refinement_module_get_refined_class(module);
600 rb_clear_method_cache(refined_class, mid);
601 rb_class_foreach_subclass(refined_class, clear_iclass_method_cache_by_id_for_refinements, mid);
602 rb_clear_all_refinement_method_cache();
603 }
604 rb_class_foreach_subclass(module, clear_iclass_method_cache_by_id, mid);
605 }
606 else {
607 clear_method_cache_by_id_in_class(klass_or_module, mid);
608 }
609}
610
611static enum rb_id_table_iterator_result
612invalidate_method_entry_in_iclass_callable_m_tbl(VALUE cme, void *data)
613{
614 vm_cme_invalidate((rb_callable_method_entry_t *)cme);
615 return ID_TABLE_DELETE;
616}
617
618static enum rb_id_table_iterator_result
619invalidate_ccs_in_iclass_cc_tbl(VALUE value, void *data)
620{
621 struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)value;
622 vm_cme_invalidate((rb_callable_method_entry_t *)ccs->cme);
623 ruby_xfree_sized(ccs, vm_ccs_alloc_size(ccs->capa));
624 return ID_TABLE_DELETE;
625}
626
627void
628rb_invalidate_method_caches(struct rb_id_table *cm_tbl, VALUE cc_tbl)
629{
630 if (cm_tbl) {
631 rb_id_table_foreach_values(cm_tbl, invalidate_method_entry_in_iclass_callable_m_tbl, NULL);
632 }
633 if (cc_tbl) {
634 rb_managed_id_table_foreach_values(cc_tbl, invalidate_ccs_in_iclass_cc_tbl, NULL);
635 }
636}
637
638static st_index_t
639vm_ci_hash(VALUE v)
640{
641 const struct rb_callinfo *ci = (const struct rb_callinfo *)v;
642 st_index_t h;
643 h = rb_hash_start(ci->mid);
644 h = rb_hash_uint(h, ci->flag);
645 h = rb_hash_uint(h, ci->argc);
646 if (ci->kwarg) {
647 for (int i = 0; i < ci->kwarg->keyword_len; i++) {
648 h = rb_hash_uint(h, ci->kwarg->keywords[i]);
649 }
650 }
651 return h;
652}
653
654static int
655vm_ci_hash_cmp(VALUE v1, VALUE v2)
656{
657 const struct rb_callinfo *ci1 = (const struct rb_callinfo *)v1;
658 const struct rb_callinfo *ci2 = (const struct rb_callinfo *)v2;
659 if (ci1->mid != ci2->mid) return 1;
660 if (ci1->flag != ci2->flag) return 1;
661 if (ci1->argc != ci2->argc) return 1;
662 if (ci1->kwarg != NULL) {
663 VM_ASSERT(ci2->kwarg != NULL); // implied by matching flags
664
665 if (ci1->kwarg->keyword_len != ci2->kwarg->keyword_len)
666 return 1;
667
668 for (int i = 0; i < ci1->kwarg->keyword_len; i++) {
669 if (ci1->kwarg->keywords[i] != ci2->kwarg->keywords[i]) {
670 return 1;
671 }
672 }
673 }
674 else {
675 VM_ASSERT(ci2->kwarg == NULL); // implied by matching flags
676 }
677 return 0;
678}
679
680static const struct st_hash_type vm_ci_hashtype = {
681 vm_ci_hash_cmp,
682 vm_ci_hash
683};
684
685static int
686ci_lookup_i(st_data_t *key, st_data_t *value, st_data_t data, int existing)
687{
688 const struct rb_callinfo *ci = (const struct rb_callinfo *)*key;
689 st_data_t *ret = (st_data_t *)data;
690
691 if (existing) {
692 if (rb_objspace_garbage_object_p((VALUE)ci)) {
693 *ret = (st_data_t)NULL;
694 return ST_DELETE;
695 }
696 else {
697 *ret = *key;
698 return ST_STOP;
699 }
700 }
701 else {
702 *key = *value = *ret = (st_data_t)ci;
703 return ST_CONTINUE;
704 }
705}
706
707const struct rb_callinfo *
708rb_vm_ci_lookup(ID mid, unsigned int flag, unsigned int argc, const struct rb_callinfo_kwarg *kwarg)
709{
710 rb_vm_t *vm = GET_VM();
711 const struct rb_callinfo *ci = NULL;
712
713 if (kwarg) {
714 RUBY_ATOMIC_FETCH_ADD(((struct rb_callinfo_kwarg *)kwarg)->references, 1);
715 }
716
717 struct rb_callinfo *new_ci = SHAREABLE_IMEMO_NEW(struct rb_callinfo, imemo_callinfo, (VALUE)kwarg);
718 new_ci->mid = mid;
719 new_ci->flag = flag;
720 new_ci->argc = argc;
721
722 RB_VM_LOCKING() {
723 st_table *ci_table = &vm->ci_table;
724
725 do {
726 st_update(ci_table, (st_data_t)new_ci, ci_lookup_i, (st_data_t)&ci);
727 } while (ci == NULL);
728 }
729
730 VM_ASSERT(ci);
731
732 return ci;
733}
734
735void
736rb_vm_ci_free(const struct rb_callinfo *ci)
737{
738 ASSERT_vm_locking();
739
740 rb_vm_t *vm = GET_VM();
741
742 st_data_t key = (st_data_t)ci;
743 st_delete(&vm->ci_table, &key, NULL);
744}
745
747 VALUE *entries;
748 size_t len;
749 size_t capa;
750};
751
752static void
753cc_refinement_set_free(void *ptr)
754{
755 struct cc_refinement_entries *e = ptr;
756 xfree(e->entries);
757}
758
759static size_t
760cc_refinement_set_memsize(const void *ptr)
761{
762 const struct cc_refinement_entries *e = ptr;
763 return e->capa * sizeof(VALUE);
764}
765
766static void
767cc_refinement_set_compact(void *ptr)
768{
769 struct cc_refinement_entries *e = ptr;
770 for (size_t i = 0; i < e->len; i++) {
771 e->entries[i] = rb_gc_location(e->entries[i]);
772 }
773}
774
775static void
776cc_refinement_set_handle_weak_references(void *ptr)
777{
778 struct cc_refinement_entries *e = ptr;
779 size_t write = 0;
780 for (size_t read = 0; read < e->len; read++) {
781 if (rb_gc_handle_weak_references_alive_p(e->entries[read])) {
782 e->entries[write++] = e->entries[read];
783 }
784 }
785 e->len = write;
786}
787
788static const rb_data_type_t cc_refinement_set_type = {
789 "VM/cc_refinement_set",
790 {
791 NULL,
792 cc_refinement_set_free,
793 cc_refinement_set_memsize,
794 cc_refinement_set_compact,
795 cc_refinement_set_handle_weak_references,
796 },
797 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
798};
799
800VALUE
801rb_cc_refinement_set_create(void)
802{
803 struct cc_refinement_entries *e;
804 VALUE obj = TypedData_Make_Struct(0, struct cc_refinement_entries, &cc_refinement_set_type, e);
805
806 e->entries = NULL;
807 e->len = 0;
808 e->capa = 0;
809
810 rb_gc_declare_weak_references(obj);
811
812 return obj;
813}
814
815void
816rb_vm_insert_cc_refinement(const struct rb_callcache *cc)
817{
818 rb_vm_t *vm = GET_VM();
819 RB_VM_LOCK_ENTER();
820 {
821 struct cc_refinement_entries *e = RTYPEDDATA_GET_DATA(vm->cc_refinement_set);
822 if (e->len == e->capa) {
823 size_t new_capa = e->capa == 0 ? 16 : e->capa * 2;
824 SIZED_REALLOC_N(e->entries, VALUE, new_capa, e->capa);
825 e->capa = new_capa;
826 }
827 e->entries[e->len++] = (VALUE)cc;
828
829 // We never mark the cc, but we need to issue a writebarrier so that
830 // the refinement set can be added to the remembered set
831 RB_OBJ_WRITTEN(vm->cc_refinement_set, Qundef, (VALUE)cc);
832 }
833 RB_VM_LOCK_LEAVE();
834}
835
836void
837rb_clear_all_refinement_method_cache(void)
838{
839 rb_vm_t *vm = GET_VM();
840
841 RB_VM_LOCK_ENTER();
842 {
843 struct cc_refinement_entries *e = RTYPEDDATA_GET_DATA(vm->cc_refinement_set);
844 for (size_t i = 0; i < e->len; i++) {
845 VALUE v = e->entries[i];
846
847 // All objects should be live as weak references are pruned in
848 // cc_refinement_set_handle_weak_references
849 VM_ASSERT(!rb_objspace_garbage_object_p(v));
850
851 const struct rb_callcache *cc = (const struct rb_callcache *)v;
852 VM_ASSERT(vm_cc_refinement_p(cc));
853
854 if (vm_cc_valid(cc)) {
855 vm_cc_invalidate(cc);
856 }
857 }
858 e->len = 0;
859 }
860 RB_VM_LOCK_LEAVE();
861
862 rb_yjit_invalidate_all_method_lookup_assumptions();
863}
864
865void
866rb_method_table_insert(VALUE klass, struct rb_id_table *table, ID method_id, const rb_method_entry_t *me)
867{
868 RB_VM_LOCKING() {
869 rb_method_table_insert0(klass, table, method_id, me, RB_TYPE_P(klass, T_ICLASS) && !RICLASS_OWNS_M_TBL_P(klass));
870 }
871}
872
873void
874rb_method_table_insert0(VALUE klass, struct rb_id_table *table, ID method_id, const rb_method_entry_t *me, bool iclass_shared_mtbl)
875{
876 VALUE table_owner = klass;
877 if (iclass_shared_mtbl) {
878 table_owner = RBASIC(table_owner)->klass;
879 }
880 VM_ASSERT_TYPE3(table_owner, T_CLASS, T_ICLASS, T_MODULE);
881 rb_id_table_insert(table, method_id, (VALUE)me);
882 RB_OBJ_WRITTEN(table_owner, Qundef, (VALUE)me);
883}
884
885// rb_f_notimplement has an extra trailing argument to distinguish it from other methods
886// at compile-time to override arity to be -1. But the trailing argument introduces a
887// signature mismatch between caller and callee, so rb_define_method family inserts a
888// method entry with rb_f_notimplement_internal, which has canonical arity=-1 signature,
889// instead of rb_f_notimplement.
890NORETURN(static VALUE rb_f_notimplement_internal(int argc, const VALUE *argv, VALUE obj));
891
892static VALUE
893rb_f_notimplement_internal(int argc, const VALUE *argv, VALUE obj)
894{
895 rb_notimplement();
896
898}
899
900VALUE
901rb_f_notimplement(int argc, const VALUE *argv, VALUE obj, VALUE marker)
902{
903 rb_f_notimplement_internal(argc, argv, obj);
904}
905
906static void
907rb_define_notimplement_method_id(VALUE mod, ID id, rb_method_visibility_t visi)
908{
909 rb_add_method(mod, id, VM_METHOD_TYPE_NOTIMPLEMENTED, (void *)1, visi);
910}
911
912void
913rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_visibility_t visi)
914{
915 if (argc < -2 || 15 < argc) rb_raise(rb_eArgError, "arity out of range: %d for -2..15", argc);
916 if (func != (VALUE(*)(ANYARGS))rb_f_notimplement) {
918 opt.func = func;
919 opt.argc = argc;
920 rb_add_method(klass, mid, VM_METHOD_TYPE_CFUNC, &opt, visi);
921 }
922 else {
923 rb_define_notimplement_method_id(klass, mid, visi);
924 }
925}
926
927void
928rb_add_method_optimized(VALUE klass, ID mid, enum method_optimized_type opt_type, unsigned int index, rb_method_visibility_t visi)
929{
931 .type = opt_type,
932 .index = index,
933 };
934 rb_add_method(klass, mid, VM_METHOD_TYPE_OPTIMIZED, &opt, visi);
935}
936
937static void
938method_definition_release(rb_method_definition_t *def)
939{
940 if (def != NULL) {
941 const unsigned int reference_count_was = RUBY_ATOMIC_FETCH_SUB(def->reference_count, 1);
942
943 RUBY_ASSERT_ALWAYS(reference_count_was != 0);
944
945 if (reference_count_was == 1) {
946 if (METHOD_DEBUG) fprintf(stderr, "-%p-%s:1->0 (remove)\n", (void *)def,
947 rb_id2name(def->original_id));
948 SIZED_FREE(def);
949 }
950 else {
951 if (METHOD_DEBUG) fprintf(stderr, "-%p-%s:%d->%d (dec)\n", (void *)def, rb_id2name(def->original_id),
952 reference_count_was, reference_count_was - 1);
953 }
954 }
955}
956
957void
958rb_method_definition_release(rb_method_definition_t *def)
959{
960 method_definition_release(def);
961}
962
963static void delete_overloaded_cme(const rb_callable_method_entry_t *cme);
964
965void
966rb_free_method_entry_vm_weak_references(const rb_method_entry_t *me)
967{
968 if (me->def && me->def->iseq_overload) {
969 delete_overloaded_cme((const rb_callable_method_entry_t *)me);
970 }
971}
972
973void
974rb_free_method_entry(const rb_method_entry_t *me)
975{
976#if USE_ZJIT
977 if (METHOD_ENTRY_CACHED(me)) {
978 rb_zjit_cme_free((const rb_callable_method_entry_t *)me);
979 }
980#endif
981
982#if USE_YJIT
983 // YJIT rb_yjit_root_mark() roots CMEs in `Invariants`,
984 // to remove from `Invariants` here.
985#endif
986
987 method_definition_release(me->def);
988}
989
990static inline rb_method_entry_t *search_method(VALUE klass, ID id, VALUE *defined_class_ptr);
991extern int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
992
993static VALUE
994(*call_cfunc_invoker_func(int argc))(VALUE recv, int argc, const VALUE *, VALUE (*func)(ANYARGS))
995{
996 if (!GET_THREAD()->ext_config.ractor_safe) {
997 switch (argc) {
998 case -2: return &call_cfunc_m2;
999 case -1: return &call_cfunc_m1;
1000 case 0: return &call_cfunc_0;
1001 case 1: return &call_cfunc_1;
1002 case 2: return &call_cfunc_2;
1003 case 3: return &call_cfunc_3;
1004 case 4: return &call_cfunc_4;
1005 case 5: return &call_cfunc_5;
1006 case 6: return &call_cfunc_6;
1007 case 7: return &call_cfunc_7;
1008 case 8: return &call_cfunc_8;
1009 case 9: return &call_cfunc_9;
1010 case 10: return &call_cfunc_10;
1011 case 11: return &call_cfunc_11;
1012 case 12: return &call_cfunc_12;
1013 case 13: return &call_cfunc_13;
1014 case 14: return &call_cfunc_14;
1015 case 15: return &call_cfunc_15;
1016 default:
1017 rb_bug("unsupported length: %d", argc);
1018 }
1019 }
1020 else {
1021 switch (argc) {
1022 case -2: return &ractor_safe_call_cfunc_m2;
1023 case -1: return &ractor_safe_call_cfunc_m1;
1024 case 0: return &ractor_safe_call_cfunc_0;
1025 case 1: return &ractor_safe_call_cfunc_1;
1026 case 2: return &ractor_safe_call_cfunc_2;
1027 case 3: return &ractor_safe_call_cfunc_3;
1028 case 4: return &ractor_safe_call_cfunc_4;
1029 case 5: return &ractor_safe_call_cfunc_5;
1030 case 6: return &ractor_safe_call_cfunc_6;
1031 case 7: return &ractor_safe_call_cfunc_7;
1032 case 8: return &ractor_safe_call_cfunc_8;
1033 case 9: return &ractor_safe_call_cfunc_9;
1034 case 10: return &ractor_safe_call_cfunc_10;
1035 case 11: return &ractor_safe_call_cfunc_11;
1036 case 12: return &ractor_safe_call_cfunc_12;
1037 case 13: return &ractor_safe_call_cfunc_13;
1038 case 14: return &ractor_safe_call_cfunc_14;
1039 case 15: return &ractor_safe_call_cfunc_15;
1040 default:
1041 rb_bug("unsupported length: %d", argc);
1042 }
1043 }
1044}
1045
1046static void
1047setup_method_cfunc_struct(rb_method_cfunc_t *cfunc, VALUE (*func)(ANYARGS), int argc)
1048{
1049 cfunc->func = func;
1050 cfunc->argc = argc;
1051 cfunc->invoker = call_cfunc_invoker_func(argc);
1052}
1053
1054
1056method_definition_addref(rb_method_definition_t *def, bool complemented)
1057{
1058 unsigned int reference_count_was = RUBY_ATOMIC_FETCH_ADD(def->reference_count, 1);
1059 if (!complemented && reference_count_was > 0) {
1060 /* TODO: A Ractor can reach this via UnboundMethod#bind */
1061 def->aliased = true;
1062 }
1063 if (METHOD_DEBUG) fprintf(stderr, "+%p-%s:%d->%d\n", (void *)def, rb_id2name(def->original_id), reference_count_was, reference_count_was+1);
1064
1065 return def;
1066}
1067
1068void
1069rb_method_definition_addref(rb_method_definition_t *def)
1070{
1071 method_definition_addref(def, false);
1072}
1073
1074void
1075rb_method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *def, void *opts)
1076{
1077 method_definition_release(me->def);
1078 *(rb_method_definition_t **)&me->def = method_definition_addref(def, METHOD_ENTRY_COMPLEMENTED(me));
1079
1080 if (!ruby_running) add_opt_method_entry(me);
1081
1082 if (opts != NULL) {
1083 switch (def->type) {
1084 case VM_METHOD_TYPE_ISEQ:
1085 {
1086 rb_method_iseq_t *iseq_body = (rb_method_iseq_t *)opts;
1087 const rb_iseq_t *iseq = iseq_body->iseqptr;
1088 rb_cref_t *method_cref, *cref = iseq_body->cref;
1089
1090 /* setup iseq first (before invoking GC) */
1091 RB_OBJ_WRITE(me, &def->body.iseq.iseqptr, iseq);
1092
1093 // Methods defined in `with_jit` should be considered METHOD_ENTRY_BASIC
1094 if (rb_iseq_attr_p(iseq, BUILTIN_ATTR_C_TRACE)) {
1095 METHOD_ENTRY_BASIC_SET((rb_method_entry_t *)me, TRUE);
1096 }
1097
1098 if (ISEQ_BODY(iseq)->mandatory_only_iseq) def->iseq_overload = 1;
1099
1100 if (0) vm_cref_dump("rb_method_definition_create", cref);
1101
1102 if (cref) {
1103 method_cref = cref;
1104 }
1105 else {
1106 method_cref = vm_cref_new_toplevel(GET_EC()); /* TODO: can we reuse? */
1107 }
1108
1109 RB_OBJ_WRITE(me, &def->body.iseq.cref, method_cref);
1110 return;
1111 }
1112 case VM_METHOD_TYPE_CFUNC:
1113 {
1114 rb_method_cfunc_t *cfunc = (rb_method_cfunc_t *)opts;
1115 setup_method_cfunc_struct(UNALIGNED_MEMBER_PTR(def, body.cfunc), cfunc->func, cfunc->argc);
1116 return;
1117 }
1118 case VM_METHOD_TYPE_ATTRSET:
1119 case VM_METHOD_TYPE_IVAR:
1120 {
1121 const rb_execution_context_t *ec = GET_EC();
1122 rb_control_frame_t *cfp;
1123 int line;
1124
1125 def->body.attr.id = (ID)(VALUE)opts;
1126
1127 cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp);
1128
1129 if (cfp && (line = rb_vm_get_sourceline(cfp))) {
1130 VALUE location = rb_ary_new3(2, rb_iseq_path(CFP_ISEQ(cfp)), INT2FIX(line));
1131 rb_ary_freeze(location);
1132 RB_OBJ_SET_SHAREABLE(location);
1133 RB_OBJ_WRITE(me, &def->body.attr.location, location);
1134 }
1135 else {
1136 VM_ASSERT(def->body.attr.location == 0);
1137 }
1138 return;
1139 }
1140 case VM_METHOD_TYPE_BMETHOD:
1141 RB_OBJ_WRITE(me, &def->body.bmethod.proc, (VALUE)opts);
1142 def->body.bmethod.defined_ractor_id = rb_ec_ractor_id(GET_EC());
1143 return;
1144 case VM_METHOD_TYPE_NOTIMPLEMENTED:
1145 setup_method_cfunc_struct(UNALIGNED_MEMBER_PTR(def, body.cfunc), (VALUE(*)(ANYARGS))rb_f_notimplement_internal, -1);
1146 return;
1147 case VM_METHOD_TYPE_OPTIMIZED:
1148 def->body.optimized = *(rb_method_optimized_t *)opts;
1149 return;
1150 case VM_METHOD_TYPE_REFINED:
1151 {
1152 const rb_method_entry_t *orig_me = (const rb_method_entry_t *)opts;
1153 RB_OBJ_WRITE(me, &def->body.refined.orig_me, orig_me);
1154 RB_OBJ_WRITE(me, &def->original_module, orig_me->def->original_module);
1155 return;
1156 }
1157 case VM_METHOD_TYPE_ALIAS:
1158 {
1159 const rb_method_entry_t *orig_me = (const rb_method_entry_t *)opts;
1160 RB_OBJ_WRITE(me, &def->body.alias.original_me, orig_me);
1161 RB_OBJ_WRITE(me, &def->original_module, orig_me->def->original_module);
1162 return;
1163 }
1164 case VM_METHOD_TYPE_ZSUPER:
1165 case VM_METHOD_TYPE_UNDEF:
1166 case VM_METHOD_TYPE_MISSING:
1167 return;
1168 }
1169 }
1170}
1171
1172static void
1173method_definition_reset(const rb_method_entry_t *me)
1174{
1175 rb_method_definition_t *def = me->def;
1176
1177 RB_OBJ_WRITTEN(me, Qundef, def->original_module);
1178
1179 switch (def->type) {
1180 case VM_METHOD_TYPE_ISEQ:
1181 RB_OBJ_WRITTEN(me, Qundef, def->body.iseq.iseqptr);
1182 RB_OBJ_WRITTEN(me, Qundef, def->body.iseq.cref);
1183 break;
1184 case VM_METHOD_TYPE_ATTRSET:
1185 case VM_METHOD_TYPE_IVAR:
1186 RB_OBJ_WRITTEN(me, Qundef, def->body.attr.location);
1187 break;
1188 case VM_METHOD_TYPE_BMETHOD:
1189 RB_OBJ_WRITTEN(me, Qundef, def->body.bmethod.proc);
1190 break;
1191 case VM_METHOD_TYPE_REFINED:
1192 RB_OBJ_WRITTEN(me, Qundef, def->body.refined.orig_me);
1193 break;
1194 case VM_METHOD_TYPE_ALIAS:
1195 RB_OBJ_WRITTEN(me, Qundef, def->body.alias.original_me);
1196 break;
1197 case VM_METHOD_TYPE_CFUNC:
1198 case VM_METHOD_TYPE_ZSUPER:
1199 case VM_METHOD_TYPE_MISSING:
1200 case VM_METHOD_TYPE_OPTIMIZED:
1201 case VM_METHOD_TYPE_UNDEF:
1202 case VM_METHOD_TYPE_NOTIMPLEMENTED:
1203 break;
1204 }
1205}
1206
1207static rb_atomic_t method_serial = 1;
1208
1210rb_method_definition_create(rb_method_type_t type, ID mid)
1211{
1214 def->type = type;
1215 def->original_id = mid;
1216 def->method_serial = (uintptr_t)RUBY_ATOMIC_FETCH_ADD(method_serial, 1);
1217 def->box = rb_current_box();
1218 return def;
1219}
1220
1221static rb_method_entry_t *
1222rb_method_entry_alloc(ID called_id, VALUE owner, VALUE defined_class, rb_method_definition_t *def, bool complement)
1223{
1224 if (def) method_definition_addref(def, complement);
1225 if (RTEST(defined_class)) {
1226 // not negative cache
1227 VM_ASSERT_TYPE2(defined_class, T_CLASS, T_ICLASS);
1228 }
1229 rb_method_entry_t *me = SHAREABLE_IMEMO_NEW(rb_method_entry_t, imemo_ment, defined_class);
1230
1231 // mark_and_move_method_entry pins itself when it is in the overloaded_cme table
1232 rb_gc_register_pinning_obj((VALUE)me);
1233
1234 *((rb_method_definition_t **)&me->def) = def;
1235 me->called_id = called_id;
1236 me->owner = owner;
1237
1238 return me;
1239}
1240
1241static VALUE
1242filter_defined_class(VALUE klass)
1243{
1244 switch (BUILTIN_TYPE(klass)) {
1245 case T_CLASS:
1246 return klass;
1247 case T_MODULE:
1248 return 0;
1249 case T_ICLASS:
1250 break;
1251 default:
1252 break;
1253 }
1254 rb_bug("filter_defined_class: %s", rb_obj_info(klass));
1255}
1256
1258rb_method_entry_create(ID called_id, VALUE klass, rb_method_visibility_t visi, rb_method_definition_t *def)
1259{
1260 rb_method_entry_t *me = rb_method_entry_alloc(called_id, klass, filter_defined_class(klass), def, false);
1261 METHOD_ENTRY_FLAGS_SET(me, visi, ruby_running ? FALSE : TRUE);
1262 if (def != NULL) method_definition_reset(me);
1263 return me;
1264}
1265
1266// Return a cloned ME that's not invalidated (MEs are disposable for caching).
1267const rb_method_entry_t *
1268rb_method_entry_clone(const rb_method_entry_t *src_me)
1269{
1270 rb_method_entry_t *me = rb_method_entry_alloc(src_me->called_id, src_me->owner, src_me->defined_class, src_me->def, METHOD_ENTRY_COMPLEMENTED(src_me));
1271
1272 METHOD_ENTRY_FLAGS_COPY(me, src_me);
1273
1274 // Also clone inner ME in case of refinement ME
1275 if (src_me->def &&
1276 src_me->def->type == VM_METHOD_TYPE_REFINED &&
1277 src_me->def->body.refined.orig_me) {
1278 const rb_method_entry_t *orig_me = src_me->def->body.refined.orig_me;
1279 VM_ASSERT(orig_me->def->type != VM_METHOD_TYPE_REFINED);
1280
1281 rb_method_entry_t *orig_clone = rb_method_entry_alloc(orig_me->called_id,
1282 orig_me->owner, orig_me->defined_class, orig_me->def, METHOD_ENTRY_COMPLEMENTED(orig_me));
1283 METHOD_ENTRY_FLAGS_COPY(orig_clone, orig_me);
1284
1285 // Clone definition, since writing a VALUE to a shared definition
1286 // can create reference edges we can't run WBs for.
1287 rb_method_definition_t *clone_def =
1288 rb_method_definition_create(VM_METHOD_TYPE_REFINED, src_me->called_id);
1289 rb_method_definition_set(me, clone_def, orig_clone);
1290 }
1291 return me;
1292}
1293
1295rb_method_entry_complement_defined_class(const rb_method_entry_t *src_me, ID called_id, VALUE defined_class)
1296{
1297 rb_method_definition_t *def = src_me->def;
1299 const rb_method_entry_t *refined_orig_me = NULL;
1300
1301 if (!src_me->defined_class &&
1302 def->type == VM_METHOD_TYPE_REFINED &&
1303 def->body.refined.orig_me) {
1304 const rb_method_entry_t *orig_me =
1305 rb_method_entry_clone(def->body.refined.orig_me);
1306 RB_OBJ_WRITE((VALUE)orig_me, &orig_me->defined_class, defined_class);
1307 refined_orig_me = orig_me;
1308 def = NULL;
1309 }
1310
1311 me = rb_method_entry_alloc(called_id, src_me->owner, defined_class, def, true);
1312 METHOD_ENTRY_FLAGS_COPY(me, src_me);
1313 METHOD_ENTRY_COMPLEMENTED_SET(me);
1314 if (!def) {
1315 def = rb_method_definition_create(VM_METHOD_TYPE_REFINED, called_id);
1316 rb_method_definition_set(me, def, (void *)refined_orig_me);
1317 }
1318
1319 VM_ASSERT_TYPE(me->owner, T_MODULE);
1320
1321 return (rb_callable_method_entry_t *)me;
1322}
1323
1324void
1325rb_method_entry_copy(rb_method_entry_t *dst, const rb_method_entry_t *src)
1326{
1327 method_definition_release(dst->def);
1328 *(rb_method_definition_t **)&dst->def = method_definition_addref(src->def, METHOD_ENTRY_COMPLEMENTED(src));
1329 method_definition_reset(dst);
1330 dst->called_id = src->called_id;
1331 RB_OBJ_WRITE((VALUE)dst, &dst->owner, src->owner);
1332 RB_OBJ_WRITE((VALUE)dst, &dst->defined_class, src->defined_class);
1333 METHOD_ENTRY_FLAGS_COPY(dst, src);
1334}
1335
1336static void
1337make_method_entry_refined(VALUE owner, rb_method_entry_t *me)
1338{
1339 if (me->def->type == VM_METHOD_TYPE_REFINED) {
1340 return;
1341 }
1342 else {
1344
1345 rb_vm_check_redefinition_opt_method(me, me->owner);
1346
1347 struct rb_method_entry_struct *orig_me =
1348 rb_method_entry_alloc(me->called_id,
1349 me->owner,
1350 me->defined_class,
1351 me->def,
1352 true);
1353 METHOD_ENTRY_FLAGS_COPY(orig_me, me);
1354
1355 def = rb_method_definition_create(VM_METHOD_TYPE_REFINED, me->called_id);
1356 rb_method_definition_set(me, def, orig_me);
1357 METHOD_ENTRY_VISI_SET(me, METHOD_VISI_PUBLIC);
1358 }
1359}
1360
1361static inline rb_method_entry_t *
1362lookup_method_table(VALUE klass, ID id)
1363{
1364 st_data_t body;
1365 struct rb_id_table *m_tbl = RCLASS_M_TBL(klass);
1366
1367 if (rb_id_table_lookup(m_tbl, id, &body)) {
1368 return (rb_method_entry_t *) body;
1369 }
1370 else {
1371 return 0;
1372 }
1373}
1374
1375void
1376rb_add_refined_method_entry(VALUE refined_class, ID mid)
1377{
1378 rb_method_entry_t *me = lookup_method_table(refined_class, mid);
1379
1380 if (me) {
1381 make_method_entry_refined(refined_class, me);
1382 rb_clear_method_cache(refined_class, mid);
1383 }
1384 else {
1385 rb_add_method(refined_class, mid, VM_METHOD_TYPE_REFINED, 0, METHOD_VISI_PUBLIC);
1386 }
1387}
1388
1389static void
1390check_override_opt_method_i(VALUE klass, VALUE arg)
1391{
1392 if (RB_TYPE_P(klass, T_ICLASS)) {
1393 // ICLASS from a module's subclass list: check the includer and
1394 // recurse into the includer's T_CLASS subclasses.
1395 VALUE includer = RCLASS_INCLUDER(klass);
1396 if (!UNDEF_P(includer) && includer) {
1397 check_override_opt_method_i(includer, arg);
1398 }
1399 return;
1400 }
1401
1402 ID mid = (ID)arg;
1403 const rb_method_entry_t *me, *newme;
1404
1405 if (vm_redefinition_check_flag(klass)) {
1406 me = lookup_method_table(RCLASS_ORIGIN(klass), mid);
1407 if (me) {
1408 newme = rb_method_entry(klass, mid);
1409 if (newme != me) rb_vm_check_redefinition_opt_method(me, me->owner);
1410 }
1411 }
1412 rb_class_foreach_subclass(klass, check_override_opt_method_i, (VALUE)mid);
1413}
1414
1415static void
1416check_override_opt_method(VALUE klass, VALUE mid)
1417{
1418 if (rb_vm_check_optimizable_mid(mid)) {
1419 check_override_opt_method_i(klass, mid);
1420 }
1421}
1422
1423VALUE
1424rb_zsuper_to_super(int argc, VALUE *argv, VALUE self)
1425{
1426 return rb_call_super_kw(argc, argv, RB_PASS_CALLED_KEYWORDS);
1427}
1428
1429static inline rb_method_entry_t* search_method0(VALUE klass, ID id, VALUE *defined_class_ptr, bool skip_refined);
1430/*
1431 * klass->method_table[mid] = method_entry(defined_class, visi, def)
1432 *
1433 * If def is given (!= NULL), then just use it and ignore original_id and otps.
1434 * If not given, then make a new def with original_id and opts.
1435 */
1436static rb_method_entry_t *
1437rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibility_t visi,
1438 rb_method_type_t type, rb_method_definition_t *def, ID original_id, void *opts)
1439{
1441 struct rb_id_table *mtbl;
1442 st_data_t data;
1443 int make_refined = 0;
1444 VALUE orig_klass;
1445 bool turn_zsuper_to_super = false;
1446
1447 if (NIL_P(klass)) {
1448 klass = rb_cObject;
1449 }
1450 orig_klass = klass;
1451
1452 if (!RCLASS_SINGLETON_P(klass) &&
1453 type != VM_METHOD_TYPE_NOTIMPLEMENTED &&
1454 type != VM_METHOD_TYPE_ZSUPER) {
1455 switch (mid) {
1456 case idInitialize:
1457 case idInitialize_copy:
1458 case idInitialize_clone:
1459 case idInitialize_dup:
1460 case idRespond_to_missing:
1461 visi = METHOD_VISI_PRIVATE;
1462 }
1463 }
1464
1465 if (type != VM_METHOD_TYPE_REFINED) {
1466 rb_class_modify_check(klass);
1467 }
1468
1469 if (RB_TYPE_P(klass, T_MODULE) && FL_TEST(klass, RMODULE_IS_REFINEMENT)) {
1470 VALUE refined_class = rb_refinement_module_get_refined_class(klass);
1471 if (type == VM_METHOD_TYPE_ZSUPER) {
1472 turn_zsuper_to_super = true;
1473 }
1474 rb_add_refined_method_entry(refined_class, mid);
1475 }
1476 if (type == VM_METHOD_TYPE_REFINED) {
1477 rb_method_entry_t *old_me = lookup_method_table(RCLASS_ORIGIN(klass), mid);
1478 if (old_me) rb_vm_check_redefinition_opt_method(old_me, klass);
1479 }
1480 else {
1481 klass = RCLASS_ORIGIN(klass);
1482 if (klass != orig_klass) {
1483 rb_clear_method_cache(orig_klass, mid);
1484 }
1485 }
1486 mtbl = RCLASS_WRITABLE_M_TBL(klass);
1487
1488 /* check re-definition */
1489 if (rb_id_table_lookup(mtbl, mid, &data)) {
1490 rb_method_entry_t *old_me = (rb_method_entry_t *)data;
1491 rb_method_definition_t *old_def = old_me->def;
1492
1493 if (rb_method_definition_eq(old_def, def)) return old_me;
1494 rb_vm_check_redefinition_opt_method(old_me, klass);
1495
1496 if (old_def->type == VM_METHOD_TYPE_REFINED) make_refined = 1;
1497
1498 if (RTEST(ruby_verbose) &&
1499 type != VM_METHOD_TYPE_UNDEF &&
1500 (old_def->aliased == false) &&
1501 (!old_def->no_redef_warning) &&
1502 !make_refined &&
1503 old_def->type != VM_METHOD_TYPE_UNDEF &&
1504 old_def->type != VM_METHOD_TYPE_ZSUPER &&
1505 old_def->type != VM_METHOD_TYPE_ALIAS) {
1506 const rb_iseq_t *iseq = 0;
1507
1508 switch (old_def->type) {
1509 case VM_METHOD_TYPE_ISEQ:
1510 iseq = def_iseq_ptr(old_def);
1511 break;
1512 case VM_METHOD_TYPE_BMETHOD:
1513 iseq = rb_proc_get_iseq(old_def->body.bmethod.proc, 0);
1514 break;
1515 default:
1516 break;
1517 }
1518 if (iseq) {
1519 rb_warning(
1520 "method redefined; discarding old %"PRIsVALUE"\n%"PRIsVALUE":%d: warning: previous definition of %"PRIsVALUE" was here",
1521 rb_id2str(mid),
1522 rb_iseq_path(iseq),
1523 ISEQ_BODY(iseq)->location.first_lineno,
1524 rb_id2str(old_def->original_id)
1525 );
1526 }
1527 else {
1528 rb_warning("method redefined; discarding old %"PRIsVALUE, rb_id2str(mid));
1529 }
1530 }
1531 }
1532
1533 /* create method entry */
1534 me = rb_method_entry_create(mid, defined_class, visi, NULL);
1535 if (def == NULL) {
1536 def = rb_method_definition_create(type, original_id);
1537 if (turn_zsuper_to_super) {
1538 def->type = VM_METHOD_TYPE_CFUNC;
1539 def->body.cfunc.func = (rb_cfunc_t)rb_zsuper_to_super;
1540 def->body.cfunc.invoker = ractor_safe_call_cfunc_m1;
1541 def->body.cfunc.argc = -1;
1542 }
1543 RB_OBJ_WRITE(me, &def->original_module, me->owner);
1544 }
1545 rb_method_definition_set(me, def, opts);
1546
1547 rb_clear_method_cache(klass, mid);
1548
1549 /* check mid */
1550 if (klass == rb_cObject) {
1551 switch (mid) {
1552 case idInitialize:
1553 case idRespond_to_missing:
1554 case idMethodMissing:
1555 case idRespond_to:
1556 rb_warn("redefining Object#%s may cause infinite loop", rb_id2name(mid));
1557 }
1558 }
1559 /* check mid */
1560 if (mid == object_id || mid == id__id__ || mid == id__send__) {
1561 if (type != VM_METHOD_TYPE_CFUNC && search_method(klass, mid, 0)) {
1562 rb_warn("redefining '%s' may cause serious problems", rb_id2name(mid));
1563 }
1564 }
1565
1566 if (make_refined) {
1567 make_method_entry_refined(klass, me);
1568 }
1569
1570 rb_method_table_insert(klass, mtbl, mid, me);
1571
1572 VM_ASSERT(me->def != NULL);
1573
1574 /* check optimized method override by a prepended module */
1575 if (RB_TYPE_P(orig_klass, T_MODULE)) {
1576 check_override_opt_method(klass, (VALUE)mid);
1577 }
1578
1579 return me;
1580}
1581
1582static st_table *
1583overloaded_cme_table(void)
1584{
1585 return &GET_VM()->overloaded_cme_table;
1586}
1587
1588#if VM_CHECK_MODE > 0
1589static int
1590vm_dump_overloaded_cme_table(st_data_t key, st_data_t val, st_data_t dmy)
1591{
1592 fprintf(stderr, "key: "); rp(key);
1593 fprintf(stderr, "val: "); rp(val);
1594 return ST_CONTINUE;
1595}
1596
1597void
1598rb_vm_dump_overloaded_cme_table(void)
1599{
1600 fprintf(stderr, "== rb_vm_dump_overloaded_cme_table\n");
1601 st_foreach(overloaded_cme_table(), vm_dump_overloaded_cme_table, 0);
1602}
1603#endif
1604
1605static int
1606lookup_overloaded_cme_i(st_data_t *key, st_data_t *value, st_data_t data, int existing)
1607{
1608 if (existing) {
1609 const rb_callable_method_entry_t *cme = (const rb_callable_method_entry_t *)*key;
1610 const rb_callable_method_entry_t *monly_cme = (const rb_callable_method_entry_t *)*value;
1611 const rb_callable_method_entry_t **ptr = (const rb_callable_method_entry_t **)data;
1612
1613 if (rb_objspace_garbage_object_p((VALUE)cme) ||
1614 rb_objspace_garbage_object_p((VALUE)monly_cme)) {
1615 *ptr = NULL;
1616 return ST_DELETE;
1617 }
1618 else {
1619 *ptr = monly_cme;
1620 }
1621 }
1622
1623 return ST_STOP;
1624}
1625
1626static const rb_callable_method_entry_t *
1627lookup_overloaded_cme(const rb_callable_method_entry_t *cme)
1628{
1629 ASSERT_vm_locking();
1630
1631 const rb_callable_method_entry_t *monly_cme = NULL;
1632 st_update(overloaded_cme_table(), (st_data_t)cme, lookup_overloaded_cme_i, (st_data_t)&monly_cme);
1633 return monly_cme;
1634}
1635
1636#if VM_CHECK_MODE > 0
1638rb_vm_lookup_overloaded_cme(const rb_callable_method_entry_t *cme)
1639{
1640 return lookup_overloaded_cme(cme);
1641}
1642#endif
1643
1644static void
1645delete_overloaded_cme(const rb_callable_method_entry_t *cme)
1646{
1647 st_data_t cme_data = (st_data_t)cme;
1648 ASSERT_vm_locking();
1649 st_delete(overloaded_cme_table(), &cme_data, NULL);
1650}
1651
1652static const rb_callable_method_entry_t *
1653get_overloaded_cme(const rb_callable_method_entry_t *cme)
1654{
1655 const rb_callable_method_entry_t *monly_cme = lookup_overloaded_cme(cme);
1656
1657 if (monly_cme && !METHOD_ENTRY_INVALIDATED(monly_cme)) {
1658 return monly_cme;
1659 }
1660 else {
1661 // create
1662 rb_method_definition_t *def = rb_method_definition_create(VM_METHOD_TYPE_ISEQ, cme->def->original_id);
1663 rb_method_entry_t *me = rb_method_entry_alloc(cme->called_id,
1664 cme->owner,
1665 cme->defined_class,
1666 def,
1667 false);
1668
1669 RB_OBJ_WRITE(me, &def->body.iseq.cref, cme->def->body.iseq.cref);
1670 RB_OBJ_WRITE(me, &def->body.iseq.iseqptr, ISEQ_BODY(cme->def->body.iseq.iseqptr)->mandatory_only_iseq);
1671 RB_OBJ_WRITE(me, &def->original_module, cme->def->original_module);
1672
1673 ASSERT_vm_locking();
1674 st_insert(overloaded_cme_table(), (st_data_t)cme, (st_data_t)me);
1675
1676 METHOD_ENTRY_VISI_SET(me, METHOD_ENTRY_VISI(cme));
1677 return (rb_callable_method_entry_t *)me;
1678 }
1679}
1680
1682rb_check_overloaded_cme(const rb_callable_method_entry_t *cme, const struct rb_callinfo * const ci)
1683{
1684 if (UNLIKELY(cme->def->iseq_overload) &&
1685 (vm_ci_flag(ci) & (VM_CALL_ARGS_SIMPLE)) &&
1686 (!(vm_ci_flag(ci) & VM_CALL_FORWARDING)) &&
1687 (int)vm_ci_argc(ci) == ISEQ_BODY(method_entry_iseqptr(cme))->param.lead_num) {
1688 VM_ASSERT(cme->def->type == VM_METHOD_TYPE_ISEQ, "type: %d", cme->def->type); // iseq_overload is marked only on ISEQ methods
1689
1690 cme = get_overloaded_cme(cme);
1691
1692 VM_ASSERT(cme != NULL);
1693 METHOD_ENTRY_CACHED_SET((struct rb_callable_method_entry_struct *)cme);
1694 }
1695
1696 return cme;
1697}
1698
1699#define CALL_METHOD_HOOK(klass, hook, mid) do { \
1700 const VALUE arg = ID2SYM(mid); \
1701 VALUE recv_class = (klass); \
1702 ID hook_id = (hook); \
1703 if (RCLASS_SINGLETON_P((klass))) { \
1704 recv_class = RCLASS_ATTACHED_OBJECT((klass)); \
1705 hook_id = singleton_##hook; \
1706 } \
1707 rb_funcallv(recv_class, hook_id, 1, &arg); \
1708 } while (0)
1709
1710static void
1711method_added(VALUE klass, ID mid, const rb_method_entry_t *me)
1712{
1713 if (ruby_running) {
1714 /* [Bug #22179] Record the just-defined method entry for method coverage
1715 * so the result no longer depends on walking the heap (and thus on GC
1716 * timing). */
1717 if (me) rb_vm_coverage_record_me(me);
1718 CALL_METHOD_HOOK(klass, added, mid);
1719 }
1720}
1721
1722void
1723rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_visibility_t visi)
1724{
1725 const rb_method_entry_t *me;
1726 RB_VM_LOCKING() {
1727 me = rb_method_entry_make(klass, mid, klass, visi, type, NULL, mid, opts);
1728 }
1729
1730 if (type != VM_METHOD_TYPE_UNDEF && type != VM_METHOD_TYPE_REFINED) {
1731 method_added(klass, mid, me);
1732 }
1733}
1734
1735void
1736rb_add_method_iseq(VALUE klass, ID mid, const rb_iseq_t *iseq, rb_cref_t *cref, rb_method_visibility_t visi)
1737{
1738 struct { /* should be same fields with rb_method_iseq_struct */
1739 const rb_iseq_t *iseqptr;
1740 rb_cref_t *cref;
1741 } iseq_body;
1742
1743 iseq_body.iseqptr = iseq;
1744 iseq_body.cref = cref;
1745
1746 rb_add_method(klass, mid, VM_METHOD_TYPE_ISEQ, &iseq_body, visi);
1747}
1748
1749static rb_method_entry_t *
1750method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *me,
1751 rb_method_visibility_t visi, VALUE defined_class)
1752{
1753 rb_method_entry_t *newme;
1754 RB_VM_LOCKING() {
1755 newme = rb_method_entry_make(klass, mid, defined_class, visi,
1756 me->def->type, me->def, 0, NULL);
1757 if (newme == me) {
1758 me->def->no_redef_warning = TRUE;
1759 METHOD_ENTRY_FLAGS_SET(newme, visi, FALSE);
1760 }
1761 }
1762
1763 method_added(klass, mid, newme);
1764 return newme;
1765}
1766
1768rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *me, rb_method_visibility_t visi)
1769{
1770 return method_entry_set(klass, mid, me, visi, klass);
1771}
1772
1773#define UNDEF_ALLOC_FUNC ((rb_alloc_func_t)-1)
1774
1775static void
1776propagate_alloc_func(VALUE subclass, VALUE arg)
1777{
1778 if (RB_TYPE_P(subclass, T_CLASS) &&
1779 !RCLASS_SINGLETON_P(subclass) &&
1780 !FL_TEST_RAW(subclass, RCLASS_ALLOCATOR_DEFINED)) {
1781 RCLASS_SET_ALLOCATOR(subclass, (rb_alloc_func_t)arg);
1782 rb_class_foreach_subclass(subclass, propagate_alloc_func, arg);
1783 }
1784}
1785
1786void
1787rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE))
1788{
1789 Check_Type(klass, T_CLASS);
1790 if (RCLASS_SINGLETON_P(klass)) {
1791 rb_raise(rb_eTypeError, "can't define an allocator for a singleton class");
1792 }
1793 RCLASS_SET_ALLOCATOR(klass, func);
1794 FL_SET_RAW(klass, RCLASS_ALLOCATOR_DEFINED);
1795 rb_class_foreach_subclass(klass, propagate_alloc_func, (VALUE)func);
1796}
1797
1798void
1800{
1801 Check_Type(klass, T_CLASS);
1802 RCLASS_SET_ALLOCATOR(klass, UNDEF_ALLOC_FUNC);
1803 FL_SET_RAW(klass, RCLASS_ALLOCATOR_DEFINED);
1804 rb_class_foreach_subclass(klass, propagate_alloc_func, (VALUE)UNDEF_ALLOC_FUNC);
1805}
1806
1809{
1810 RBIMPL_ASSERT_TYPE(klass, T_CLASS);
1811
1812 rb_alloc_func_t allocator = RCLASS_ALLOCATOR(klass);
1813 if (allocator == UNDEF_ALLOC_FUNC) return 0;
1814 RUBY_ASSERT(allocator);
1815 return allocator;
1816}
1817
1818const rb_method_entry_t *
1819rb_method_entry_at(VALUE klass, ID id)
1820{
1821 return lookup_method_table(klass, id);
1822}
1823
1824static inline rb_method_entry_t*
1825search_method0(VALUE klass, ID id, VALUE *defined_class_ptr, bool skip_refined)
1826{
1827 rb_method_entry_t *me = NULL;
1828
1829 RB_DEBUG_COUNTER_INC(mc_search);
1830
1831 for (; klass; klass = RCLASS_SUPER(klass)) {
1832 RB_DEBUG_COUNTER_INC(mc_search_super);
1833 if ((me = lookup_method_table(klass, id)) != 0) {
1834 if (!skip_refined || me->def->type != VM_METHOD_TYPE_REFINED ||
1835 me->def->body.refined.orig_me) {
1836 break;
1837 }
1838 }
1839 }
1840
1841 if (defined_class_ptr) *defined_class_ptr = klass;
1842
1843 if (me == NULL) RB_DEBUG_COUNTER_INC(mc_search_notfound);
1844
1845 VM_ASSERT(me == NULL || !METHOD_ENTRY_INVALIDATED(me),
1846 "invalid me, mid:%s, klass:%"PRIsVALUE"(%s)",
1847 rb_id2name(id),
1848 RTEST(rb_mod_name(klass)) ? rb_mod_name(klass) : rb_str_new_lit("anonymous"),
1849 rb_obj_info(klass));
1850 return me;
1851}
1852
1853static inline rb_method_entry_t*
1854search_method(VALUE klass, ID id, VALUE *defined_class_ptr)
1855{
1856 return search_method0(klass, id, defined_class_ptr, false);
1857}
1858
1859static rb_method_entry_t *
1860search_method_protect(VALUE klass, ID id, VALUE *defined_class_ptr)
1861{
1862 rb_method_entry_t *me = search_method(klass, id, defined_class_ptr);
1863
1864 if (!UNDEFINED_METHOD_ENTRY_P(me)) {
1865 return me;
1866 }
1867 else {
1868 return NULL;
1869 }
1870}
1871
1872const rb_method_entry_t *
1873rb_method_entry(VALUE klass, ID id)
1874{
1875 return search_method_protect(klass, id, NULL);
1876}
1877
1878static inline const rb_callable_method_entry_t *
1879prepare_callable_method_entry(VALUE defined_class, ID id, const rb_method_entry_t * const me, int create)
1880{
1881 struct rb_id_table *mtbl;
1882 const rb_callable_method_entry_t *cme;
1883 VALUE cme_data;
1884 int cme_found = 0;
1885
1886 if (me) {
1887 if (me->defined_class == 0) {
1888 RB_DEBUG_COUNTER_INC(mc_cme_complement);
1889 VM_ASSERT_TYPE2(defined_class, T_ICLASS, T_MODULE);
1890
1891 mtbl = RCLASS_WRITABLE_CALLABLE_M_TBL(defined_class);
1892 if (mtbl && rb_id_table_lookup(mtbl, id, &cme_data)) {
1893 cme = (rb_callable_method_entry_t *)cme_data;
1894 cme_found = 1;
1895 }
1896 if (cme_found) {
1897 RB_DEBUG_COUNTER_INC(mc_cme_complement_hit);
1898 VM_ASSERT(callable_method_entry_p(cme));
1899 VM_ASSERT(!METHOD_ENTRY_INVALIDATED(cme));
1900 }
1901 else if (create) {
1902 if (!mtbl) {
1903 mtbl = rb_id_table_create(0);
1904 RCLASS_WRITE_CALLABLE_M_TBL(defined_class, mtbl);
1905 }
1906 cme = rb_method_entry_complement_defined_class(me, me->called_id, defined_class);
1907 rb_id_table_insert(mtbl, id, (VALUE)cme);
1908 RB_OBJ_WRITTEN(defined_class, Qundef, (VALUE)cme);
1909 VM_ASSERT(callable_method_entry_p(cme));
1910 }
1911 else {
1912 return NULL;
1913 }
1914 }
1915 else {
1916 cme = (const rb_callable_method_entry_t *)me;
1917 VM_ASSERT(callable_method_entry_p(cme));
1918 VM_ASSERT(!METHOD_ENTRY_INVALIDATED(cme));
1919 }
1920 return cme;
1921 }
1922 else {
1923 return NULL;
1924 }
1925}
1926
1927static const rb_callable_method_entry_t *
1928complemented_callable_method_entry(VALUE klass, ID id)
1929{
1930 VALUE defined_class;
1931 rb_method_entry_t *me = search_method(klass, id, &defined_class);
1932 return prepare_callable_method_entry(defined_class, id, me, FALSE);
1933}
1934
1935static const rb_callable_method_entry_t *
1936cached_callable_method_entry(VALUE klass, ID mid)
1937{
1938 ASSERT_vm_locking();
1939
1940 VALUE cc_tbl = RCLASS_WRITABLE_CC_TBL(klass);
1941 VALUE ccs_data;
1942
1943 if (cc_tbl && rb_managed_id_table_lookup(cc_tbl, mid, &ccs_data)) {
1944 struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_data;
1945 VM_ASSERT(vm_ccs_p(ccs));
1946
1947 if (LIKELY(!METHOD_ENTRY_INVALIDATED(ccs->cme))) {
1948 VM_ASSERT(ccs->cme->called_id == mid);
1949 RB_DEBUG_COUNTER_INC(ccs_found);
1950 return ccs->cme;
1951 }
1952 else {
1953 rb_vm_barrier();
1954
1955 rb_managed_id_table_delete(cc_tbl, mid);
1956 rb_vm_ccs_invalidate_and_free(ccs);
1957 }
1958 }
1959
1960 RB_DEBUG_COUNTER_INC(ccs_not_found);
1961 return NULL;
1962}
1963
1964static void
1965cache_callable_method_entry(VALUE klass, ID mid, const rb_callable_method_entry_t *cme)
1966{
1967 ASSERT_vm_locking();
1968 VM_ASSERT(cme != NULL);
1969
1970 VALUE cc_tbl = RCLASS_WRITABLE_CC_TBL(klass);
1971 VALUE ccs_data;
1972
1973 if (!cc_tbl) {
1974 cc_tbl = rb_vm_cc_table_create(2);
1975 RCLASS_WRITE_CC_TBL(klass, cc_tbl);
1976 }
1977
1978 if (rb_managed_id_table_lookup(cc_tbl, mid, &ccs_data)) {
1979#if VM_CHECK_MODE > 0
1980 struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_data;
1981 VM_ASSERT(ccs->cme == cme);
1982#endif
1983 }
1984 else {
1985 if (rb_multi_ractor_p()) {
1986 VALUE new_cc_tbl = rb_vm_cc_table_dup(cc_tbl);
1987 vm_ccs_create(klass, new_cc_tbl, mid, cme);
1988 RB_OBJ_ATOMIC_WRITE(klass, &RCLASSEXT_CC_TBL(RCLASS_EXT_WRITABLE(klass)), new_cc_tbl);
1989 }
1990 else {
1991 vm_ccs_create(klass, cc_tbl, mid, cme);
1992 }
1993 }
1994}
1995
1996static const rb_callable_method_entry_t *
1997negative_cme(ID mid)
1998{
1999 rb_vm_t *vm = GET_VM();
2000 const rb_callable_method_entry_t *cme;
2001 VALUE cme_data;
2002
2003 if (rb_id_table_lookup(&vm->negative_cme_table, mid, &cme_data)) {
2004 cme = (rb_callable_method_entry_t *)cme_data;
2005 }
2006 else {
2007 cme = (rb_callable_method_entry_t *)rb_method_entry_alloc(mid, Qnil, Qnil, NULL, false);
2008 rb_id_table_insert(&vm->negative_cme_table, mid, (VALUE)cme);
2009 }
2010
2011 VM_ASSERT(cme != NULL);
2012 return cme;
2013}
2014
2015static const rb_callable_method_entry_t *
2016callable_method_entry_or_negative(VALUE klass, ID mid, VALUE *defined_class_ptr)
2017{
2018 const rb_callable_method_entry_t *cme;
2019
2020 VM_ASSERT(!SPECIAL_CONST_P(klass));
2021
2022 if (RB_BUILTIN_TYPE(klass) == T_NONE) {
2023 // If we find a T_NONE here, it's most likely we called CLASS_OF(obj) on a
2024 // garbage collected object (the freelist is stored in the class pointer),
2025 // but it's possible that just the class was GC'd.
2026 // This message intentionally tries to imply the former, but make an
2027 // accurate statement for either case.
2028 rb_bug("attempted to search method '%s' on a garbage collected object",
2029 rb_id2name(mid));
2030 }
2031
2032 VM_ASSERT_TYPE2(klass, T_CLASS, T_ICLASS);
2033
2034 /* Fast path: lock-free read from cache */
2035 VALUE cc_tbl = RUBY_ATOMIC_VALUE_LOAD(RCLASS_WRITABLE_CC_TBL(klass));
2036 if (cc_tbl) {
2037 VALUE ccs_data;
2038 if (rb_managed_id_table_lookup(cc_tbl, mid, &ccs_data)) {
2039 struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_data;
2040 VM_ASSERT(vm_ccs_p(ccs));
2041
2042 if (LIKELY(!METHOD_ENTRY_INVALIDATED(ccs->cme))) {
2043 VM_ASSERT(ccs->cme->called_id == mid);
2044 if (defined_class_ptr != NULL) *defined_class_ptr = ccs->cme->defined_class;
2045 RB_DEBUG_COUNTER_INC(ccs_found);
2046 return ccs->cme;
2047 }
2048 }
2049 }
2050
2051 /* Slow path: need to lock and potentially populate cache */
2052 RB_VM_LOCKING() {
2053 cme = cached_callable_method_entry(klass, mid);
2054
2055 if (cme) {
2056 if (defined_class_ptr != NULL) *defined_class_ptr = cme->defined_class;
2057 }
2058 else {
2059 VALUE defined_class;
2060 rb_method_entry_t *me = search_method(klass, mid, &defined_class);
2061 if (defined_class_ptr) *defined_class_ptr = defined_class;
2062
2063 if (me != NULL) {
2064 cme = prepare_callable_method_entry(defined_class, mid, me, TRUE);
2065 }
2066 else {
2067 cme = negative_cme(mid);
2068 }
2069
2070 cache_callable_method_entry(klass, mid, cme);
2071 }
2072 }
2073
2074 return cme;
2075}
2076
2077// This is exposed for YJIT so that we can make assumptions that methods are
2078// not defined.
2080rb_callable_method_entry_or_negative(VALUE klass, ID mid)
2081{
2082 return callable_method_entry_or_negative(klass, mid, NULL);
2083}
2084
2085static const rb_callable_method_entry_t *
2086callable_method_entry(VALUE klass, ID mid, VALUE *defined_class_ptr)
2087{
2088 const rb_callable_method_entry_t *cme;
2089 cme = callable_method_entry_or_negative(klass, mid, defined_class_ptr);
2090 return !UNDEFINED_METHOD_ENTRY_P(cme) ? cme : NULL;
2091}
2092
2094rb_callable_method_entry(VALUE klass, ID mid)
2095{
2096 return callable_method_entry(klass, mid, NULL);
2097}
2098
2099static const rb_method_entry_t *resolve_refined_method(VALUE refinements, const rb_method_entry_t *me, VALUE *defined_class_ptr);
2100
2101static const rb_method_entry_t *
2102method_entry_resolve_refinement(VALUE klass, ID id, int with_refinement, VALUE *defined_class_ptr)
2103{
2104 const rb_method_entry_t *me = search_method_protect(klass, id, defined_class_ptr);
2105
2106 if (me) {
2107 if (me->def->type == VM_METHOD_TYPE_REFINED) {
2108 if (with_refinement) {
2109 const rb_cref_t *cref = rb_vm_cref();
2110 VALUE refinements = cref ? CREF_REFINEMENTS(cref) : Qnil;
2111 me = resolve_refined_method(refinements, me, defined_class_ptr);
2112 }
2113 else {
2114 me = resolve_refined_method(Qnil, me, defined_class_ptr);
2115 }
2116
2117 if (UNDEFINED_METHOD_ENTRY_P(me)) me = NULL;
2118 }
2119 }
2120
2121 return me;
2122}
2123
2124const rb_method_entry_t *
2125rb_method_entry_with_refinements(VALUE klass, ID id, VALUE *defined_class_ptr)
2126{
2127 return method_entry_resolve_refinement(klass, id, TRUE, defined_class_ptr);
2128}
2129
2130static const rb_callable_method_entry_t *
2131callable_method_entry_refinements0(VALUE klass, ID id, VALUE *defined_class_ptr, bool with_refinements,
2132 const rb_callable_method_entry_t *cme)
2133{
2134 if (cme == NULL || LIKELY(cme->def->type != VM_METHOD_TYPE_REFINED)) {
2135 return cme;
2136 }
2137 else {
2138 VALUE defined_class, *dcp = defined_class_ptr ? defined_class_ptr : &defined_class;
2139 const rb_method_entry_t *me = method_entry_resolve_refinement(klass, id, with_refinements, dcp);
2140 return prepare_callable_method_entry(*dcp, id, me, TRUE);
2141 }
2142}
2143
2144static const rb_callable_method_entry_t *
2145callable_method_entry_refinements(VALUE klass, ID id, VALUE *defined_class_ptr, bool with_refinements)
2146{
2147 const rb_callable_method_entry_t *cme = callable_method_entry(klass, id, defined_class_ptr);
2148 return callable_method_entry_refinements0(klass, id, defined_class_ptr, with_refinements, cme);
2149}
2150
2152rb_callable_method_entry_with_refinements(VALUE klass, ID id, VALUE *defined_class_ptr)
2153{
2154 return callable_method_entry_refinements(klass, id, defined_class_ptr, true);
2155}
2156
2157static const rb_callable_method_entry_t *
2158callable_method_entry_without_refinements(VALUE klass, ID id, VALUE *defined_class_ptr)
2159{
2160 return callable_method_entry_refinements(klass, id, defined_class_ptr, false);
2161}
2162
2163const rb_method_entry_t *
2164rb_method_entry_without_refinements(VALUE klass, ID id, VALUE *defined_class_ptr)
2165{
2166 return method_entry_resolve_refinement(klass, id, FALSE, defined_class_ptr);
2167}
2168
2170rb_callable_method_entry_without_refinements(VALUE klass, ID id, VALUE *defined_class_ptr)
2171{
2172 VALUE defined_class, *dcp = defined_class_ptr ? defined_class_ptr : &defined_class;
2173 const rb_method_entry_t *me = method_entry_resolve_refinement(klass, id, FALSE, dcp);
2174 return prepare_callable_method_entry(*dcp, id, me, TRUE);
2175}
2176
2177static const rb_method_entry_t *
2178resolve_refined_method(VALUE refinements, const rb_method_entry_t *me, VALUE *defined_class_ptr)
2179{
2180 while (me && me->def->type == VM_METHOD_TYPE_REFINED) {
2181 VALUE refinement;
2182 const rb_method_entry_t *tmp_me;
2183 VALUE super;
2184
2185 refinement = find_refinement(refinements, me->owner);
2186 if (!NIL_P(refinement)) {
2187 tmp_me = search_method_protect(refinement, me->called_id, defined_class_ptr);
2188
2189 if (tmp_me && tmp_me->def->type != VM_METHOD_TYPE_REFINED) {
2190 return tmp_me;
2191 }
2192 }
2193
2194 tmp_me = me->def->body.refined.orig_me;
2195 if (tmp_me) {
2196 if (!tmp_me->defined_class) {
2197 VM_ASSERT_TYPE(tmp_me->owner, T_MODULE);
2198 }
2199 else if (defined_class_ptr) {
2200 *defined_class_ptr = tmp_me->defined_class;
2201 }
2202 return tmp_me;
2203 }
2204
2205 super = RCLASS_SUPER(me->owner);
2206 if (!super) {
2207 return 0;
2208 }
2209
2210 me = search_method_protect(super, me->called_id, defined_class_ptr);
2211 }
2212 return me;
2213}
2214
2215const rb_method_entry_t *
2216rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me)
2217{
2218 return resolve_refined_method(refinements, me, NULL);
2219}
2220
2222rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me)
2223{
2224 VALUE defined_class = me->defined_class;
2225 const rb_method_entry_t *resolved_me = resolve_refined_method(refinements, (const rb_method_entry_t *)me, &defined_class);
2226
2227 if (resolved_me && resolved_me->defined_class == 0) {
2228 return rb_method_entry_complement_defined_class(resolved_me, me->called_id, defined_class);
2229 }
2230 else {
2231 return (const rb_callable_method_entry_t *)resolved_me;
2232 }
2233}
2234
2235static void
2236remove_method(VALUE klass, ID mid)
2237{
2238 VALUE data;
2239 rb_method_entry_t *me = 0;
2240 VALUE self = klass;
2241
2242 rb_class_modify_check(klass);
2243 klass = RCLASS_ORIGIN(klass);
2244 if (mid == object_id || mid == id__id__ || mid == id__send__ || mid == idInitialize) {
2245 rb_warn("removing '%s' may cause serious problems", rb_id2name(mid));
2246 }
2247
2248 if (!rb_id_table_lookup(RCLASS_M_TBL(klass), mid, &data) ||
2249 !(me = (rb_method_entry_t *)data) ||
2250 (!me->def || me->def->type == VM_METHOD_TYPE_UNDEF) ||
2251 UNDEFINED_REFINED_METHOD_P(me->def)) {
2252 rb_name_err_raise("method '%1$s' not defined in %2$s",
2253 klass, ID2SYM(mid));
2254 }
2255
2256 if (klass != self) {
2257 rb_clear_method_cache(self, mid);
2258 }
2259 rb_clear_method_cache(klass, mid);
2260 rb_id_table_delete(RCLASS_WRITABLE_M_TBL(klass), mid);
2261
2262 rb_vm_check_redefinition_opt_method(me, klass);
2263
2264 if (me->def->type == VM_METHOD_TYPE_REFINED) {
2265 rb_add_refined_method_entry(klass, mid);
2266 }
2267
2268 CALL_METHOD_HOOK(self, removed, mid);
2269}
2270
2271void
2273{
2274 remove_method(klass, mid);
2275}
2276
2277void
2278rb_remove_method(VALUE klass, const char *name)
2279{
2280 remove_method(klass, rb_intern(name));
2281}
2282
2283/*
2284 * call-seq:
2285 * remove_method(symbol) -> self
2286 * remove_method(string) -> self
2287 *
2288 * Removes the method identified by _symbol_ from the current
2289 * class. For an example, see Module#undef_method.
2290 * String arguments are converted to symbols.
2291 */
2292
2293static VALUE
2294rb_mod_remove_method(int argc, VALUE *argv, VALUE mod)
2295{
2296 int i;
2297
2298 for (i = 0; i < argc; i++) {
2299 VALUE v = argv[i];
2300 ID id = rb_check_id(&v);
2301 if (!id) {
2302 rb_name_err_raise("method '%1$s' not defined in %2$s",
2303 mod, v);
2304 }
2305 remove_method(mod, id);
2306 }
2307 return mod;
2308}
2309
2310static void
2311rb_export_method(VALUE klass, ID name, rb_method_visibility_t visi)
2312{
2314 VALUE defined_class;
2315 VALUE origin_class = RCLASS_ORIGIN(klass);
2316
2317 me = search_method0(origin_class, name, &defined_class, true);
2318
2319 if (!me && RB_TYPE_P(klass, T_MODULE)) {
2320 me = search_method(rb_cObject, name, &defined_class);
2321 }
2322
2323 if (UNDEFINED_METHOD_ENTRY_P(me) ||
2324 UNDEFINED_REFINED_METHOD_P(me->def)) {
2325 rb_print_undef(klass, name, METHOD_VISI_UNDEF);
2326 }
2327
2328 if (METHOD_ENTRY_VISI(me) != visi) {
2329 rb_vm_check_redefinition_opt_method(me, klass);
2330
2331 if (klass == defined_class || origin_class == defined_class) {
2332 if (me->def->type == VM_METHOD_TYPE_REFINED) {
2333 // Refinement method entries should always be public because the refinement
2334 // search is always performed.
2335 if (me->def->body.refined.orig_me) {
2336 METHOD_ENTRY_VISI_SET((rb_method_entry_t *)me->def->body.refined.orig_me, visi);
2337 }
2338 }
2339 else {
2340 METHOD_ENTRY_VISI_SET(me, visi);
2341 }
2342 rb_clear_method_cache(klass, name);
2343 }
2344 else {
2345 rb_add_method(klass, name, VM_METHOD_TYPE_ZSUPER, 0, visi);
2346 }
2347 }
2348}
2349
2350#define BOUND_PRIVATE 0x01
2351#define BOUND_RESPONDS 0x02
2352
2353static int
2354method_boundp(VALUE klass, ID id, int ex)
2355{
2356 const rb_callable_method_entry_t *cme;
2357
2358 VM_ASSERT_TYPE2(klass, T_CLASS, T_ICLASS);
2359
2360 if (ex & BOUND_RESPONDS) {
2361 cme = rb_callable_method_entry_with_refinements(klass, id, NULL);
2362 }
2363 else {
2364 cme = callable_method_entry_without_refinements(klass, id, NULL);
2365 }
2366
2367 if (cme != NULL) {
2368 if (ex & ~BOUND_RESPONDS) {
2369 switch (METHOD_ENTRY_VISI(cme)) {
2370 case METHOD_VISI_PRIVATE:
2371 return 0;
2372 case METHOD_VISI_PROTECTED:
2373 if (ex & BOUND_RESPONDS) return 0;
2374 default:
2375 break;
2376 }
2377 }
2378
2379 if (cme->def->type == VM_METHOD_TYPE_NOTIMPLEMENTED) {
2380 if (ex & BOUND_RESPONDS) return 2;
2381 return 0;
2382 }
2383 return 1;
2384 }
2385 return 0;
2386}
2387
2388// deprecated
2389int
2390rb_method_boundp(VALUE klass, ID id, int ex)
2391{
2392 return method_boundp(klass, id, ex);
2393}
2394
2395static void
2396vm_cref_set_visibility(rb_method_visibility_t method_visi, int module_func)
2397{
2398 rb_scope_visibility_t *scope_visi = (rb_scope_visibility_t *)&rb_vm_cref()->scope_visi;
2399 scope_visi->method_visi = method_visi;
2400 scope_visi->module_func = module_func;
2401}
2402
2403void
2404rb_scope_visibility_set(rb_method_visibility_t visi)
2405{
2406 vm_cref_set_visibility(visi, FALSE);
2407}
2408
2409static void
2410scope_visibility_check(void)
2411{
2412 /* Check for public/protected/private/module_function called inside a method */
2413 rb_control_frame_t *cfp = GET_EC()->cfp+1;
2414 if (cfp && CFP_ISEQ(cfp) && ISEQ_BODY(CFP_ISEQ(cfp))->type == ISEQ_TYPE_METHOD) {
2415 rb_warn("calling %s without arguments inside a method may not have the intended effect",
2416 rb_id2name(rb_frame_this_func()));
2417 }
2418}
2419
2420static void
2421rb_scope_module_func_set(void)
2422{
2423 scope_visibility_check();
2424 vm_cref_set_visibility(METHOD_VISI_PRIVATE, TRUE);
2425}
2426
2427const rb_cref_t *rb_vm_cref_in_context(VALUE self, VALUE cbase);
2428void
2429rb_attr(VALUE klass, ID id, int read, int write, int ex)
2430{
2431 ID attriv;
2432 rb_method_visibility_t visi;
2433 const rb_execution_context_t *ec = GET_EC();
2434 const rb_cref_t *cref = rb_vm_cref_in_context(klass, klass);
2435
2436 if (!ex || !cref) {
2437 visi = METHOD_VISI_PUBLIC;
2438 }
2439 else {
2440 switch (vm_scope_visibility_get(ec)) {
2441 case METHOD_VISI_PRIVATE:
2442 if (vm_scope_module_func_check(ec)) {
2443 rb_warning("attribute accessor as module_function");
2444 }
2445 visi = METHOD_VISI_PRIVATE;
2446 break;
2447 case METHOD_VISI_PROTECTED:
2448 visi = METHOD_VISI_PROTECTED;
2449 break;
2450 default:
2451 visi = METHOD_VISI_PUBLIC;
2452 break;
2453 }
2454 }
2455
2456 attriv = rb_intern_str(rb_sprintf("@%"PRIsVALUE, rb_id2str(id)));
2457 if (read) {
2458 rb_add_method(klass, id, VM_METHOD_TYPE_IVAR, (void *)attriv, visi);
2459 }
2460 if (write) {
2461 rb_add_method(klass, rb_id_attrset(id), VM_METHOD_TYPE_ATTRSET, (void *)attriv, visi);
2462 }
2463}
2464
2465void
2467{
2468 const rb_method_entry_t *me;
2469
2470 if (NIL_P(klass)) {
2471 rb_raise(rb_eTypeError, "no class to undef method");
2472 }
2473 rb_class_modify_check(klass);
2474 if (id == object_id || id == id__id__ || id == id__send__ || id == idInitialize) {
2475 rb_warn("undefining '%s' may cause serious problems", rb_id2name(id));
2476 }
2477
2478 me = search_method(klass, id, 0);
2479 if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
2480 me = rb_resolve_refined_method(Qnil, me);
2481 }
2482
2483 if (UNDEFINED_METHOD_ENTRY_P(me) ||
2484 UNDEFINED_REFINED_METHOD_P(me->def)) {
2485 rb_method_name_error(klass, rb_id2str(id));
2486 }
2487
2488 rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, METHOD_VISI_PUBLIC);
2489
2490 CALL_METHOD_HOOK(klass, undefined, id);
2491}
2492
2493/*
2494 * call-seq:
2495 * undef_method(symbol) -> self
2496 * undef_method(string) -> self
2497 *
2498 * Prevents the current class from responding to calls to the named
2499 * method. Contrast this with <code>remove_method</code>, which deletes
2500 * the method from the particular class; Ruby will still search
2501 * superclasses and mixed-in modules for a possible receiver.
2502 * String arguments are converted to symbols.
2503 *
2504 * class Parent
2505 * def hello
2506 * puts "In parent"
2507 * end
2508 * end
2509 * class Child < Parent
2510 * def hello
2511 * puts "In child"
2512 * end
2513 * end
2514 *
2515 *
2516 * c = Child.new
2517 * c.hello
2518 *
2519 *
2520 * class Child
2521 * remove_method :hello # remove from child, still in parent
2522 * end
2523 * c.hello
2524 *
2525 *
2526 * class Child
2527 * undef_method :hello # prevent any calls to 'hello'
2528 * end
2529 * c.hello
2530 *
2531 * <em>produces:</em>
2532 *
2533 * In child
2534 * In parent
2535 * prog.rb:23: undefined method 'hello' for #<Child:0x401b3bb4> (NoMethodError)
2536 */
2537
2538static VALUE
2539rb_mod_undef_method(int argc, VALUE *argv, VALUE mod)
2540{
2541 int i;
2542 for (i = 0; i < argc; i++) {
2543 VALUE v = argv[i];
2544 ID id = rb_check_id(&v);
2545 if (!id) {
2546 rb_method_name_error(mod, v);
2547 }
2548 rb_undef(mod, id);
2549 }
2550 return mod;
2551}
2552
2553static rb_method_visibility_t
2554check_definition_visibility(VALUE mod, int argc, VALUE *argv)
2555{
2556 const rb_method_entry_t *me;
2557 VALUE mid, include_super, lookup_mod = mod;
2558 int inc_super;
2559 ID id;
2560
2561 rb_scan_args(argc, argv, "11", &mid, &include_super);
2562 id = rb_check_id(&mid);
2563 if (!id) return METHOD_VISI_UNDEF;
2564
2565 if (argc == 1) {
2566 inc_super = 1;
2567 }
2568 else {
2569 inc_super = RTEST(include_super);
2570 if (!inc_super) {
2571 lookup_mod = RCLASS_ORIGIN(mod);
2572 }
2573 }
2574
2575 me = rb_method_entry_without_refinements(lookup_mod, id, NULL);
2576 if (me) {
2577 if (me->def->type == VM_METHOD_TYPE_NOTIMPLEMENTED) return METHOD_VISI_UNDEF;
2578 if (!inc_super && me->owner != mod) return METHOD_VISI_UNDEF;
2579 return METHOD_ENTRY_VISI(me);
2580 }
2581 return METHOD_VISI_UNDEF;
2582}
2583
2584/*
2585 * call-seq:
2586 * mod.method_defined?(symbol, inherit=true) -> true or false
2587 * mod.method_defined?(string, inherit=true) -> true or false
2588 *
2589 * Returns +true+ if the named method is defined by
2590 * _mod_. If _inherit_ is set, the lookup will also search _mod_'s
2591 * ancestors. Public and protected methods are matched.
2592 * String arguments are converted to symbols.
2593 *
2594 * module A
2595 * def method1() end
2596 * def protected_method1() end
2597 * protected :protected_method1
2598 * end
2599 * class B
2600 * def method2() end
2601 * def private_method2() end
2602 * private :private_method2
2603 * end
2604 * class C < B
2605 * include A
2606 * def method3() end
2607 * end
2608 *
2609 * A.method_defined? :method1 #=> true
2610 * C.method_defined? "method1" #=> true
2611 * C.method_defined? "method2" #=> true
2612 * C.method_defined? "method2", true #=> true
2613 * C.method_defined? "method2", false #=> false
2614 * C.method_defined? "method3" #=> true
2615 * C.method_defined? "protected_method1" #=> true
2616 * C.method_defined? "method4" #=> false
2617 * C.method_defined? "private_method2" #=> false
2618 */
2619
2620static VALUE
2621rb_mod_method_defined(int argc, VALUE *argv, VALUE mod)
2622{
2623 rb_method_visibility_t visi = check_definition_visibility(mod, argc, argv);
2624 return RBOOL(visi == METHOD_VISI_PUBLIC || visi == METHOD_VISI_PROTECTED);
2625}
2626
2627static VALUE
2628check_definition(VALUE mod, int argc, VALUE *argv, rb_method_visibility_t visi)
2629{
2630 return RBOOL(check_definition_visibility(mod, argc, argv) == visi);
2631}
2632
2633/*
2634 * call-seq:
2635 * mod.public_method_defined?(symbol, inherit=true) -> true or false
2636 * mod.public_method_defined?(string, inherit=true) -> true or false
2637 *
2638 * Returns +true+ if the named public method is defined by
2639 * _mod_. If _inherit_ is set, the lookup will also search _mod_'s
2640 * ancestors.
2641 * String arguments are converted to symbols.
2642 *
2643 * module A
2644 * def method1() end
2645 * end
2646 * class B
2647 * protected
2648 * def method2() end
2649 * end
2650 * class C < B
2651 * include A
2652 * def method3() end
2653 * end
2654 *
2655 * A.method_defined? :method1 #=> true
2656 * C.public_method_defined? "method1" #=> true
2657 * C.public_method_defined? "method1", true #=> true
2658 * C.public_method_defined? "method1", false #=> true
2659 * C.public_method_defined? "method2" #=> false
2660 * C.method_defined? "method2" #=> true
2661 */
2662
2663static VALUE
2664rb_mod_public_method_defined(int argc, VALUE *argv, VALUE mod)
2665{
2666 return check_definition(mod, argc, argv, METHOD_VISI_PUBLIC);
2667}
2668
2669/*
2670 * call-seq:
2671 * mod.private_method_defined?(symbol, inherit=true) -> true or false
2672 * mod.private_method_defined?(string, inherit=true) -> true or false
2673 *
2674 * Returns +true+ if the named private method is defined by
2675 * _mod_. If _inherit_ is set, the lookup will also search _mod_'s
2676 * ancestors.
2677 * String arguments are converted to symbols.
2678 *
2679 * module A
2680 * def method1() end
2681 * end
2682 * class B
2683 * private
2684 * def method2() end
2685 * end
2686 * class C < B
2687 * include A
2688 * def method3() end
2689 * end
2690 *
2691 * A.method_defined? :method1 #=> true
2692 * C.private_method_defined? "method1" #=> false
2693 * C.private_method_defined? "method2" #=> true
2694 * C.private_method_defined? "method2", true #=> true
2695 * C.private_method_defined? "method2", false #=> false
2696 * C.method_defined? "method2" #=> false
2697 */
2698
2699static VALUE
2700rb_mod_private_method_defined(int argc, VALUE *argv, VALUE mod)
2701{
2702 return check_definition(mod, argc, argv, METHOD_VISI_PRIVATE);
2703}
2704
2705/*
2706 * call-seq:
2707 * mod.protected_method_defined?(symbol, inherit=true) -> true or false
2708 * mod.protected_method_defined?(string, inherit=true) -> true or false
2709 *
2710 * Returns +true+ if the named protected method is defined
2711 * _mod_. If _inherit_ is set, the lookup will also search _mod_'s
2712 * ancestors.
2713 * String arguments are converted to symbols.
2714 *
2715 * module A
2716 * def method1() end
2717 * end
2718 * class B
2719 * protected
2720 * def method2() end
2721 * end
2722 * class C < B
2723 * include A
2724 * def method3() end
2725 * end
2726 *
2727 * A.method_defined? :method1 #=> true
2728 * C.protected_method_defined? "method1" #=> false
2729 * C.protected_method_defined? "method2" #=> true
2730 * C.protected_method_defined? "method2", true #=> true
2731 * C.protected_method_defined? "method2", false #=> false
2732 * C.method_defined? "method2" #=> true
2733 */
2734
2735static VALUE
2736rb_mod_protected_method_defined(int argc, VALUE *argv, VALUE mod)
2737{
2738 return check_definition(mod, argc, argv, METHOD_VISI_PROTECTED);
2739}
2740
2741int
2742rb_method_entry_eq(const rb_method_entry_t *m1, const rb_method_entry_t *m2)
2743{
2744 return rb_method_definition_eq(m1->def, m2->def);
2745}
2746
2747static const rb_method_definition_t *
2748original_method_definition(const rb_method_definition_t *def)
2749{
2750 again:
2751 if (def) {
2752 switch (def->type) {
2753 case VM_METHOD_TYPE_REFINED:
2754 if (def->body.refined.orig_me) {
2755 def = def->body.refined.orig_me->def;
2756 goto again;
2757 }
2758 break;
2759 case VM_METHOD_TYPE_ALIAS:
2760 def = def->body.alias.original_me->def;
2761 goto again;
2762 default:
2763 break;
2764 }
2765 }
2766 return def;
2767}
2768
2769int
2770rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2)
2771{
2772 d1 = original_method_definition(d1);
2773 d2 = original_method_definition(d2);
2774
2775 if (d1 == d2) return 1;
2776 if (!d1 || !d2) return 0;
2777 if (d1->type != d2->type) return 0;
2778
2779 switch (d1->type) {
2780 case VM_METHOD_TYPE_ISEQ:
2781 return d1->body.iseq.iseqptr == d2->body.iseq.iseqptr;
2782 case VM_METHOD_TYPE_CFUNC:
2783 return
2784 d1->body.cfunc.func == d2->body.cfunc.func &&
2785 d1->body.cfunc.argc == d2->body.cfunc.argc;
2786 case VM_METHOD_TYPE_ATTRSET:
2787 case VM_METHOD_TYPE_IVAR:
2788 return d1->body.attr.id == d2->body.attr.id;
2789 case VM_METHOD_TYPE_BMETHOD:
2790 return RTEST(rb_equal(d1->body.bmethod.proc, d2->body.bmethod.proc));
2791 case VM_METHOD_TYPE_MISSING:
2792 return d1->original_id == d2->original_id;
2793 case VM_METHOD_TYPE_ZSUPER:
2794 case VM_METHOD_TYPE_NOTIMPLEMENTED:
2795 case VM_METHOD_TYPE_UNDEF:
2796 return 1;
2797 case VM_METHOD_TYPE_OPTIMIZED:
2798 return (d1->body.optimized.type == d2->body.optimized.type) &&
2799 (d1->body.optimized.index == d2->body.optimized.index);
2800 case VM_METHOD_TYPE_REFINED:
2801 case VM_METHOD_TYPE_ALIAS:
2802 break;
2803 }
2804 rb_bug("rb_method_definition_eq: unsupported type: %d", d1->type);
2805}
2806
2807static st_index_t
2808rb_hash_method_definition(st_index_t hash, const rb_method_definition_t *def)
2809{
2810 hash = rb_hash_uint(hash, def->type);
2811 def = original_method_definition(def);
2812
2813 if (!def) return hash;
2814
2815 switch (def->type) {
2816 case VM_METHOD_TYPE_ISEQ:
2817 return rb_hash_uint(hash, (st_index_t)def->body.iseq.iseqptr->body);
2818 case VM_METHOD_TYPE_CFUNC:
2819 hash = rb_hash_uint(hash, (st_index_t)def->body.cfunc.func);
2820 return rb_hash_uint(hash, def->body.cfunc.argc);
2821 case VM_METHOD_TYPE_ATTRSET:
2822 case VM_METHOD_TYPE_IVAR:
2823 return rb_hash_uint(hash, def->body.attr.id);
2824 case VM_METHOD_TYPE_BMETHOD:
2825 return rb_hash_proc(hash, def->body.bmethod.proc);
2826 case VM_METHOD_TYPE_MISSING:
2827 return rb_hash_uint(hash, def->original_id);
2828 case VM_METHOD_TYPE_ZSUPER:
2829 case VM_METHOD_TYPE_NOTIMPLEMENTED:
2830 case VM_METHOD_TYPE_UNDEF:
2831 return hash;
2832 case VM_METHOD_TYPE_OPTIMIZED:
2833 hash = rb_hash_uint(hash, def->body.optimized.index);
2834 return rb_hash_uint(hash, def->body.optimized.type);
2835 case VM_METHOD_TYPE_REFINED:
2836 case VM_METHOD_TYPE_ALIAS:
2837 break; /* unreachable */
2838 }
2839 rb_bug("rb_hash_method_definition: unsupported method type (%d)", def->type);
2840}
2841
2842st_index_t
2843rb_hash_method_entry(st_index_t hash, const rb_method_entry_t *me)
2844{
2845 return rb_hash_method_definition(hash, me->def);
2846}
2847
2848void
2849rb_alias(VALUE klass, ID alias_name, ID original_name)
2850{
2851 const VALUE target_klass = klass;
2852 VALUE defined_class;
2853 const rb_method_entry_t *orig_me;
2854 rb_method_visibility_t visi = METHOD_VISI_UNDEF;
2855
2856 if (NIL_P(klass)) {
2857 rb_raise(rb_eTypeError, "no class to make alias");
2858 }
2859
2860 rb_class_modify_check(klass);
2861
2862 again:
2863 orig_me = search_method(klass, original_name, &defined_class);
2864
2865 if (orig_me && orig_me->def->type == VM_METHOD_TYPE_REFINED) {
2866 orig_me = rb_resolve_refined_method(Qnil, orig_me);
2867 }
2868
2869 if (UNDEFINED_METHOD_ENTRY_P(orig_me) ||
2870 UNDEFINED_REFINED_METHOD_P(orig_me->def)) {
2871 if ((!RB_TYPE_P(klass, T_MODULE)) ||
2872 (orig_me = search_method(rb_cObject, original_name, &defined_class),
2873 UNDEFINED_METHOD_ENTRY_P(orig_me))) {
2874 rb_print_undef(target_klass, original_name, METHOD_VISI_UNDEF);
2875 }
2876 }
2877
2878 switch (orig_me->def->type) {
2879 case VM_METHOD_TYPE_ZSUPER:
2880 klass = RCLASS_SUPER(klass);
2881 original_name = orig_me->def->original_id;
2882 visi = METHOD_ENTRY_VISI(orig_me);
2883 goto again;
2884 case VM_METHOD_TYPE_ALIAS:
2885 visi = METHOD_ENTRY_VISI(orig_me);
2886 orig_me = orig_me->def->body.alias.original_me;
2887 VM_ASSERT(orig_me->def->type != VM_METHOD_TYPE_ALIAS);
2888 break;
2889 default: break;
2890 }
2891
2892 if (visi == METHOD_VISI_UNDEF) visi = METHOD_ENTRY_VISI(orig_me);
2893
2894 if (orig_me->defined_class == 0) {
2895 const rb_method_entry_t *alias_me =
2896 rb_method_entry_make(target_klass, alias_name, target_klass, visi,
2897 VM_METHOD_TYPE_ALIAS, NULL, orig_me->called_id,
2898 (void *)rb_method_entry_clone(orig_me));
2899 method_added(target_klass, alias_name, alias_me);
2900 }
2901 else {
2902 rb_method_entry_t *alias_me;
2903
2904 alias_me = method_entry_set(target_klass, alias_name, orig_me, visi, orig_me->owner);
2905 RB_OBJ_WRITE(alias_me, &alias_me->owner, target_klass);
2906
2907 if (RB_TYPE_P(target_klass, T_MODULE)) {
2908 // defined_class should not be set
2909 }
2910 else {
2911 RB_OBJ_WRITE(alias_me, &alias_me->defined_class, orig_me->defined_class);
2912 }
2913 }
2914}
2915
2916/*
2917 * call-seq:
2918 * alias_method(new_name, old_name) -> symbol
2919 *
2920 * Makes <i>new_name</i> a new copy of the method <i>old_name</i>. This can
2921 * be used to retain access to methods that are overridden.
2922 *
2923 * module Mod
2924 * alias_method :orig_exit, :exit #=> :orig_exit
2925 * def exit(code=0)
2926 * puts "Exiting with code #{code}"
2927 * orig_exit(code)
2928 * end
2929 * end
2930 * include Mod
2931 * exit(99)
2932 *
2933 * <em>produces:</em>
2934 *
2935 * Exiting with code 99
2936 */
2937
2938static VALUE
2939rb_mod_alias_method(VALUE mod, VALUE newname, VALUE oldname)
2940{
2941 ID oldid = rb_check_id(&oldname);
2942 if (!oldid) {
2943 rb_print_undef_str(mod, oldname);
2944 }
2945 VALUE id = rb_to_id(newname);
2946 rb_alias(mod, id, oldid);
2947 return ID2SYM(id);
2948}
2949
2950static void
2951check_and_export_method(VALUE self, VALUE name, rb_method_visibility_t visi)
2952{
2953 ID id = rb_check_id(&name);
2954 if (!id) {
2955 rb_print_undef_str(self, name);
2956 }
2957 rb_export_method(self, id, visi);
2958}
2959
2960static void
2961set_method_visibility(VALUE self, int argc, const VALUE *argv, rb_method_visibility_t visi)
2962{
2963 int i;
2964
2965 rb_check_frozen(self);
2966 if (argc == 0) {
2967 rb_warning("%"PRIsVALUE" with no argument is just ignored",
2968 QUOTE_ID(rb_frame_callee()));
2969 return;
2970 }
2971
2972
2973 VALUE v;
2974
2975 if (argc == 1 && (v = rb_check_array_type(argv[0])) != Qnil) {
2976 long j;
2977
2978 for (j = 0; j < RARRAY_LEN(v); j++) {
2979 check_and_export_method(self, RARRAY_AREF(v, j), visi);
2980 }
2981 }
2982 else {
2983 for (i = 0; i < argc; i++) {
2984 check_and_export_method(self, argv[i], visi);
2985 }
2986 }
2987}
2988
2989static VALUE
2990set_visibility(int argc, const VALUE *argv, VALUE module, rb_method_visibility_t visi)
2991{
2992 if (argc == 0) {
2993 scope_visibility_check();
2994 rb_scope_visibility_set(visi);
2995 return Qnil;
2996 }
2997
2998 set_method_visibility(module, argc, argv, visi);
2999 if (argc == 1) {
3000 return argv[0];
3001 }
3002 return rb_ary_new_from_values(argc, argv);
3003}
3004
3005/*
3006 * call-seq:
3007 * public -> nil
3008 * public(method_name) -> method_name
3009 * public(method_name, method_name, ...) -> array
3010 * public(array) -> array
3011 *
3012 * With no arguments, sets the default visibility for subsequently
3013 * defined methods to public. With arguments, sets the named methods to
3014 * have public visibility.
3015 * String arguments are converted to symbols.
3016 * An Array of Symbols and/or Strings is also accepted.
3017 * If a single argument is passed, it is returned.
3018 * If no argument is passed, nil is returned.
3019 * If multiple arguments are passed, the arguments are returned as an array.
3020 */
3021
3022static VALUE
3023rb_mod_public(int argc, VALUE *argv, VALUE module)
3024{
3025 return set_visibility(argc, argv, module, METHOD_VISI_PUBLIC);
3026}
3027
3028/*
3029 * call-seq:
3030 * protected -> nil
3031 * protected(method_name) -> method_name
3032 * protected(method_name, method_name, ...) -> array
3033 * protected(array) -> array
3034 *
3035 * Sets the visibility of a section or of a list of method names as protected.
3036 * Accepts no arguments, a splat of method names (symbols or strings) or an
3037 * array of method names. Returns the arguments that it received.
3038 *
3039 * == Important difference between protected in other languages
3040 *
3041 * Protected methods in Ruby are different from other languages such as Java,
3042 * where methods are marked as protected to give access to subclasses. In Ruby,
3043 * subclasses <b>already have access to all methods defined in the parent
3044 * class</b>, even private ones.
3045 *
3046 * Marking a method as protected allows <b>different objects of the same
3047 * class</b> to call it.
3048 *
3049 * One use case is for comparison methods, such as <code>==</code>, if we want
3050 * to expose a method for comparison between objects of the same class without
3051 * making the method public to objects of other classes.
3052 *
3053 * == Performance considerations
3054 *
3055 * Protected methods are slower than others because they can't use inline
3056 * cache.
3057 *
3058 * == Example
3059 *
3060 * class Account
3061 * # Mark balance as protected, so that we can compare between accounts
3062 * # without making it public.
3063 * attr_reader :balance
3064 * protected :balance
3065 *
3066 * def initialize(balance)
3067 * @balance = balance
3068 * end
3069 *
3070 * def >(other)
3071 * # The invocation to `other.balance` is allowed because `other` is a
3072 * # different object of the same class (Account).
3073 * balance > other.balance
3074 * end
3075 * end
3076 *
3077 * account1 = Account.new(100)
3078 * account2 = Account.new(50)
3079 *
3080 * account1 > account2 # => true (works)
3081 * account1.balance # => NoMethodError (fails because balance is not public)
3082 *
3083 * To show a private method on RDoc, use <code>:doc:</code> instead of this.
3084 */
3085
3086static VALUE
3087rb_mod_protected(int argc, VALUE *argv, VALUE module)
3088{
3089 return set_visibility(argc, argv, module, METHOD_VISI_PROTECTED);
3090}
3091
3092/*
3093 * call-seq:
3094 * private -> nil
3095 * private(method_name) -> method_name
3096 * private(method_name, method_name, ...) -> array
3097 * private(array) -> array
3098 *
3099 * With no arguments, sets the default visibility for subsequently
3100 * defined methods to private. With arguments, sets the named methods
3101 * to have private visibility.
3102 * String arguments are converted to symbols.
3103 * An Array of Symbols and/or Strings is also accepted.
3104 * If a single argument is passed, it is returned.
3105 * If no argument is passed, nil is returned.
3106 * If multiple arguments are passed, the arguments are returned as an array.
3107 *
3108 * module Mod
3109 * def a() end
3110 * def b() end
3111 * private
3112 * def c() end
3113 * private :a
3114 * end
3115 * Mod.private_instance_methods #=> [:a, :c]
3116 *
3117 * Note that to show a private method on RDoc, use <code>:doc:</code>.
3118 */
3119
3120static VALUE
3121rb_mod_private(int argc, VALUE *argv, VALUE module)
3122{
3123 return set_visibility(argc, argv, module, METHOD_VISI_PRIVATE);
3124}
3125
3126/*
3127 * call-seq:
3128 * ruby2_keywords(method_name, ...) -> nil
3129 *
3130 * Deprecated: will be removed in Ruby 4.4. Use <tt>...</tt>
3131 * {argument forwarding}[rdoc-ref:syntax/methods.rdoc@Argument+Forwarding]
3132 * or other delegation styles instead; they work correctly on Ruby 3.0
3133 * and later. See https://bugs.ruby-lang.org/issues/22205 for the
3134 * schedule.
3135 *
3136 * For the given method names, marks the method as passing keywords through
3137 * a normal argument splat. This should only be called on methods that
3138 * accept an argument splat (<tt>*args</tt>) but not explicit keywords or
3139 * a keyword splat. It marks the method such that if the method is called
3140 * with keyword arguments, the final hash argument is marked with a special
3141 * flag such that if it is the final element of a normal argument splat to
3142 * another method call, and that method call does not include explicit
3143 * keywords or a keyword splat, the final element is interpreted as keywords.
3144 * In other words, keywords will be passed through the method to other
3145 * methods.
3146 *
3147 * This should only be used for methods that delegate keywords to another
3148 * method, and only for backwards compatibility with Ruby versions before 3.0.
3149 * See https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/
3150 * for details on why +ruby2_keywords+ exists and when and how to use it.
3151 */
3152
3153static VALUE
3154rb_mod_ruby2_keywords(int argc, VALUE *argv, VALUE module)
3155{
3156 int i;
3157 VALUE origin_class = RCLASS_ORIGIN(module);
3158
3160 rb_check_frozen(module);
3161
3162 for (i = 0; i < argc; i++) {
3163 VALUE v = argv[i];
3164 ID name = rb_check_id(&v);
3166 VALUE defined_class;
3167
3168 if (!name) {
3169 rb_print_undef_str(module, v);
3170 }
3171
3172 me = search_method(origin_class, name, &defined_class);
3173 if (!me && RB_TYPE_P(module, T_MODULE)) {
3174 me = search_method(rb_cObject, name, &defined_class);
3175 }
3176
3177 if (UNDEFINED_METHOD_ENTRY_P(me) ||
3178 UNDEFINED_REFINED_METHOD_P(me->def)) {
3179 rb_print_undef(module, name, METHOD_VISI_UNDEF);
3180 }
3181
3182 if (module == defined_class || origin_class == defined_class) {
3183 switch (me->def->type) {
3184 case VM_METHOD_TYPE_ISEQ:
3185 if (ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_rest &&
3186 !ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_post &&
3187 !ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_kw &&
3188 !ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_kwrest) {
3189 ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.ruby2_keywords = 1;
3190 rb_clear_method_cache(module, name);
3191 }
3192 else {
3193 rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (method accepts keywords or post arguments or method does not accept argument splat)", QUOTE_ID(name));
3194 }
3195 break;
3196 case VM_METHOD_TYPE_BMETHOD: {
3197 VALUE procval = me->def->body.bmethod.proc;
3198 if (vm_block_handler_type(procval) == block_handler_type_proc) {
3199 procval = vm_proc_to_block_handler(VM_BH_TO_PROC(procval));
3200 }
3201
3202 if (vm_block_handler_type(procval) == block_handler_type_iseq) {
3203 const struct rb_captured_block *captured = VM_BH_TO_ISEQ_BLOCK(procval);
3204 const rb_iseq_t *iseq = rb_iseq_check(captured->code.iseq);
3205 if (ISEQ_BODY(iseq)->param.flags.has_rest &&
3206 !ISEQ_BODY(iseq)->param.flags.has_post &&
3207 !ISEQ_BODY(iseq)->param.flags.has_kw &&
3208 !ISEQ_BODY(iseq)->param.flags.has_kwrest) {
3209 ISEQ_BODY(iseq)->param.flags.ruby2_keywords = 1;
3210 rb_clear_method_cache(module, name);
3211 }
3212 else {
3213 rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (method accepts keywords or post arguments or method does not accept argument splat)", QUOTE_ID(name));
3214 }
3215 break;
3216 }
3217 }
3218 /* fallthrough */
3219 default:
3220 rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (method not defined in Ruby)", QUOTE_ID(name));
3221 break;
3222 }
3223 }
3224 else {
3225 rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (can only set in method defining module)", QUOTE_ID(name));
3226 }
3227 }
3228 return Qnil;
3229}
3230
3231/*
3232 * call-seq:
3233 * mod.public_class_method(symbol, ...) -> mod
3234 * mod.public_class_method(string, ...) -> mod
3235 * mod.public_class_method(array) -> mod
3236 *
3237 * Makes a list of existing class methods public.
3238 *
3239 * String arguments are converted to symbols.
3240 * An Array of Symbols and/or Strings is also accepted.
3241 */
3242
3243static VALUE
3244rb_mod_public_method(int argc, VALUE *argv, VALUE obj)
3245{
3246 set_method_visibility(rb_singleton_class(obj), argc, argv, METHOD_VISI_PUBLIC);
3247 return obj;
3248}
3249
3250/*
3251 * call-seq:
3252 * mod.private_class_method(symbol, ...) -> mod
3253 * mod.private_class_method(string, ...) -> mod
3254 * mod.private_class_method(array) -> mod
3255 *
3256 * Makes existing class methods private. Often used to hide the default
3257 * constructor <code>new</code>.
3258 *
3259 * String arguments are converted to symbols.
3260 * An Array of Symbols and/or Strings is also accepted.
3261 *
3262 * class SimpleSingleton # Not thread safe
3263 * private_class_method :new
3264 * def SimpleSingleton.create(*args, &block)
3265 * @me = new(*args, &block) if ! @me
3266 * @me
3267 * end
3268 * end
3269 */
3270
3271static VALUE
3272rb_mod_private_method(int argc, VALUE *argv, VALUE obj)
3273{
3274 set_method_visibility(rb_singleton_class(obj), argc, argv, METHOD_VISI_PRIVATE);
3275 return obj;
3276}
3277
3278/*
3279 * call-seq:
3280 * public
3281 * public(symbol, ...)
3282 * public(string, ...)
3283 * public(array)
3284 *
3285 * With no arguments, sets the default visibility for subsequently
3286 * defined methods to public. With arguments, sets the named methods to
3287 * have public visibility.
3288 *
3289 * String arguments are converted to symbols.
3290 * An Array of Symbols and/or Strings is also accepted.
3291 */
3292
3293static VALUE
3294top_public(int argc, VALUE *argv, VALUE _)
3295{
3296 return rb_mod_public(argc, argv, rb_top_main_class("public"));
3297}
3298
3299/*
3300 * call-seq:
3301 * private
3302 * private(symbol, ...)
3303 * private(string, ...)
3304 * private(array)
3305 *
3306 * With no arguments, sets the default visibility for subsequently
3307 * defined methods to private. With arguments, sets the named methods to
3308 * have private visibility.
3309 *
3310 * String arguments are converted to symbols.
3311 * An Array of Symbols and/or Strings is also accepted.
3312 */
3313static VALUE
3314top_private(int argc, VALUE *argv, VALUE _)
3315{
3316 return rb_mod_private(argc, argv, rb_top_main_class("private"));
3317}
3318
3319/*
3320 * call-seq:
3321 * ruby2_keywords(method_name, ...) -> self
3322 *
3323 * Deprecated: will be removed in Ruby 4.4. Use <tt>...</tt>
3324 * {argument forwarding}[rdoc-ref:syntax/methods.rdoc@Argument+Forwarding]
3325 * or other delegation styles instead; they work correctly on Ruby 3.0
3326 * and later. See https://bugs.ruby-lang.org/issues/22205 for the
3327 * schedule.
3328 *
3329 * For the given method names, marks the method as passing keywords through
3330 * a normal argument splat. See Module#ruby2_keywords in detail.
3331 */
3332static VALUE
3333top_ruby2_keywords(int argc, VALUE *argv, VALUE module)
3334{
3335 return rb_mod_ruby2_keywords(argc, argv, rb_top_main_class("ruby2_keywords"));
3336}
3337
3338/*
3339 * call-seq:
3340 * module_function -> nil
3341 * module_function(method_name) -> method_name
3342 * module_function(method_name, method_name, ...) -> array
3343 *
3344 * Creates module functions for the named methods. These functions may
3345 * be called with the module as a receiver, and also become available
3346 * as instance methods to classes that mix in the module. Module
3347 * functions are copies of the original, and so may be changed
3348 * independently. The instance-method versions are made private. If
3349 * used with no arguments, subsequently defined methods become module
3350 * functions.
3351 * String arguments are converted to symbols.
3352 * If a single argument is passed, it is returned.
3353 * If no argument is passed, nil is returned.
3354 * If multiple arguments are passed, the arguments are returned as an array.
3355 *
3356 * module Mod
3357 * def one
3358 * "This is one"
3359 * end
3360 * module_function :one
3361 * end
3362 * class Cls
3363 * include Mod
3364 * def call_one
3365 * one
3366 * end
3367 * end
3368 * Mod.one #=> "This is one"
3369 * c = Cls.new
3370 * c.call_one #=> "This is one"
3371 * module Mod
3372 * def one
3373 * "This is the new one"
3374 * end
3375 * end
3376 * Mod.one #=> "This is one"
3377 * c.call_one #=> "This is the new one"
3378 */
3379
3380static VALUE
3381rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
3382{
3383 int i;
3384 ID id;
3385 const rb_method_entry_t *me;
3386
3387 if (!RB_TYPE_P(module, T_MODULE)) {
3388 rb_raise(rb_eTypeError, "module_function must be called for modules");
3389 }
3390
3391 if (argc == 0) {
3392 rb_scope_module_func_set();
3393 return Qnil;
3394 }
3395
3396 set_method_visibility(module, argc, argv, METHOD_VISI_PRIVATE);
3397
3398 for (i = 0; i < argc; i++) {
3399 VALUE m = module;
3400
3401 id = rb_to_id(argv[i]);
3402 for (;;) {
3403 me = search_method(m, id, 0);
3404 if (me == 0) {
3405 me = search_method(rb_cObject, id, 0);
3406 }
3407 if (UNDEFINED_METHOD_ENTRY_P(me)) {
3408 rb_print_undef(module, id, METHOD_VISI_UNDEF);
3409 }
3410 if (me->def->type != VM_METHOD_TYPE_ZSUPER) {
3411 break; /* normal case: need not to follow 'super' link */
3412 }
3413 m = RCLASS_SUPER(m);
3414 if (!m)
3415 break;
3416 }
3417 rb_method_entry_set(rb_singleton_class(module), id, me, METHOD_VISI_PUBLIC);
3418 }
3419 if (argc == 1) {
3420 return argv[0];
3421 }
3422 return rb_ary_new_from_values(argc, argv);
3423}
3424
3425#ifdef __GNUC__
3426#pragma push_macro("rb_method_basic_definition_p")
3427#undef rb_method_basic_definition_p
3428#endif
3429int
3431{
3432 const rb_callable_method_entry_t *cme;
3433 if (!klass) return TRUE; /* hidden object cannot be overridden */
3434 cme = rb_callable_method_entry(klass, id);
3435 return (cme && METHOD_ENTRY_BASIC(cme)) ? TRUE : FALSE;
3436}
3437#ifdef __GNUC__
3438#pragma pop_macro("rb_method_basic_definition_p")
3439#endif
3440
3441static VALUE
3442call_method_entry(rb_execution_context_t *ec, VALUE defined_class, VALUE obj, ID id,
3443 const rb_callable_method_entry_t *cme, int argc, const VALUE *argv, int kw_splat)
3444{
3445 VALUE passed_block_handler = vm_passed_block_handler(ec);
3446 VALUE result = rb_vm_call_kw(ec, obj, id, argc, argv, cme, kw_splat);
3447 vm_passed_block_handler_set(ec, passed_block_handler);
3448 return result;
3449}
3450
3451static VALUE
3452basic_obj_respond_to_missing(rb_execution_context_t *ec, VALUE klass, VALUE obj,
3453 VALUE mid, VALUE priv)
3454{
3455 VALUE defined_class, args[2];
3456 const ID rtmid = idRespond_to_missing;
3457 const rb_callable_method_entry_t *const cme = callable_method_entry(klass, rtmid, &defined_class);
3458
3459 if (!cme || METHOD_ENTRY_BASIC(cme)) return Qundef;
3460 args[0] = mid;
3461 args[1] = priv;
3462 return call_method_entry(ec, defined_class, obj, rtmid, cme, 2, args, RB_NO_KEYWORDS);
3463}
3464
3465static inline int
3466basic_obj_respond_to(rb_execution_context_t *ec, VALUE obj, ID id, int pub)
3467{
3468 VALUE klass = CLASS_OF(obj);
3469 VALUE ret;
3470
3471 switch (method_boundp(klass, id, pub|BOUND_RESPONDS)) {
3472 case 2:
3473 return FALSE;
3474 case 0:
3475 ret = basic_obj_respond_to_missing(ec, klass, obj, ID2SYM(id),
3476 RBOOL(!pub));
3477 return RTEST(ret) && !UNDEF_P(ret);
3478 default:
3479 return TRUE;
3480 }
3481}
3482
3483static int
3484vm_respond_to(rb_execution_context_t *ec, VALUE klass, VALUE obj, ID id, int priv)
3485{
3486 VALUE defined_class;
3487 const ID resid = idRespond_to;
3488 const rb_callable_method_entry_t *const cme = callable_method_entry(klass, resid, &defined_class);
3489
3490 if (!cme) return -1;
3491 if (METHOD_ENTRY_BASIC(cme)) {
3492 return -1;
3493 }
3494 else {
3495 int argc = 1;
3496 VALUE args[2];
3497 VALUE result;
3498
3499 args[0] = ID2SYM(id);
3500 args[1] = Qtrue;
3501 if (priv) {
3502 argc = rb_method_entry_arity((const rb_method_entry_t *)cme);
3503 if (argc > 2) {
3504 rb_raise(rb_eArgError,
3505 "respond_to? must accept 1 or 2 arguments (requires %d)",
3506 argc);
3507 }
3508 if (argc != 1) {
3509 argc = 2;
3510 }
3511 else if (!NIL_P(ruby_verbose)) {
3512 VALUE location = rb_method_entry_location((const rb_method_entry_t *)cme);
3514 "%"PRIsVALUE"%c""respond_to?(:%"PRIsVALUE") uses"
3515 " the deprecated method signature, which takes one parameter",
3516 (RCLASS_SINGLETON_P(klass) ? obj : klass),
3517 (RCLASS_SINGLETON_P(klass) ? '.' : '#'),
3518 QUOTE_ID(id));
3519 if (!NIL_P(location)) {
3520 VALUE path = RARRAY_AREF(location, 0);
3521 VALUE line = RARRAY_AREF(location, 1);
3522 if (!NIL_P(path)) {
3524 RSTRING_PTR(path), NUM2INT(line),
3525 "respond_to? is defined here");
3526 }
3527 }
3528 }
3529 }
3530 result = call_method_entry(ec, defined_class, obj, resid, cme, argc, args, RB_NO_KEYWORDS);
3531 return RTEST(result);
3532 }
3533}
3534
3535int
3536rb_obj_respond_to(VALUE obj, ID id, int priv)
3537{
3538 rb_execution_context_t *ec = GET_EC();
3539 return rb_ec_obj_respond_to(ec, obj, id, priv);
3540}
3541
3542int
3543rb_ec_obj_respond_to(rb_execution_context_t *ec, VALUE obj, ID id, int priv)
3544{
3545 VALUE klass = CLASS_OF(obj);
3546 int ret = vm_respond_to(ec, klass, obj, id, priv);
3547 if (ret == -1) ret = basic_obj_respond_to(ec, obj, id, !priv);
3548 return ret;
3549}
3550
3551int
3553{
3554 return rb_obj_respond_to(obj, id, FALSE);
3555}
3556
3557
3558/*
3559 * call-seq:
3560 * obj.respond_to?(symbol, include_all=false) -> true or false
3561 * obj.respond_to?(string, include_all=false) -> true or false
3562 *
3563 * Returns +true+ if _obj_ responds to the given method. Private and
3564 * protected methods are included in the search only if the optional
3565 * second parameter evaluates to +true+.
3566 *
3567 * If the method is not implemented,
3568 * as Process.fork on Windows, File.lchmod on GNU/Linux, etc.,
3569 * false is returned.
3570 *
3571 * If the method is not defined, <code>respond_to_missing?</code>
3572 * method is called and the result is returned.
3573 *
3574 * When the method name parameter is given as a string, the string is
3575 * converted to a symbol.
3576 */
3577
3578static VALUE
3579obj_respond_to(int argc, VALUE *argv, VALUE obj)
3580{
3581 VALUE mid, priv;
3582 ID id;
3583 rb_execution_context_t *ec = GET_EC();
3584
3585 rb_scan_args(argc, argv, "11", &mid, &priv);
3586 if (!(id = rb_check_id(&mid))) {
3587 VALUE ret = basic_obj_respond_to_missing(ec, CLASS_OF(obj), obj,
3588 rb_to_symbol(mid), priv);
3589 if (UNDEF_P(ret)) ret = Qfalse;
3590 return ret;
3591 }
3592 return RBOOL(basic_obj_respond_to(ec, obj, id, !RTEST(priv)));
3593}
3594
3595/*
3596 * call-seq:
3597 * obj.respond_to_missing?(symbol, include_all) -> true or false
3598 * obj.respond_to_missing?(string, include_all) -> true or false
3599 *
3600 * DO NOT USE THIS DIRECTLY.
3601 *
3602 * Hook method to return whether the _obj_ can respond to _id_ method
3603 * or not.
3604 *
3605 * When the method name parameter is given as a string, the string is
3606 * converted to a symbol.
3607 *
3608 * See #respond_to?, and the example of BasicObject.
3609 */
3610static VALUE
3611obj_respond_to_missing(VALUE obj, VALUE mid, VALUE priv)
3612{
3613 return Qfalse;
3614}
3615
3616void
3617Init_eval_method(void)
3618{
3619 rb_define_method(rb_mKernel, "respond_to?", obj_respond_to, -1);
3620 rb_define_method(rb_mKernel, "respond_to_missing?", obj_respond_to_missing, 2);
3621
3622 rb_define_method(rb_cModule, "remove_method", rb_mod_remove_method, -1);
3623 rb_define_method(rb_cModule, "undef_method", rb_mod_undef_method, -1);
3624 rb_define_method(rb_cModule, "alias_method", rb_mod_alias_method, 2);
3625 rb_define_private_method(rb_cModule, "public", rb_mod_public, -1);
3626 rb_define_private_method(rb_cModule, "protected", rb_mod_protected, -1);
3627 rb_define_private_method(rb_cModule, "private", rb_mod_private, -1);
3628 rb_define_private_method(rb_cModule, "module_function", rb_mod_modfunc, -1);
3629 rb_define_private_method(rb_cModule, "ruby2_keywords", rb_mod_ruby2_keywords, -1);
3630
3631 rb_define_method(rb_cModule, "method_defined?", rb_mod_method_defined, -1);
3632 rb_define_method(rb_cModule, "public_method_defined?", rb_mod_public_method_defined, -1);
3633 rb_define_method(rb_cModule, "private_method_defined?", rb_mod_private_method_defined, -1);
3634 rb_define_method(rb_cModule, "protected_method_defined?", rb_mod_protected_method_defined, -1);
3635 rb_define_method(rb_cModule, "public_class_method", rb_mod_public_method, -1);
3636 rb_define_method(rb_cModule, "private_class_method", rb_mod_private_method, -1);
3637
3639 "public", top_public, -1);
3641 "private", top_private, -1);
3643 "ruby2_keywords", top_ruby2_keywords, -1);
3644
3645 {
3646#define REPLICATE_METHOD(klass, id) do { \
3647 const rb_method_entry_t *me = rb_method_entry((klass), (id)); \
3648 rb_method_entry_set((klass), (id), me, METHOD_ENTRY_VISI(me)); \
3649 } while (0)
3650
3651 REPLICATE_METHOD(rb_eException, idMethodMissing);
3652 REPLICATE_METHOD(rb_eException, idRespond_to);
3653 REPLICATE_METHOD(rb_eException, idRespond_to_missing);
3654 }
3655}
#define RUBY_ASSERT_ALWAYS(expr,...)
A variant of RUBY_ASSERT that does not interface with RUBY_DEBUG.
Definition assert.h:199
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
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_FETCH_SUB(var, val)
Atomically replaces the value pointed by var with the result of subtraction of val to the old value o...
Definition atomic.h:129
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_private_method(klass, mid, func, arity)
Defines klass#mid and makes it private.
VALUE rb_singleton_class(VALUE obj)
Finds or creates the singleton class of the passed object.
Definition class.c:2854
void rb_class_modify_check(VALUE klass)
Asserts that klass is not a frozen class.
Definition eval.c:440
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
Definition class.c:3187
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define T_NONE
Old name of RUBY_T_NONE.
Definition value_type.h:74
#define T_MODULE
Old name of RUBY_T_MODULE.
Definition value_type.h:70
#define T_ICLASS
Old name of RUBY_T_ICLASS.
Definition value_type.h:66
#define FL_TEST_RAW
Old name of RB_FL_TEST_RAW.
Definition fl_type.h:128
#define rb_ary_new3
Old name of rb_ary_new_from_args.
Definition array.h:658
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define NIL_P
Old name of RB_NIL_P.
#define T_CLASS
Old name of RUBY_T_CLASS.
Definition value_type.h:58
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
#define FL_TEST
Old name of RB_FL_TEST.
Definition fl_type.h:127
#define FL_SET_RAW
Old name of RB_FL_SET_RAW.
Definition fl_type.h:126
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:478
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:476
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1431
void rb_category_compile_warn(rb_warning_category_t category, const char *file, int line, const char *fmt,...)
Identical to rb_compile_warn(), except it also accepts category.
Definition error.c:441
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:468
VALUE rb_eException
Mother of all exceptions.
Definition error.c:1423
void rb_warning(const char *fmt,...)
Issues a warning.
Definition error.c:499
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:57
VALUE rb_cObject
Object class.
Definition object.c:58
VALUE rb_cModule
Module class.
Definition object.c:59
VALUE rb_equal(VALUE lhs, VALUE rhs)
This function is an optimised version of calling #==.
Definition object.c:138
#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:468
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:456
VALUE rb_call_super_kw(int argc, const VALUE *argv, int kw_splat)
Identical to rb_call_super(), except you can specify how to handle the last element of the given arra...
Definition vm_eval.c:355
VALUE rb_ary_new_from_values(long n, const VALUE *elts)
Identical to rb_ary_new_from_args(), except how objects are passed.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
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_freeze(VALUE obj)
Freeze an array, preventing further modifications.
void rb_undef(VALUE mod, ID mid)
Inserts a method entry that hides previous method definition of the given name.
Definition vm_method.c:2466
#define UNLIMITED_ARGUMENTS
This macro is used in conjunction with rb_check_arity().
Definition error.h:35
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
#define rb_hash_uint(h, i)
Just another name of st_hash_uint.
Definition string.h:943
#define rb_str_new_lit(str)
Identical to rb_str_new_static(), except it cannot take string variables.
Definition string.h:1706
st_index_t rb_hash_start(st_index_t i)
Starts a series of hashing.
Definition random.c:1714
VALUE rb_mod_name(VALUE mod)
Queries the name of a module.
Definition variable.c:150
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3552
VALUE(* rb_alloc_func_t)(VALUE klass)
This is the type of functions that ruby calls when trying to allocate an object.
Definition vm.h:219
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
Definition vm_method.c:1799
void rb_alias(VALUE klass, ID dst, ID src)
Resembles alias.
Definition vm_method.c:2849
int rb_method_basic_definition_p(VALUE klass, ID mid)
Well... Let us hesitate from describing what a "basic definition" is.
Definition vm_method.c:3430
void rb_attr(VALUE klass, ID name, int need_reader, int need_writer, int honour_visibility)
This function resembles now-deprecated Module#attr.
Definition vm_method.c:2429
void rb_remove_method(VALUE klass, const char *name)
Removes a method.
Definition vm_method.c:2278
rb_alloc_func_t rb_get_alloc_func(VALUE klass)
Queries the allocator function of a class.
Definition vm_method.c:1808
void rb_clear_constant_cache_for_id(ID id)
Clears the inline constant caches associated with a particular ID.
Definition vm_method.c:325
void rb_remove_method_id(VALUE klass, ID mid)
Identical to rb_remove_method(), except it accepts the method name as ID.
Definition vm_method.c:2272
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
VALUE rb_f_notimplement(int argc, const VALUE *argv, VALUE obj, VALUE marker)
Raises rb_eNotImpError.
Definition vm_method.c:901
int rb_method_boundp(VALUE klass, ID id, int ex)
Queries if the klass has this method.
Definition vm_method.c:2390
int rb_obj_respond_to(VALUE obj, ID mid, int private_p)
Identical to rb_respond_to(), except it additionally takes the visibility parameter.
Definition vm_method.c:3536
ID rb_check_id(volatile VALUE *namep)
Detects if the given name is already interned or not.
Definition symbol.c:1287
VALUE rb_to_symbol(VALUE name)
Identical to rb_intern_str(), except it generates a dynamic symbol if necessary.
Definition string.c:13271
ID rb_to_id(VALUE str)
Identical to rb_intern_str(), except it tries to convert the parameter object to an instance of rb_cS...
Definition string.c:13261
int capa
Designed capacity of the buffer.
Definition io.h:11
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:50
#define RARRAY_AREF(a, i)
Definition rarray.h:402
#define RBASIC(obj)
Convenient casting macro.
Definition rbasic.h:40
#define RCLASS_SUPER
Just another name of rb_class_get_superclass.
Definition rclass.h:44
#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
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
Definition scan_args.h:78
#define RB_NO_KEYWORDS
Do not pass keywords.
Definition scan_args.h:69
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
#define ANYARGS
Functions declared using this macro take arbitrary arguments, including void.
Definition stdarg.h:64
Definition vm_method.c:384
Definition method.h:63
CREF (Class REFerence)
Definition method.h:45
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:238
size_t(* dsize)(const void *)
This function is to query the size of the underlying memory regions.
Definition rtypeddata.h:278
struct rb_data_type_struct::@64 function
Function pointers.
RUBY_DATA_FUNC dfree
This function is called when the object is no longer used.
Definition rtypeddata.h:268
const char * wrap_struct_name
Name of structs of this kind.
Definition rtypeddata.h:245
VALUE flags
Type-specific behavioural characteristics.
Definition rtypeddata.h:352
Definition method.h:55
rb_cref_t * cref
class reference, should be marked
Definition method.h:144
const rb_iseq_t * iseqptr
iseq pointer, should be separated from iseqval
Definition method.h:143
Definition st.h:79
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 enum ruby_value_type RB_BUILTIN_TYPE(VALUE obj)
Queries the type of the object.
Definition value_type.h:182
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition value_type.h:425
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