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