001
002
003
004
005 #define CACHE_SIZE 0x800
006 #define CACHE_MASK 0x7ff
007 #define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK)
008
009 #define NOEX_NOREDEF 0
010 #ifndef NOEX_NOREDEF
011 #define NOEX_NOREDEF NOEX_RESPONDS
012 #endif
013
014 static void rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me, VALUE klass);
015
016 static ID object_id;
017 static ID removed, singleton_removed, undefined, singleton_undefined;
018 static ID added, singleton_added, attached;
019
020 struct cache_entry {
021 VALUE filled_version;
022 ID mid;
023 VALUE klass;
024 rb_method_entry_t *me;
025 VALUE defined_class;
026 };
027
028 static struct cache_entry cache[CACHE_SIZE];
029 #define ruby_running (GET_VM()->running)
030
031
032 static void
033 vm_clear_global_method_cache(void)
034 {
035 struct cache_entry *ent, *end;
036
037 ent = cache;
038 end = ent + CACHE_SIZE;
039 while (ent < end) {
040 ent->filled_version = 0;
041 ent++;
042 }
043 }
044
045 void
046 rb_clear_cache(void)
047 {
048 rb_vm_change_state();
049 }
050
051 static void
052 rb_clear_cache_for_undef(VALUE klass, ID id)
053 {
054 rb_vm_change_state();
055 }
056
057 static void
058 rb_clear_cache_by_id(ID id)
059 {
060 rb_vm_change_state();
061 }
062
063 void
064 rb_clear_cache_by_class(VALUE klass)
065 {
066 rb_vm_change_state();
067 }
068
069 VALUE
070 rb_f_notimplement(int argc, VALUE *argv, VALUE obj)
071 {
072 rb_notimplement();
073
074 UNREACHABLE;
075 }
076
077 static void
078 rb_define_notimplement_method_id(VALUE mod, ID id, rb_method_flag_t noex)
079 {
080 rb_add_method(mod, id, VM_METHOD_TYPE_NOTIMPLEMENTED, 0, noex);
081 }
082
083 void
084 rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_flag_t noex)
085 {
086 if (argc < -2 || 15 < argc) rb_raise(rb_eArgError, "arity out of range: %d for -2..15", argc);
087 if (func != rb_f_notimplement) {
088 rb_method_cfunc_t opt;
089 opt.func = func;
090 opt.argc = argc;
091 rb_add_method(klass, mid, VM_METHOD_TYPE_CFUNC, &opt, noex);
092 }
093 else {
094 rb_define_notimplement_method_id(klass, mid, noex);
095 }
096 }
097
098 void
099 rb_unlink_method_entry(rb_method_entry_t *me)
100 {
101 struct unlinked_method_entry_list_entry *ume = ALLOC(struct unlinked_method_entry_list_entry);
102 ume->me = me;
103 ume->next = GET_VM()->unlinked_method_entry_list;
104 GET_VM()->unlinked_method_entry_list = ume;
105 }
106
107 void
108 rb_gc_mark_unlinked_live_method_entries(void *pvm)
109 {
110 rb_vm_t *vm = pvm;
111 struct unlinked_method_entry_list_entry *ume = vm->unlinked_method_entry_list;
112
113 while (ume) {
114 if (ume->me->mark) {
115 rb_mark_method_entry(ume->me);
116 }
117 ume = ume->next;
118 }
119 }
120
121 void
122 rb_sweep_method_entry(void *pvm)
123 {
124 rb_vm_t *vm = pvm;
125 struct unlinked_method_entry_list_entry **prev_ume = &vm->unlinked_method_entry_list, *ume = *prev_ume, *curr_ume;
126
127 while (ume) {
128 if (ume->me->mark) {
129 ume->me->mark = 0;
130 prev_ume = &ume->next;
131 ume = *prev_ume;
132 }
133 else {
134 rb_free_method_entry(ume->me);
135
136 curr_ume = ume;
137 ume = ume->next;
138 *prev_ume = ume;
139 xfree(curr_ume);
140 }
141 }
142 }
143
144 static void
145 release_method_definition(rb_method_definition_t *def)
146 {
147 if (def == 0)
148 return;
149 if (def->alias_count == 0) {
150 if (def->type == VM_METHOD_TYPE_REFINED &&
151 def->body.orig_me) {
152 release_method_definition(def->body.orig_me->def);
153 xfree(def->body.orig_me);
154 }
155 xfree(def);
156 }
157 else if (def->alias_count > 0) {
158 def->alias_count--;
159 }
160 }
161
162 void
163 rb_free_method_entry(rb_method_entry_t *me)
164 {
165 release_method_definition(me->def);
166 xfree(me);
167 }
168
169 static int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
170
171 static inline rb_method_entry_t *
172 lookup_method_table(VALUE klass, ID id)
173 {
174 st_data_t body;
175 st_table *m_tbl = RCLASS_M_TBL(klass);
176 if (st_lookup(m_tbl, id, &body)) {
177 return (rb_method_entry_t *) body;
178 }
179 else {
180 return 0;
181 }
182 }
183
184 static void
185 make_method_entry_refined(rb_method_entry_t *me)
186 {
187 rb_method_definition_t *new_def;
188
189 if (me->def && me->def->type == VM_METHOD_TYPE_REFINED)
190 return;
191
192 new_def = ALLOC(rb_method_definition_t);
193 new_def->type = VM_METHOD_TYPE_REFINED;
194 new_def->original_id = me->called_id;
195 new_def->alias_count = 0;
196 new_def->body.orig_me = ALLOC(rb_method_entry_t);
197 *new_def->body.orig_me = *me;
198 rb_vm_check_redefinition_opt_method(me, me->klass);
199 if (me->def) me->def->alias_count++;
200 me->def = new_def;
201 }
202
203 void
204 rb_add_refined_method_entry(VALUE refined_class, ID mid)
205 {
206 rb_method_entry_t *me = lookup_method_table(refined_class, mid);
207
208 if (me) {
209 make_method_entry_refined(me);
210 }
211 else {
212 rb_add_method(refined_class, mid, VM_METHOD_TYPE_REFINED, 0,
213 NOEX_PUBLIC);
214 }
215 }
216
217 static rb_method_entry_t *
218 rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type,
219 rb_method_definition_t *def, rb_method_flag_t noex)
220 {
221 rb_method_entry_t *me;
222 #if NOEX_NOREDEF
223 VALUE rklass;
224 #endif
225 st_table *mtbl;
226 st_data_t data;
227 int make_refined = 0;
228
229 if (NIL_P(klass)) {
230 klass = rb_cObject;
231 }
232 if (rb_safe_level() >= 4 &&
233 (klass == rb_cObject || !OBJ_UNTRUSTED(klass))) {
234 rb_raise(rb_eSecurityError, "Insecure: can't define method");
235 }
236 if (!FL_TEST(klass, FL_SINGLETON) &&
237 type != VM_METHOD_TYPE_NOTIMPLEMENTED &&
238 type != VM_METHOD_TYPE_ZSUPER &&
239 (mid == idInitialize || mid == idInitialize_copy ||
240 mid == idInitialize_clone || mid == idInitialize_dup ||
241 mid == idRespond_to_missing)) {
242 noex = NOEX_PRIVATE | noex;
243 }
244
245 rb_check_frozen(klass);
246 #if NOEX_NOREDEF
247 rklass = klass;
248 #endif
249 if (FL_TEST(klass, RMODULE_IS_REFINEMENT)) {
250 VALUE refined_class =
251 rb_refinement_module_get_refined_class(klass);
252
253 rb_add_refined_method_entry(refined_class, mid);
254 }
255 if (type == VM_METHOD_TYPE_REFINED) {
256 rb_method_entry_t *old_me =
257 lookup_method_table(RCLASS_ORIGIN(klass), mid);
258 if (old_me) rb_vm_check_redefinition_opt_method(old_me, klass);
259 }
260 else {
261 klass = RCLASS_ORIGIN(klass);
262 }
263 mtbl = RCLASS_M_TBL(klass);
264
265
266 if (st_lookup(mtbl, mid, &data)) {
267 rb_method_entry_t *old_me = (rb_method_entry_t *)data;
268 rb_method_definition_t *old_def = old_me->def;
269
270 if (rb_method_definition_eq(old_def, def)) return old_me;
271 #if NOEX_NOREDEF
272 if (old_me->flag & NOEX_NOREDEF) {
273 rb_raise(rb_eTypeError, "cannot redefine %"PRIsVALUE"#%"PRIsVALUE,
274 rb_class_name(rklass), rb_id2str(mid));
275 }
276 #endif
277 rb_vm_check_redefinition_opt_method(old_me, klass);
278 if (old_def->type == VM_METHOD_TYPE_REFINED)
279 make_refined = 1;
280
281 if (RTEST(ruby_verbose) &&
282 type != VM_METHOD_TYPE_UNDEF &&
283 old_def->alias_count == 0 &&
284 old_def->type != VM_METHOD_TYPE_UNDEF &&
285 old_def->type != VM_METHOD_TYPE_ZSUPER) {
286 rb_iseq_t *iseq = 0;
287
288 rb_warning("method redefined; discarding old %s", rb_id2name(mid));
289 switch (old_def->type) {
290 case VM_METHOD_TYPE_ISEQ:
291 iseq = old_def->body.iseq;
292 break;
293 case VM_METHOD_TYPE_BMETHOD:
294 iseq = rb_proc_get_iseq(old_def->body.proc, 0);
295 break;
296 default:
297 break;
298 }
299 if (iseq && !NIL_P(iseq->location.path)) {
300 int line = iseq->line_info_table ? rb_iseq_first_lineno(iseq) : 0;
301 rb_compile_warning(RSTRING_PTR(iseq->location.path), line,
302 "previous definition of %s was here",
303 rb_id2name(old_def->original_id));
304 }
305 }
306
307 rb_unlink_method_entry(old_me);
308 }
309
310 me = ALLOC(rb_method_entry_t);
311
312 rb_clear_cache_by_id(mid);
313
314 me->flag = NOEX_WITH_SAFE(noex);
315 me->mark = 0;
316 me->called_id = mid;
317 me->klass = klass;
318 me->def = def;
319 if (def) def->alias_count++;
320
321
322 if (klass == rb_cObject && mid == idInitialize) {
323 rb_warn("redefining Object#initialize may cause infinite loop");
324 }
325
326 if (mid == object_id || mid == id__send__) {
327 if (type == VM_METHOD_TYPE_ISEQ) {
328 rb_warn("redefining `%s' may cause serious problems", rb_id2name(mid));
329 }
330 }
331
332 if (make_refined) {
333 make_method_entry_refined(me);
334 }
335
336 st_insert(mtbl, mid, (st_data_t) me);
337
338 return me;
339 }
340
341 #define CALL_METHOD_HOOK(klass, hook, mid) do { \
342 const VALUE arg = ID2SYM(mid); \
343 VALUE recv_class = (klass); \
344 ID hook_id = (hook); \
345 if (FL_TEST((klass), FL_SINGLETON)) { \
346 recv_class = rb_ivar_get((klass), attached); \
347 hook_id = singleton_##hook; \
348 } \
349 rb_funcall2(recv_class, hook_id, 1, &arg); \
350 } while (0)
351
352 static void
353 method_added(VALUE klass, ID mid)
354 {
355 if (ruby_running) {
356 CALL_METHOD_HOOK(klass, added, mid);
357 }
358 }
359
360 static VALUE
361 (*call_cfunc_invoker_func(int argc))(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *)
362 {
363 switch (argc) {
364 case -2: return &call_cfunc_m2;
365 case -1: return &call_cfunc_m1;
366 case 0: return &call_cfunc_0;
367 case 1: return &call_cfunc_1;
368 case 2: return &call_cfunc_2;
369 case 3: return &call_cfunc_3;
370 case 4: return &call_cfunc_4;
371 case 5: return &call_cfunc_5;
372 case 6: return &call_cfunc_6;
373 case 7: return &call_cfunc_7;
374 case 8: return &call_cfunc_8;
375 case 9: return &call_cfunc_9;
376 case 10: return &call_cfunc_10;
377 case 11: return &call_cfunc_11;
378 case 12: return &call_cfunc_12;
379 case 13: return &call_cfunc_13;
380 case 14: return &call_cfunc_14;
381 case 15: return &call_cfunc_15;
382 default:
383 rb_bug("call_cfunc_func: unsupported length: %d", argc);
384 }
385 }
386
387 static void
388 setup_method_cfunc_struct(rb_method_cfunc_t *cfunc, VALUE (*func)(), int argc)
389 {
390 cfunc->func = func;
391 cfunc->argc = argc;
392 cfunc->invoker = call_cfunc_invoker_func(argc);
393 }
394
395 rb_method_entry_t *
396 rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_flag_t noex)
397 {
398 rb_thread_t *th;
399 rb_control_frame_t *cfp;
400 int line;
401 rb_method_entry_t *me = rb_method_entry_make(klass, mid, type, 0, noex);
402 rb_method_definition_t *def = ALLOC(rb_method_definition_t);
403 if (me->def && me->def->type == VM_METHOD_TYPE_REFINED) {
404 me->def->body.orig_me->def = def;
405 }
406 else {
407 me->def = def;
408 }
409 def->type = type;
410 def->original_id = mid;
411 def->alias_count = 0;
412 switch (type) {
413 case VM_METHOD_TYPE_ISEQ:
414 def->body.iseq = (rb_iseq_t *)opts;
415 break;
416 case VM_METHOD_TYPE_CFUNC:
417 {
418 rb_method_cfunc_t *cfunc = (rb_method_cfunc_t *)opts;
419 setup_method_cfunc_struct(&def->body.cfunc, cfunc->func, cfunc->argc);
420 }
421 break;
422 case VM_METHOD_TYPE_ATTRSET:
423 case VM_METHOD_TYPE_IVAR:
424 def->body.attr.id = (ID)opts;
425 def->body.attr.location = Qfalse;
426 th = GET_THREAD();
427 cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
428 if (cfp && (line = rb_vm_get_sourceline(cfp))) {
429 VALUE location = rb_ary_new3(2, cfp->iseq->location.path, INT2FIX(line));
430 def->body.attr.location = rb_ary_freeze(location);
431 }
432 break;
433 case VM_METHOD_TYPE_BMETHOD:
434 def->body.proc = (VALUE)opts;
435 break;
436 case VM_METHOD_TYPE_NOTIMPLEMENTED:
437 setup_method_cfunc_struct(&def->body.cfunc, rb_f_notimplement, -1);
438 break;
439 case VM_METHOD_TYPE_OPTIMIZED:
440 def->body.optimize_type = (enum method_optimized_type)opts;
441 break;
442 case VM_METHOD_TYPE_ZSUPER:
443 case VM_METHOD_TYPE_UNDEF:
444 break;
445 case VM_METHOD_TYPE_REFINED:
446 def->body.orig_me = (rb_method_entry_t *) opts;
447 break;
448 default:
449 rb_bug("rb_add_method: unsupported method type (%d)\n", type);
450 }
451 if (type != VM_METHOD_TYPE_UNDEF && type != VM_METHOD_TYPE_REFINED) {
452 method_added(klass, mid);
453 }
454 return me;
455 }
456
457 rb_method_entry_t *
458 rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *me, rb_method_flag_t noex)
459 {
460 rb_method_type_t type = me->def ? me->def->type : VM_METHOD_TYPE_UNDEF;
461 rb_method_entry_t *newme = rb_method_entry_make(klass, mid, type, me->def, noex);
462 method_added(klass, mid);
463 return newme;
464 }
465
466 #define UNDEF_ALLOC_FUNC ((rb_alloc_func_t)-1)
467
468 void
469 rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE))
470 {
471 Check_Type(klass, T_CLASS);
472 RCLASS_EXT(klass)->allocator = func;
473 }
474
475 void
476 rb_undef_alloc_func(VALUE klass)
477 {
478 rb_define_alloc_func(klass, UNDEF_ALLOC_FUNC);
479 }
480
481 rb_alloc_func_t
482 rb_get_alloc_func(VALUE klass)
483 {
484 Check_Type(klass, T_CLASS);
485
486 for (; klass; klass = RCLASS_SUPER(klass)) {
487 rb_alloc_func_t allocator = RCLASS_EXT(klass)->allocator;
488 if (allocator == UNDEF_ALLOC_FUNC) break;
489 if (allocator) return allocator;
490 }
491 return 0;
492 }
493
494 static inline rb_method_entry_t*
495 search_method(VALUE klass, ID id, VALUE *defined_class_ptr)
496 {
497 rb_method_entry_t *me;
498
499 for (me = 0; klass; klass = RCLASS_SUPER(klass)) {
500 if ((me = lookup_method_table(klass, id)) != 0) break;
501 }
502
503 if (defined_class_ptr)
504 *defined_class_ptr = klass;
505 return me;
506 }
507
508
509
510
511
512
513
514 rb_method_entry_t *
515 rb_method_entry_get_without_cache(VALUE klass, ID id,
516 VALUE *defined_class_ptr)
517 {
518 VALUE defined_class;
519 rb_method_entry_t *me = search_method(klass, id, &defined_class);
520
521 if (ruby_running) {
522 struct cache_entry *ent;
523 ent = cache + EXPR1(klass, id);
524 ent->filled_version = GET_VM_STATE_VERSION();
525 ent->klass = klass;
526 ent->defined_class = defined_class;
527
528 if (UNDEFINED_METHOD_ENTRY_P(me)) {
529 ent->mid = id;
530 ent->me = 0;
531 me = 0;
532 }
533 else {
534 ent->mid = id;
535 ent->me = me;
536 }
537 }
538
539 if (defined_class_ptr)
540 *defined_class_ptr = defined_class;
541 return me;
542 }
543
544 rb_method_entry_t *
545 rb_method_entry(VALUE klass, ID id, VALUE *defined_class_ptr)
546 {
547 #if OPT_GLOBAL_METHOD_CACHE
548 struct cache_entry *ent;
549
550 ent = cache + EXPR1(klass, id);
551 if (ent->filled_version == GET_VM_STATE_VERSION() &&
552 ent->mid == id && ent->klass == klass) {
553 if (defined_class_ptr)
554 *defined_class_ptr = ent->defined_class;
555 return ent->me;
556 }
557 #endif
558
559 return rb_method_entry_get_without_cache(klass, id, defined_class_ptr);
560 }
561
562 static rb_method_entry_t *
563 get_original_method_entry(VALUE refinements,
564 rb_method_entry_t *me,
565 VALUE *defined_class_ptr)
566 {
567 if (me->def->body.orig_me) {
568 return me->def->body.orig_me;
569 }
570 else {
571 rb_method_entry_t *tmp_me;
572 tmp_me = rb_method_entry(RCLASS_SUPER(me->klass), me->called_id,
573 defined_class_ptr);
574 return rb_resolve_refined_method(refinements, tmp_me,
575 defined_class_ptr);
576 }
577 }
578
579 rb_method_entry_t *
580 rb_resolve_refined_method(VALUE refinements, rb_method_entry_t *me,
581 VALUE *defined_class_ptr)
582 {
583 if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
584 VALUE refinement;
585 rb_method_entry_t *tmp_me;
586
587 refinement = find_refinement(refinements, me->klass);
588 if (NIL_P(refinement)) {
589 return get_original_method_entry(refinements, me,
590 defined_class_ptr);
591 }
592 tmp_me = rb_method_entry(refinement, me->called_id,
593 defined_class_ptr);
594 if (tmp_me && tmp_me->def->type != VM_METHOD_TYPE_REFINED) {
595 return tmp_me;
596 }
597 else {
598 return get_original_method_entry(refinements, me,
599 defined_class_ptr);
600 }
601 }
602 else {
603 return me;
604 }
605 }
606
607 rb_method_entry_t *
608 rb_method_entry_with_refinements(VALUE klass, ID id,
609 VALUE *defined_class_ptr)
610 {
611 VALUE defined_class;
612 rb_method_entry_t *me = rb_method_entry(klass, id, &defined_class);
613
614 if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
615 NODE *cref = rb_vm_cref();
616 VALUE refinements = cref ? cref->nd_refinements : Qnil;
617
618 me = rb_resolve_refined_method(refinements, me, &defined_class);
619 }
620 if (defined_class_ptr)
621 *defined_class_ptr = defined_class;
622 return me;
623 }
624
625 rb_method_entry_t *
626 rb_method_entry_without_refinements(VALUE klass, ID id,
627 VALUE *defined_class_ptr)
628 {
629 VALUE defined_class;
630 rb_method_entry_t *me = rb_method_entry(klass, id, &defined_class);
631
632 if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
633 me = rb_resolve_refined_method(Qnil, me, &defined_class);
634 }
635 if (defined_class_ptr)
636 *defined_class_ptr = defined_class;
637 return me;
638 }
639
640 static void
641 remove_method(VALUE klass, ID mid)
642 {
643 st_data_t key, data;
644 rb_method_entry_t *me = 0;
645 VALUE self = klass;
646
647 klass = RCLASS_ORIGIN(klass);
648 if (klass == rb_cObject) {
649 rb_secure(4);
650 }
651 if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(klass)) {
652 rb_raise(rb_eSecurityError, "Insecure: can't remove method");
653 }
654 rb_check_frozen(klass);
655 if (mid == object_id || mid == id__send__ || mid == idInitialize) {
656 rb_warn("removing `%s' may cause serious problems", rb_id2name(mid));
657 }
658
659 if (!st_lookup(RCLASS_M_TBL(klass), mid, &data) ||
660 !(me = (rb_method_entry_t *)data) ||
661 (!me->def || me->def->type == VM_METHOD_TYPE_UNDEF)) {
662 rb_name_error(mid, "method `%s' not defined in %s",
663 rb_id2name(mid), rb_class2name(klass));
664 }
665 key = (st_data_t)mid;
666 st_delete(RCLASS_M_TBL(klass), &key, &data);
667
668 rb_vm_check_redefinition_opt_method(me, klass);
669 rb_clear_cache_for_undef(klass, mid);
670 rb_unlink_method_entry(me);
671
672 CALL_METHOD_HOOK(self, removed, mid);
673 }
674
675 void
676 rb_remove_method_id(VALUE klass, ID mid)
677 {
678 remove_method(klass, mid);
679 }
680
681 void
682 rb_remove_method(VALUE klass, const char *name)
683 {
684 remove_method(klass, rb_intern(name));
685 }
686
687
688
689
690
691
692
693
694
695
696
697 static VALUE
698 rb_mod_remove_method(int argc, VALUE *argv, VALUE mod)
699 {
700 int i;
701
702 for (i = 0; i < argc; i++) {
703 VALUE v = argv[i];
704 ID id = rb_check_id(&v);
705 if (!id) {
706 rb_name_error_str(v, "method `%s' not defined in %s",
707 RSTRING_PTR(v), rb_class2name(mod));
708 }
709 remove_method(mod, id);
710 }
711 return mod;
712 }
713
714 #undef rb_disable_super
715 #undef rb_enable_super
716
717 void
718 rb_disable_super(VALUE klass, const char *name)
719 {
720
721 }
722
723 void
724 rb_enable_super(VALUE klass, const char *name)
725 {
726 rb_warning("rb_enable_super() is obsolete");
727 }
728
729 static void
730 rb_export_method(VALUE klass, ID name, rb_method_flag_t noex)
731 {
732 rb_method_entry_t *me;
733 VALUE defined_class;
734
735 if (klass == rb_cObject) {
736 rb_secure(4);
737 }
738
739 me = search_method(klass, name, &defined_class);
740 if (!me && RB_TYPE_P(klass, T_MODULE)) {
741 me = search_method(rb_cObject, name, &defined_class);
742 }
743
744 if (UNDEFINED_METHOD_ENTRY_P(me)) {
745 rb_print_undef(klass, name, 0);
746 }
747
748 if (me->flag != noex) {
749 rb_vm_check_redefinition_opt_method(me, klass);
750
751 if (klass == defined_class ||
752 RCLASS_ORIGIN(klass) == defined_class) {
753 me->flag = noex;
754 if (me->def->type == VM_METHOD_TYPE_REFINED) {
755 me->def->body.orig_me->flag = noex;
756 }
757 }
758 else {
759 rb_add_method(klass, name, VM_METHOD_TYPE_ZSUPER, 0, noex);
760 }
761 }
762 }
763
764 int
765 rb_method_boundp(VALUE klass, ID id, int ex)
766 {
767 rb_method_entry_t *me =
768 rb_method_entry_without_refinements(klass, id, 0);
769
770 if (me != 0) {
771 if ((ex & ~NOEX_RESPONDS) &&
772 ((me->flag & NOEX_PRIVATE) ||
773 ((ex & NOEX_RESPONDS) && (me->flag & NOEX_PROTECTED)))) {
774 return 0;
775 }
776 if (!me->def) return 0;
777 if (me->def->type == VM_METHOD_TYPE_NOTIMPLEMENTED) {
778 if (ex & NOEX_RESPONDS) return 2;
779 return 0;
780 }
781 return 1;
782 }
783 return 0;
784 }
785
786 void
787 rb_attr(VALUE klass, ID id, int read, int write, int ex)
788 {
789 const char *name;
790 ID attriv;
791 VALUE aname;
792 rb_method_flag_t noex;
793
794 if (!ex) {
795 noex = NOEX_PUBLIC;
796 }
797 else {
798 if (SCOPE_TEST(NOEX_PRIVATE)) {
799 noex = NOEX_PRIVATE;
800 rb_warning((SCOPE_CHECK(NOEX_MODFUNC)) ?
801 "attribute accessor as module_function" :
802 "private attribute?");
803 }
804 else if (SCOPE_TEST(NOEX_PROTECTED)) {
805 noex = NOEX_PROTECTED;
806 }
807 else {
808 noex = NOEX_PUBLIC;
809 }
810 }
811
812 if (!rb_is_local_id(id) && !rb_is_const_id(id)) {
813 rb_name_error(id, "invalid attribute name `%s'", rb_id2name(id));
814 }
815 name = rb_id2name(id);
816 if (!name) {
817 rb_raise(rb_eArgError, "argument needs to be symbol or string");
818 }
819 aname = rb_sprintf("@%s", name);
820 rb_enc_copy(aname, rb_id2str(id));
821 attriv = rb_intern_str(aname);
822 if (read) {
823 rb_add_method(klass, id, VM_METHOD_TYPE_IVAR, (void *)attriv, noex);
824 }
825 if (write) {
826 rb_add_method(klass, rb_id_attrset(id), VM_METHOD_TYPE_ATTRSET, (void *)attriv, noex);
827 }
828 }
829
830 void
831 rb_undef(VALUE klass, ID id)
832 {
833 rb_method_entry_t *me;
834
835 if (NIL_P(klass)) {
836 rb_raise(rb_eTypeError, "no class to undef method");
837 }
838 if (rb_vm_cbase() == rb_cObject && klass == rb_cObject) {
839 rb_secure(4);
840 }
841 if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(klass)) {
842 rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'", rb_id2name(id));
843 }
844 rb_frozen_class_p(klass);
845 if (id == object_id || id == id__send__ || id == idInitialize) {
846 rb_warn("undefining `%s' may cause serious problems", rb_id2name(id));
847 }
848
849 me = search_method(klass, id, 0);
850
851 if (UNDEFINED_METHOD_ENTRY_P(me)) {
852 const char *s0 = " class";
853 VALUE c = klass;
854
855 if (FL_TEST(c, FL_SINGLETON)) {
856 VALUE obj = rb_ivar_get(klass, attached);
857
858 if (RB_TYPE_P(obj, T_MODULE) || RB_TYPE_P(obj, T_CLASS)) {
859 c = obj;
860 s0 = "";
861 }
862 }
863 else if (RB_TYPE_P(c, T_MODULE)) {
864 s0 = " module";
865 }
866 rb_name_error(id, "undefined method `%"PRIsVALUE"' for%s `%"PRIsVALUE"'",
867 QUOTE_ID(id), s0, rb_class_name(c));
868 }
869
870 rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, NOEX_PUBLIC);
871
872 CALL_METHOD_HOOK(klass, undefined, id);
873 }
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920 static VALUE
921 rb_mod_undef_method(int argc, VALUE *argv, VALUE mod)
922 {
923 int i;
924 for (i = 0; i < argc; i++) {
925 VALUE v = argv[i];
926 ID id = rb_check_id(&v);
927 if (!id) {
928 rb_method_name_error(mod, v);
929 }
930 rb_undef(mod, id);
931 }
932 return mod;
933 }
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963 static VALUE
964 rb_mod_method_defined(VALUE mod, VALUE mid)
965 {
966 ID id = rb_check_id(&mid);
967 if (!id || !rb_method_boundp(mod, id, 1)) {
968 return Qfalse;
969 }
970 return Qtrue;
971
972 }
973
974 #define VISI_CHECK(x,f) (((x)&NOEX_MASK) == (f))
975
976 static VALUE
977 check_definition(VALUE mod, VALUE mid, rb_method_flag_t noex)
978 {
979 const rb_method_entry_t *me;
980 ID id = rb_check_id(&mid);
981 if (!id) return Qfalse;
982 me = rb_method_entry(mod, id, 0);
983 if (me) {
984 if (VISI_CHECK(me->flag, noex))
985 return Qtrue;
986 }
987 return Qfalse;
988 }
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018 static VALUE
1019 rb_mod_public_method_defined(VALUE mod, VALUE mid)
1020 {
1021 return check_definition(mod, mid, NOEX_PUBLIC);
1022 }
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052 static VALUE
1053 rb_mod_private_method_defined(VALUE mod, VALUE mid)
1054 {
1055 return check_definition(mod, mid, NOEX_PRIVATE);
1056 }
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086 static VALUE
1087 rb_mod_protected_method_defined(VALUE mod, VALUE mid)
1088 {
1089 return check_definition(mod, mid, NOEX_PROTECTED);
1090 }
1091
1092 int
1093 rb_method_entry_eq(const rb_method_entry_t *m1, const rb_method_entry_t *m2)
1094 {
1095 return rb_method_definition_eq(m1->def, m2->def);
1096 }
1097
1098 static int
1099 rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2)
1100 {
1101 if (d1 && d1->type == VM_METHOD_TYPE_REFINED)
1102 d1 = d1->body.orig_me->def;
1103 if (d2 && d2->type == VM_METHOD_TYPE_REFINED)
1104 d2 = d2->body.orig_me->def;
1105 if (d1 == d2) return 1;
1106 if (!d1 || !d2) return 0;
1107 if (d1->type != d2->type) {
1108 return 0;
1109 }
1110 switch (d1->type) {
1111 case VM_METHOD_TYPE_ISEQ:
1112 return d1->body.iseq == d2->body.iseq;
1113 case VM_METHOD_TYPE_CFUNC:
1114 return
1115 d1->body.cfunc.func == d2->body.cfunc.func &&
1116 d1->body.cfunc.argc == d2->body.cfunc.argc;
1117 case VM_METHOD_TYPE_ATTRSET:
1118 case VM_METHOD_TYPE_IVAR:
1119 return d1->body.attr.id == d2->body.attr.id;
1120 case VM_METHOD_TYPE_BMETHOD:
1121 return RTEST(rb_equal(d1->body.proc, d2->body.proc));
1122 case VM_METHOD_TYPE_MISSING:
1123 return d1->original_id == d2->original_id;
1124 case VM_METHOD_TYPE_ZSUPER:
1125 case VM_METHOD_TYPE_NOTIMPLEMENTED:
1126 case VM_METHOD_TYPE_UNDEF:
1127 return 1;
1128 case VM_METHOD_TYPE_OPTIMIZED:
1129 return d1->body.optimize_type == d2->body.optimize_type;
1130 default:
1131 rb_bug("rb_method_entry_eq: unsupported method type (%d)\n", d1->type);
1132 return 0;
1133 }
1134 }
1135
1136 static st_index_t
1137 rb_hash_method_definition(st_index_t hash, const rb_method_definition_t *def)
1138 {
1139 again:
1140 hash = rb_hash_uint(hash, def->type);
1141 switch (def->type) {
1142 case VM_METHOD_TYPE_ISEQ:
1143 return rb_hash_uint(hash, (st_index_t)def->body.iseq);
1144 case VM_METHOD_TYPE_CFUNC:
1145 hash = rb_hash_uint(hash, (st_index_t)def->body.cfunc.func);
1146 return rb_hash_uint(hash, def->body.cfunc.argc);
1147 case VM_METHOD_TYPE_ATTRSET:
1148 case VM_METHOD_TYPE_IVAR:
1149 return rb_hash_uint(hash, def->body.attr.id);
1150 case VM_METHOD_TYPE_BMETHOD:
1151 return rb_hash_proc(hash, def->body.proc);
1152 case VM_METHOD_TYPE_MISSING:
1153 return rb_hash_uint(hash, def->original_id);
1154 case VM_METHOD_TYPE_ZSUPER:
1155 case VM_METHOD_TYPE_NOTIMPLEMENTED:
1156 case VM_METHOD_TYPE_UNDEF:
1157 return hash;
1158 case VM_METHOD_TYPE_OPTIMIZED:
1159 return rb_hash_uint(hash, def->body.optimize_type);
1160 case VM_METHOD_TYPE_REFINED:
1161 if (def->body.orig_me) {
1162 def = def->body.orig_me->def;
1163 goto again;
1164 }
1165 else {
1166 return hash;
1167 }
1168 default:
1169 rb_bug("rb_hash_method_definition: unsupported method type (%d)\n", def->type);
1170 }
1171 return hash;
1172 }
1173
1174 st_index_t
1175 rb_hash_method_entry(st_index_t hash, const rb_method_entry_t *me)
1176 {
1177 return rb_hash_method_definition(hash, me->def);
1178 }
1179
1180 void
1181 rb_alias(VALUE klass, ID name, ID def)
1182 {
1183 VALUE target_klass = klass;
1184 rb_method_entry_t *orig_me;
1185 rb_method_flag_t flag = NOEX_UNDEF;
1186
1187 if (NIL_P(klass)) {
1188 rb_raise(rb_eTypeError, "no class to make alias");
1189 }
1190
1191 rb_frozen_class_p(klass);
1192 if (klass == rb_cObject) {
1193 rb_secure(4);
1194 }
1195
1196 again:
1197 orig_me = search_method(klass, def, 0);
1198
1199 if (UNDEFINED_METHOD_ENTRY_P(orig_me)) {
1200 if ((!RB_TYPE_P(klass, T_MODULE)) ||
1201 (orig_me = search_method(rb_cObject, def, 0),
1202 UNDEFINED_METHOD_ENTRY_P(orig_me))) {
1203 rb_print_undef(klass, def, 0);
1204 }
1205 }
1206 if (orig_me->def->type == VM_METHOD_TYPE_ZSUPER) {
1207 klass = RCLASS_SUPER(klass);
1208 def = orig_me->def->original_id;
1209 flag = orig_me->flag;
1210 goto again;
1211 }
1212
1213 if (flag == NOEX_UNDEF) flag = orig_me->flag;
1214 rb_method_entry_set(target_klass, name, orig_me, flag);
1215 }
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239 static VALUE
1240 rb_mod_alias_method(VALUE mod, VALUE newname, VALUE oldname)
1241 {
1242 ID oldid = rb_check_id(&oldname);
1243 if (!oldid) {
1244 rb_print_undef_str(mod, oldname);
1245 }
1246 rb_alias(mod, rb_to_id(newname), oldid);
1247 return mod;
1248 }
1249
1250 static void
1251 secure_visibility(VALUE self)
1252 {
1253 if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(self)) {
1254 rb_raise(rb_eSecurityError,
1255 "Insecure: can't change method visibility");
1256 }
1257 }
1258
1259 static void
1260 set_method_visibility(VALUE self, int argc, VALUE *argv, rb_method_flag_t ex)
1261 {
1262 int i;
1263 secure_visibility(self);
1264
1265 if (argc == 0) {
1266 rb_warning("%s with no argument is just ignored", rb_id2name(rb_frame_callee()));
1267 }
1268
1269 for (i = 0; i < argc; i++) {
1270 VALUE v = argv[i];
1271 ID id = rb_check_id(&v);
1272 if (!id) {
1273 rb_print_undef_str(self, v);
1274 }
1275 rb_export_method(self, id, ex);
1276 }
1277 rb_clear_cache_by_class(self);
1278 }
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292 static VALUE
1293 rb_mod_public(int argc, VALUE *argv, VALUE module)
1294 {
1295 secure_visibility(module);
1296 if (argc == 0) {
1297 SCOPE_SET(NOEX_PUBLIC);
1298 }
1299 else {
1300 set_method_visibility(module, argc, argv, NOEX_PUBLIC);
1301 }
1302 return module;
1303 }
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317 static VALUE
1318 rb_mod_protected(int argc, VALUE *argv, VALUE module)
1319 {
1320 secure_visibility(module);
1321 if (argc == 0) {
1322 SCOPE_SET(NOEX_PROTECTED);
1323 }
1324 else {
1325 set_method_visibility(module, argc, argv, NOEX_PROTECTED);
1326 }
1327 return module;
1328 }
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351 static VALUE
1352 rb_mod_private(int argc, VALUE *argv, VALUE module)
1353 {
1354 secure_visibility(module);
1355 if (argc == 0) {
1356 SCOPE_SET(NOEX_PRIVATE);
1357 }
1358 else {
1359 set_method_visibility(module, argc, argv, NOEX_PRIVATE);
1360 }
1361 return module;
1362 }
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374 static VALUE
1375 rb_mod_public_method(int argc, VALUE *argv, VALUE obj)
1376 {
1377 set_method_visibility(rb_singleton_class(obj), argc, argv, NOEX_PUBLIC);
1378 return obj;
1379 }
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400 static VALUE
1401 rb_mod_private_method(int argc, VALUE *argv, VALUE obj)
1402 {
1403 set_method_visibility(rb_singleton_class(obj), argc, argv, NOEX_PRIVATE);
1404 return obj;
1405 }
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420 static VALUE
1421 top_public(int argc, VALUE *argv)
1422 {
1423 return rb_mod_public(argc, argv, rb_cObject);
1424 }
1425
1426 static VALUE
1427 top_private(int argc, VALUE *argv)
1428 {
1429 return rb_mod_private(argc, argv, rb_cObject);
1430 }
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470 static VALUE
1471 rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
1472 {
1473 int i;
1474 ID id;
1475 const rb_method_entry_t *me;
1476
1477 if (!RB_TYPE_P(module, T_MODULE)) {
1478 rb_raise(rb_eTypeError, "module_function must be called for modules");
1479 }
1480
1481 secure_visibility(module);
1482 if (argc == 0) {
1483 SCOPE_SET(NOEX_MODFUNC);
1484 return module;
1485 }
1486
1487 set_method_visibility(module, argc, argv, NOEX_PRIVATE);
1488
1489 for (i = 0; i < argc; i++) {
1490 VALUE m = module;
1491
1492 id = rb_to_id(argv[i]);
1493 for (;;) {
1494 me = search_method(m, id, 0);
1495 if (me == 0) {
1496 me = search_method(rb_cObject, id, 0);
1497 }
1498 if (UNDEFINED_METHOD_ENTRY_P(me)) {
1499 rb_print_undef(module, id, 0);
1500 }
1501 if (me->def->type != VM_METHOD_TYPE_ZSUPER) {
1502 break;
1503 }
1504 m = RCLASS_SUPER(m);
1505 if (!m)
1506 break;
1507 }
1508 rb_method_entry_set(rb_singleton_class(module), id, me, NOEX_PUBLIC);
1509 }
1510 return module;
1511 }
1512
1513 int
1514 rb_method_basic_definition_p(VALUE klass, ID id)
1515 {
1516 const rb_method_entry_t *me = rb_method_entry(klass, id, 0);
1517 if (me && (me->flag & NOEX_BASIC))
1518 return 1;
1519 return 0;
1520 }
1521
1522 static inline int
1523 basic_obj_respond_to(VALUE obj, ID id, int pub)
1524 {
1525 VALUE klass = CLASS_OF(obj);
1526 VALUE args[2];
1527
1528 switch (rb_method_boundp(klass, id, pub|NOEX_RESPONDS)) {
1529 case 2:
1530 return FALSE;
1531 case 0:
1532 args[0] = ID2SYM(id);
1533 args[1] = pub ? Qfalse : Qtrue;
1534 return RTEST(rb_funcall2(obj, idRespond_to_missing, 2, args));
1535 default:
1536 return TRUE;
1537 }
1538 }
1539
1540 int
1541 rb_obj_respond_to(VALUE obj, ID id, int priv)
1542 {
1543 VALUE klass = CLASS_OF(obj);
1544
1545 if (rb_method_basic_definition_p(klass, idRespond_to)) {
1546 return basic_obj_respond_to(obj, id, !RTEST(priv));
1547 }
1548 else {
1549 int argc = 1;
1550 VALUE args[2];
1551 args[0] = ID2SYM(id);
1552 args[1] = Qtrue;
1553 if (priv) {
1554 if (rb_obj_method_arity(obj, idRespond_to) != 1) {
1555 argc = 2;
1556 }
1557 else if (!NIL_P(ruby_verbose)) {
1558 VALUE klass = CLASS_OF(obj);
1559 VALUE location = rb_mod_method_location(klass, idRespond_to);
1560 rb_warn("%"PRIsVALUE"%c""respond_to?(:%"PRIsVALUE") is"
1561 " old fashion which takes only one parameter",
1562 (FL_TEST(klass, FL_SINGLETON) ? obj : klass),
1563 (FL_TEST(klass, FL_SINGLETON) ? '.' : '#'),
1564 QUOTE_ID(id));
1565 if (!NIL_P(location)) {
1566 VALUE path = RARRAY_PTR(location)[0];
1567 VALUE line = RARRAY_PTR(location)[1];
1568 if (!NIL_P(path)) {
1569 rb_compile_warn(RSTRING_PTR(path), NUM2INT(line),
1570 "respond_to? is defined here");
1571 }
1572 }
1573 }
1574 }
1575 return RTEST(rb_funcall2(obj, idRespond_to, argc, args));
1576 }
1577 }
1578
1579 int
1580 rb_respond_to(VALUE obj, ID id)
1581 {
1582 return rb_obj_respond_to(obj, id, FALSE);
1583 }
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606 static VALUE
1607 obj_respond_to(int argc, VALUE *argv, VALUE obj)
1608 {
1609 VALUE mid, priv;
1610 ID id;
1611
1612 rb_scan_args(argc, argv, "11", &mid, &priv);
1613 if (!(id = rb_check_id(&mid))) {
1614 if (!rb_method_basic_definition_p(CLASS_OF(obj), idRespond_to_missing)) {
1615 VALUE args[2];
1616 args[0] = ID2SYM(rb_to_id(mid));
1617 args[1] = priv;
1618 return rb_funcall2(obj, idRespond_to_missing, 2, args);
1619 }
1620 return Qfalse;
1621 }
1622 if (basic_obj_respond_to(obj, id, !RTEST(priv)))
1623 return Qtrue;
1624 return Qfalse;
1625 }
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642 static VALUE
1643 obj_respond_to_missing(VALUE obj, VALUE mid, VALUE priv)
1644 {
1645 return Qfalse;
1646 }
1647
1648 void
1649 Init_eval_method(void)
1650 {
1651 #undef rb_intern
1652 #define rb_intern(str) rb_intern_const(str)
1653
1654 rb_define_method(rb_mKernel, "respond_to?", obj_respond_to, -1);
1655 rb_define_method(rb_mKernel, "respond_to_missing?", obj_respond_to_missing, 2);
1656
1657 rb_define_private_method(rb_cModule, "remove_method", rb_mod_remove_method, -1);
1658 rb_define_private_method(rb_cModule, "undef_method", rb_mod_undef_method, -1);
1659 rb_define_private_method(rb_cModule, "alias_method", rb_mod_alias_method, 2);
1660 rb_define_private_method(rb_cModule, "public", rb_mod_public, -1);
1661 rb_define_private_method(rb_cModule, "protected", rb_mod_protected, -1);
1662 rb_define_private_method(rb_cModule, "private", rb_mod_private, -1);
1663 rb_define_private_method(rb_cModule, "module_function", rb_mod_modfunc, -1);
1664
1665 rb_define_method(rb_cModule, "method_defined?", rb_mod_method_defined, 1);
1666 rb_define_method(rb_cModule, "public_method_defined?", rb_mod_public_method_defined, 1);
1667 rb_define_method(rb_cModule, "private_method_defined?", rb_mod_private_method_defined, 1);
1668 rb_define_method(rb_cModule, "protected_method_defined?", rb_mod_protected_method_defined, 1);
1669 rb_define_method(rb_cModule, "public_class_method", rb_mod_public_method, -1);
1670 rb_define_method(rb_cModule, "private_class_method", rb_mod_private_method, -1);
1671
1672 rb_define_private_method(rb_singleton_class(rb_vm_top_self()),
1673 "public", top_public, -1);
1674 rb_define_private_method(rb_singleton_class(rb_vm_top_self()),
1675 "private", top_private, -1);
1676
1677 object_id = rb_intern("object_id");
1678 added = rb_intern("method_added");
1679 singleton_added = rb_intern("singleton_method_added");
1680 removed = rb_intern("method_removed");
1681 singleton_removed = rb_intern("singleton_method_removed");
1682 undefined = rb_intern("method_undefined");
1683 singleton_undefined = rb_intern("singleton_method_undefined");
1684 attached = rb_intern("__attached__");
1685
1686 {
1687 #define REPLICATE_METHOD(klass, id, noex) \
1688 rb_method_entry_set((klass), (id), \
1689 rb_method_entry((klass), (id), 0), \
1690 (rb_method_flag_t)(noex | NOEX_BASIC | NOEX_NOREDEF))
1691 REPLICATE_METHOD(rb_eException, idMethodMissing, NOEX_PRIVATE);
1692 REPLICATE_METHOD(rb_eException, idRespond_to, NOEX_PUBLIC);
1693 REPLICATE_METHOD(rb_eException, idRespond_to_missing, NOEX_PUBLIC);
1694 }
1695 }