00001
00002
00003
00004
00005 #define CACHE_SIZE 0x800
00006 #define CACHE_MASK 0x7ff
00007 #define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK)
00008
00009 static void rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me);
00010
00011 static ID object_id, respond_to_missing;
00012 static ID removed, singleton_removed, undefined, singleton_undefined;
00013 static ID added, singleton_added, attached;
00014
00015 struct cache_entry {
00016 VALUE filled_version;
00017 ID mid;
00018 VALUE klass;
00019 rb_method_entry_t *me;
00020 };
00021
00022 static struct cache_entry cache[CACHE_SIZE];
00023 #define ruby_running (GET_VM()->running)
00024
00025
00026 static void
00027 vm_clear_global_method_cache(void)
00028 {
00029 struct cache_entry *ent, *end;
00030
00031 ent = cache;
00032 end = ent + CACHE_SIZE;
00033 while (ent < end) {
00034 ent->filled_version = 0;
00035 ent++;
00036 }
00037 }
00038
00039 void
00040 rb_clear_cache(void)
00041 {
00042 rb_vm_change_state();
00043 }
00044
00045 static void
00046 rb_clear_cache_for_undef(VALUE klass, ID id)
00047 {
00048 rb_vm_change_state();
00049 }
00050
00051 static void
00052 rb_clear_cache_by_id(ID id)
00053 {
00054 rb_vm_change_state();
00055 }
00056
00057 void
00058 rb_clear_cache_by_class(VALUE klass)
00059 {
00060 rb_vm_change_state();
00061 }
00062
00063 VALUE
00064 rb_f_notimplement(int argc, VALUE *argv, VALUE obj)
00065 {
00066 rb_notimplement();
00067 }
00068
00069 static void
00070 rb_define_notimplement_method_id(VALUE mod, ID id, rb_method_flag_t noex)
00071 {
00072 rb_add_method(mod, id, VM_METHOD_TYPE_NOTIMPLEMENTED, 0, noex);
00073 }
00074
00075 void
00076 rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_flag_t noex)
00077 {
00078 if (func != rb_f_notimplement) {
00079 rb_method_cfunc_t opt;
00080 opt.func = func;
00081 opt.argc = argc;
00082 rb_add_method(klass, mid, VM_METHOD_TYPE_CFUNC, &opt, noex);
00083 }
00084 else {
00085 rb_define_notimplement_method_id(klass, mid, noex);
00086 }
00087 }
00088
00089 void
00090 rb_unlink_method_entry(rb_method_entry_t *me)
00091 {
00092 struct unlinked_method_entry_list_entry *ume = ALLOC(struct unlinked_method_entry_list_entry);
00093 ume->me = me;
00094 ume->next = GET_VM()->unlinked_method_entry_list;
00095 GET_VM()->unlinked_method_entry_list = ume;
00096 }
00097
00098 void
00099 rb_gc_mark_unlinked_live_method_entries(void *pvm)
00100 {
00101 rb_vm_t *vm = pvm;
00102 struct unlinked_method_entry_list_entry *ume = vm->unlinked_method_entry_list;
00103
00104 while (ume) {
00105 if (ume->me->mark) {
00106 rb_mark_method_entry(ume->me);
00107 }
00108 ume = ume->next;
00109 }
00110 }
00111
00112 void
00113 rb_sweep_method_entry(void *pvm)
00114 {
00115 rb_vm_t *vm = pvm;
00116 struct unlinked_method_entry_list_entry *ume = vm->unlinked_method_entry_list, *prev_ume = 0, *curr_ume;
00117
00118 while (ume) {
00119 if (ume->me->mark) {
00120 ume->me->mark = 0;
00121 prev_ume = ume;
00122 ume = ume->next;
00123 }
00124 else {
00125 rb_free_method_entry(ume->me);
00126
00127 if (prev_ume == 0) {
00128 vm->unlinked_method_entry_list = ume->next;
00129 }
00130 else {
00131 prev_ume->next = ume->next;
00132 }
00133
00134 curr_ume = ume;
00135 ume = ume->next;
00136 xfree(curr_ume);
00137 }
00138 }
00139 }
00140
00141 void
00142 rb_free_method_entry(rb_method_entry_t *me)
00143 {
00144 rb_method_definition_t *def = me->def;
00145
00146 if (def) {
00147 if (def->alias_count == 0) {
00148 xfree(def);
00149 }
00150 else if (def->alias_count > 0) {
00151 def->alias_count--;
00152 }
00153 me->def = 0;
00154 }
00155 xfree(me);
00156 }
00157
00158 static int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
00159
00160 static rb_method_entry_t *
00161 rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type,
00162 rb_method_definition_t *def, rb_method_flag_t noex)
00163 {
00164 rb_method_entry_t *me;
00165 st_table *mtbl;
00166 st_data_t data;
00167
00168 if (NIL_P(klass)) {
00169 klass = rb_cObject;
00170 }
00171 if (rb_safe_level() >= 4 &&
00172 (klass == rb_cObject || !OBJ_UNTRUSTED(klass))) {
00173 rb_raise(rb_eSecurityError, "Insecure: can't define method");
00174 }
00175 if (!FL_TEST(klass, FL_SINGLETON) &&
00176 type != VM_METHOD_TYPE_NOTIMPLEMENTED &&
00177 type != VM_METHOD_TYPE_ZSUPER &&
00178 (mid == rb_intern("initialize") || mid == rb_intern("initialize_copy"))) {
00179 noex = NOEX_PRIVATE | noex;
00180 }
00181 else if (FL_TEST(klass, FL_SINGLETON) &&
00182 type == VM_METHOD_TYPE_CFUNC &&
00183 mid == rb_intern("allocate")) {
00184 rb_warn("defining %s.allocate is deprecated; use rb_define_alloc_func()",
00185 rb_class2name(rb_ivar_get(klass, attached)));
00186 mid = ID_ALLOCATOR;
00187 }
00188
00189 rb_check_frozen(klass);
00190 mtbl = RCLASS_M_TBL(klass);
00191
00192
00193 if (st_lookup(mtbl, mid, &data)) {
00194 rb_method_entry_t *old_me = (rb_method_entry_t *)data;
00195 rb_method_definition_t *old_def = old_me->def;
00196
00197 if (rb_method_definition_eq(old_def, def)) return old_me;
00198 rb_vm_check_redefinition_opt_method(old_me);
00199
00200 if (RTEST(ruby_verbose) &&
00201 type != VM_METHOD_TYPE_UNDEF &&
00202 old_def->alias_count == 0 &&
00203 old_def->type != VM_METHOD_TYPE_UNDEF &&
00204 old_def->type != VM_METHOD_TYPE_ZSUPER) {
00205 rb_iseq_t *iseq = 0;
00206
00207 rb_warning("method redefined; discarding old %s", rb_id2name(mid));
00208 switch (old_def->type) {
00209 case VM_METHOD_TYPE_ISEQ:
00210 iseq = old_def->body.iseq;
00211 break;
00212 case VM_METHOD_TYPE_BMETHOD:
00213 iseq = rb_proc_get_iseq(old_def->body.proc, 0);
00214 break;
00215 default:
00216 break;
00217 }
00218 if (iseq && !NIL_P(iseq->filename)) {
00219 int line = iseq->insn_info_table ? rb_iseq_first_lineno(iseq) : 0;
00220 rb_compile_warning(RSTRING_PTR(iseq->filename), line,
00221 "previous definition of %s was here",
00222 rb_id2name(old_def->original_id));
00223 }
00224 }
00225
00226 rb_unlink_method_entry(old_me);
00227 }
00228
00229 me = ALLOC(rb_method_entry_t);
00230
00231 rb_clear_cache_by_id(mid);
00232
00233 me->flag = NOEX_WITH_SAFE(noex);
00234 me->mark = 0;
00235 me->called_id = mid;
00236 me->klass = klass;
00237 me->def = def;
00238 if (def) def->alias_count++;
00239
00240
00241 if (klass == rb_cObject && mid == idInitialize) {
00242 rb_warn("redefining Object#initialize may cause infinite loop");
00243 }
00244
00245 if (mid == object_id || mid == id__send__) {
00246 if (type == VM_METHOD_TYPE_ISEQ) {
00247 rb_warn("redefining `%s' may cause serious problems", rb_id2name(mid));
00248 }
00249 }
00250
00251 st_insert(mtbl, mid, (st_data_t) me);
00252
00253 return me;
00254 }
00255
00256 #define CALL_METHOD_HOOK(klass, hook, mid) do { \
00257 const VALUE arg = ID2SYM(mid); \
00258 VALUE recv_class = (klass); \
00259 ID hook_id = (hook); \
00260 if (FL_TEST((klass), FL_SINGLETON)) { \
00261 recv_class = rb_ivar_get((klass), attached); \
00262 hook_id = singleton_##hook; \
00263 } \
00264 rb_funcall2(recv_class, hook_id, 1, &arg); \
00265 } while (0)
00266
00267 static void
00268 method_added(VALUE klass, ID mid)
00269 {
00270 if (mid != ID_ALLOCATOR && ruby_running) {
00271 CALL_METHOD_HOOK(klass, added, mid);
00272 }
00273 }
00274
00275 rb_method_entry_t *
00276 rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_flag_t noex)
00277 {
00278 rb_thread_t *th;
00279 rb_control_frame_t *cfp;
00280 int line;
00281 rb_method_entry_t *me = rb_method_entry_make(klass, mid, type, 0, noex);
00282 rb_method_definition_t *def = ALLOC(rb_method_definition_t);
00283 me->def = def;
00284 def->type = type;
00285 def->original_id = mid;
00286 def->alias_count = 0;
00287 switch (type) {
00288 case VM_METHOD_TYPE_ISEQ:
00289 def->body.iseq = (rb_iseq_t *)opts;
00290 break;
00291 case VM_METHOD_TYPE_CFUNC:
00292 def->body.cfunc = *(rb_method_cfunc_t *)opts;
00293 break;
00294 case VM_METHOD_TYPE_ATTRSET:
00295 case VM_METHOD_TYPE_IVAR:
00296 def->body.attr.id = (ID)opts;
00297 def->body.attr.location = Qfalse;
00298 th = GET_THREAD();
00299 cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
00300 if (cfp && (line = rb_vm_get_sourceline(cfp))) {
00301 VALUE location = rb_ary_new3(2, cfp->iseq->filename, INT2FIX(line));
00302 def->body.attr.location = rb_ary_freeze(location);
00303 }
00304 break;
00305 case VM_METHOD_TYPE_BMETHOD:
00306 def->body.proc = (VALUE)opts;
00307 break;
00308 case VM_METHOD_TYPE_NOTIMPLEMENTED:
00309 def->body.cfunc.func = rb_f_notimplement;
00310 def->body.cfunc.argc = -1;
00311 break;
00312 case VM_METHOD_TYPE_OPTIMIZED:
00313 def->body.optimize_type = (enum method_optimized_type)opts;
00314 break;
00315 case VM_METHOD_TYPE_ZSUPER:
00316 case VM_METHOD_TYPE_UNDEF:
00317 break;
00318 default:
00319 rb_bug("rb_add_method: unsupported method type (%d)\n", type);
00320 }
00321 if (type != VM_METHOD_TYPE_UNDEF) {
00322 method_added(klass, mid);
00323 }
00324 return me;
00325 }
00326
00327 rb_method_entry_t *
00328 rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *me, rb_method_flag_t noex)
00329 {
00330 rb_method_type_t type = me->def ? me->def->type : VM_METHOD_TYPE_UNDEF;
00331 rb_method_entry_t *newme = rb_method_entry_make(klass, mid, type, me->def, noex);
00332 method_added(klass, mid);
00333 return newme;
00334 }
00335
00336 void
00337 rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE))
00338 {
00339 Check_Type(klass, T_CLASS);
00340 rb_add_method_cfunc(rb_singleton_class(klass), ID_ALLOCATOR,
00341 func, 0, NOEX_PRIVATE);
00342 }
00343
00344 void
00345 rb_undef_alloc_func(VALUE klass)
00346 {
00347 Check_Type(klass, T_CLASS);
00348 rb_add_method(rb_singleton_class(klass), ID_ALLOCATOR, VM_METHOD_TYPE_UNDEF, 0, NOEX_UNDEF);
00349 }
00350
00351 rb_alloc_func_t
00352 rb_get_alloc_func(VALUE klass)
00353 {
00354 rb_method_entry_t *me;
00355 Check_Type(klass, T_CLASS);
00356 me = rb_method_entry(CLASS_OF(klass), ID_ALLOCATOR);
00357
00358 if (me && me->def && me->def->type == VM_METHOD_TYPE_CFUNC) {
00359 return (rb_alloc_func_t)me->def->body.cfunc.func;
00360 }
00361 else {
00362 return 0;
00363 }
00364 }
00365
00366 static rb_method_entry_t*
00367 search_method(VALUE klass, ID id)
00368 {
00369 st_data_t body;
00370 if (!klass) {
00371 return 0;
00372 }
00373
00374 while (!st_lookup(RCLASS_M_TBL(klass), id, &body)) {
00375 klass = RCLASS_SUPER(klass);
00376 if (!klass) {
00377 return 0;
00378 }
00379 }
00380
00381 return (rb_method_entry_t *)body;
00382 }
00383
00384
00385
00386
00387
00388
00389
00390 rb_method_entry_t *
00391 rb_method_entry_get_without_cache(VALUE klass, ID id)
00392 {
00393 rb_method_entry_t *me = search_method(klass, id);
00394
00395 if (ruby_running) {
00396 struct cache_entry *ent;
00397 ent = cache + EXPR1(klass, id);
00398 ent->filled_version = GET_VM_STATE_VERSION();
00399 ent->klass = klass;
00400
00401 if (UNDEFINED_METHOD_ENTRY_P(me)) {
00402 ent->mid = id;
00403 ent->me = 0;
00404 me = 0;
00405 }
00406 else {
00407 ent->mid = id;
00408 ent->me = me;
00409 }
00410 }
00411
00412 return me;
00413 }
00414
00415 rb_method_entry_t *
00416 rb_method_entry(VALUE klass, ID id)
00417 {
00418 struct cache_entry *ent;
00419
00420 ent = cache + EXPR1(klass, id);
00421 if (ent->filled_version == GET_VM_STATE_VERSION() &&
00422 ent->mid == id && ent->klass == klass) {
00423 return ent->me;
00424 }
00425
00426 return rb_method_entry_get_without_cache(klass, id);
00427 }
00428
00429 static void
00430 remove_method(VALUE klass, ID mid)
00431 {
00432 st_data_t key, data;
00433 rb_method_entry_t *me = 0;
00434
00435 if (klass == rb_cObject) {
00436 rb_secure(4);
00437 }
00438 if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(klass)) {
00439 rb_raise(rb_eSecurityError, "Insecure: can't remove method");
00440 }
00441 rb_check_frozen(klass);
00442 if (mid == object_id || mid == id__send__ || mid == idInitialize) {
00443 rb_warn("removing `%s' may cause serious problems", rb_id2name(mid));
00444 }
00445
00446 if (!st_lookup(RCLASS_M_TBL(klass), mid, &data) ||
00447 !(me = (rb_method_entry_t *)data) ||
00448 (!me->def || me->def->type == VM_METHOD_TYPE_UNDEF)) {
00449 rb_name_error(mid, "method `%s' not defined in %s",
00450 rb_id2name(mid), rb_class2name(klass));
00451 }
00452 key = (st_data_t)mid;
00453 st_delete(RCLASS_M_TBL(klass), &key, &data);
00454
00455 rb_vm_check_redefinition_opt_method(me);
00456 rb_clear_cache_for_undef(klass, mid);
00457 rb_unlink_method_entry(me);
00458
00459 CALL_METHOD_HOOK(klass, removed, mid);
00460 }
00461
00462 void
00463 rb_remove_method_id(VALUE klass, ID mid)
00464 {
00465 remove_method(klass, mid);
00466 }
00467
00468 void
00469 rb_remove_method(VALUE klass, const char *name)
00470 {
00471 remove_method(klass, rb_intern(name));
00472 }
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482 static VALUE
00483 rb_mod_remove_method(int argc, VALUE *argv, VALUE mod)
00484 {
00485 int i;
00486
00487 for (i = 0; i < argc; i++) {
00488 remove_method(mod, rb_to_id(argv[i]));
00489 }
00490 return mod;
00491 }
00492
00493 #undef rb_disable_super
00494 #undef rb_enable_super
00495
00496 void
00497 rb_disable_super(VALUE klass, const char *name)
00498 {
00499
00500 }
00501
00502 void
00503 rb_enable_super(VALUE klass, const char *name)
00504 {
00505 rb_warning("rb_enable_super() is obsolete");
00506 }
00507
00508 static void
00509 rb_export_method(VALUE klass, ID name, rb_method_flag_t noex)
00510 {
00511 rb_method_entry_t *me;
00512
00513 if (klass == rb_cObject) {
00514 rb_secure(4);
00515 }
00516
00517 me = search_method(klass, name);
00518 if (!me && TYPE(klass) == T_MODULE) {
00519 me = search_method(rb_cObject, name);
00520 }
00521
00522 if (UNDEFINED_METHOD_ENTRY_P(me)) {
00523 rb_print_undef(klass, name, 0);
00524 }
00525
00526 if (me->flag != noex) {
00527 rb_vm_check_redefinition_opt_method(me);
00528
00529 if (klass == me->klass) {
00530 me->flag = noex;
00531 }
00532 else {
00533 rb_add_method(klass, name, VM_METHOD_TYPE_ZSUPER, 0, noex);
00534 }
00535 }
00536 }
00537
00538 int
00539 rb_method_boundp(VALUE klass, ID id, int ex)
00540 {
00541 rb_method_entry_t *me = rb_method_entry(klass, id);
00542
00543 if (me != 0) {
00544 if ((ex & ~NOEX_RESPONDS) && (me->flag & NOEX_PRIVATE)) {
00545 return FALSE;
00546 }
00547 if (!me->def) return 0;
00548 if (me->def->type == VM_METHOD_TYPE_NOTIMPLEMENTED) {
00549 if (ex & NOEX_RESPONDS) return 2;
00550 return 0;
00551 }
00552 return 1;
00553 }
00554 return 0;
00555 }
00556
00557 void
00558 rb_attr(VALUE klass, ID id, int read, int write, int ex)
00559 {
00560 const char *name;
00561 ID attriv;
00562 VALUE aname;
00563 rb_method_flag_t noex;
00564
00565 if (!ex) {
00566 noex = NOEX_PUBLIC;
00567 }
00568 else {
00569 if (SCOPE_TEST(NOEX_PRIVATE)) {
00570 noex = NOEX_PRIVATE;
00571 rb_warning((SCOPE_CHECK(NOEX_MODFUNC)) ?
00572 "attribute accessor as module_function" :
00573 "private attribute?");
00574 }
00575 else if (SCOPE_TEST(NOEX_PROTECTED)) {
00576 noex = NOEX_PROTECTED;
00577 }
00578 else {
00579 noex = NOEX_PUBLIC;
00580 }
00581 }
00582
00583 if (!rb_is_local_id(id) && !rb_is_const_id(id)) {
00584 rb_name_error(id, "invalid attribute name `%s'", rb_id2name(id));
00585 }
00586 name = rb_id2name(id);
00587 if (!name) {
00588 rb_raise(rb_eArgError, "argument needs to be symbol or string");
00589 }
00590 aname = rb_sprintf("@%s", name);
00591 rb_enc_copy(aname, rb_id2str(id));
00592 attriv = rb_intern_str(aname);
00593 if (read) {
00594 rb_add_method(klass, id, VM_METHOD_TYPE_IVAR, (void *)attriv, noex);
00595 }
00596 if (write) {
00597 rb_add_method(klass, rb_id_attrset(id), VM_METHOD_TYPE_ATTRSET, (void *)attriv, noex);
00598 }
00599 }
00600
00601 void
00602 rb_undef(VALUE klass, ID id)
00603 {
00604 rb_method_entry_t *me;
00605
00606 if (NIL_P(klass)) {
00607 rb_raise(rb_eTypeError, "no class to undef method");
00608 }
00609 if (rb_vm_cbase() == rb_cObject && klass == rb_cObject) {
00610 rb_secure(4);
00611 }
00612 if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(klass)) {
00613 rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'", rb_id2name(id));
00614 }
00615 rb_frozen_class_p(klass);
00616 if (id == object_id || id == id__send__ || id == idInitialize) {
00617 rb_warn("undefining `%s' may cause serious problems", rb_id2name(id));
00618 }
00619
00620 me = search_method(klass, id);
00621
00622 if (UNDEFINED_METHOD_ENTRY_P(me)) {
00623 const char *s0 = " class";
00624 VALUE c = klass;
00625
00626 if (FL_TEST(c, FL_SINGLETON)) {
00627 VALUE obj = rb_ivar_get(klass, attached);
00628
00629 switch (TYPE(obj)) {
00630 case T_MODULE:
00631 case T_CLASS:
00632 c = obj;
00633 s0 = "";
00634 }
00635 }
00636 else if (TYPE(c) == T_MODULE) {
00637 s0 = " module";
00638 }
00639 rb_name_error(id, "undefined method `%s' for%s `%s'",
00640 rb_id2name(id), s0, rb_class2name(c));
00641 }
00642
00643 rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, NOEX_PUBLIC);
00644
00645 CALL_METHOD_HOOK(klass, undefined, id);
00646 }
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691 static VALUE
00692 rb_mod_undef_method(int argc, VALUE *argv, VALUE mod)
00693 {
00694 int i;
00695 for (i = 0; i < argc; i++) {
00696 rb_undef(mod, rb_to_id(argv[i]));
00697 }
00698 return mod;
00699 }
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727 static VALUE
00728 rb_mod_method_defined(VALUE mod, VALUE mid)
00729 {
00730 if (!rb_method_boundp(mod, rb_to_id(mid), 1)) {
00731 return Qfalse;
00732 }
00733 return Qtrue;
00734
00735 }
00736
00737 #define VISI_CHECK(x,f) (((x)&NOEX_MASK) == (f))
00738
00739 static VALUE
00740 check_definition(VALUE mod, ID mid, rb_method_flag_t noex)
00741 {
00742 const rb_method_entry_t *me;
00743 me = rb_method_entry(mod, mid);
00744 if (me) {
00745 if (VISI_CHECK(me->flag, noex))
00746 return Qtrue;
00747 }
00748 return Qfalse;
00749 }
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777 static VALUE
00778 rb_mod_public_method_defined(VALUE mod, VALUE mid)
00779 {
00780 return check_definition(mod, rb_to_id(mid), NOEX_PUBLIC);
00781 }
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809 static VALUE
00810 rb_mod_private_method_defined(VALUE mod, VALUE mid)
00811 {
00812 return check_definition(mod, rb_to_id(mid), NOEX_PRIVATE);
00813 }
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841 static VALUE
00842 rb_mod_protected_method_defined(VALUE mod, VALUE mid)
00843 {
00844 return check_definition(mod, rb_to_id(mid), NOEX_PROTECTED);
00845 }
00846
00847 int
00848 rb_method_entry_eq(const rb_method_entry_t *m1, const rb_method_entry_t *m2)
00849 {
00850 return rb_method_definition_eq(m1->def, m2->def);
00851 }
00852
00853 static int
00854 rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2)
00855 {
00856 if (d1 == d2) return 1;
00857 if (!d1 || !d2) return 0;
00858 if (d1->type != d2->type) {
00859 return 0;
00860 }
00861 switch (d1->type) {
00862 case VM_METHOD_TYPE_ISEQ:
00863 return d1->body.iseq == d2->body.iseq;
00864 case VM_METHOD_TYPE_CFUNC:
00865 return
00866 d1->body.cfunc.func == d2->body.cfunc.func &&
00867 d1->body.cfunc.argc == d2->body.cfunc.argc;
00868 case VM_METHOD_TYPE_ATTRSET:
00869 case VM_METHOD_TYPE_IVAR:
00870 return d1->body.attr.id == d2->body.attr.id;
00871 case VM_METHOD_TYPE_BMETHOD:
00872 return RTEST(rb_equal(d1->body.proc, d2->body.proc));
00873 case VM_METHOD_TYPE_MISSING:
00874 return d1->original_id == d2->original_id;
00875 case VM_METHOD_TYPE_ZSUPER:
00876 case VM_METHOD_TYPE_NOTIMPLEMENTED:
00877 case VM_METHOD_TYPE_UNDEF:
00878 return 1;
00879 case VM_METHOD_TYPE_OPTIMIZED:
00880 return d1->body.optimize_type == d2->body.optimize_type;
00881 default:
00882 rb_bug("rb_method_entry_eq: unsupported method type (%d)\n", d1->type);
00883 return 0;
00884 }
00885 }
00886
00887 void
00888 rb_alias(VALUE klass, ID name, ID def)
00889 {
00890 VALUE target_klass = klass;
00891 rb_method_entry_t *orig_me;
00892 rb_method_flag_t flag = NOEX_UNDEF;
00893
00894 if (NIL_P(klass)) {
00895 rb_raise(rb_eTypeError, "no class to make alias");
00896 }
00897
00898 rb_frozen_class_p(klass);
00899 if (klass == rb_cObject) {
00900 rb_secure(4);
00901 }
00902
00903 again:
00904 orig_me = search_method(klass, def);
00905
00906 if (UNDEFINED_METHOD_ENTRY_P(orig_me)) {
00907 if ((TYPE(klass) != T_MODULE) ||
00908 (orig_me = search_method(rb_cObject, def), UNDEFINED_METHOD_ENTRY_P(orig_me))) {
00909 rb_print_undef(klass, def, 0);
00910 }
00911 }
00912 if (orig_me->def->type == VM_METHOD_TYPE_ZSUPER) {
00913 klass = RCLASS_SUPER(klass);
00914 def = orig_me->def->original_id;
00915 flag = orig_me->flag;
00916 goto again;
00917 }
00918
00919 if (flag == NOEX_UNDEF) flag = orig_me->flag;
00920 rb_method_entry_set(target_klass, name, orig_me, flag);
00921 }
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945 static VALUE
00946 rb_mod_alias_method(VALUE mod, VALUE newname, VALUE oldname)
00947 {
00948 rb_alias(mod, rb_to_id(newname), rb_to_id(oldname));
00949 return mod;
00950 }
00951
00952 static void
00953 secure_visibility(VALUE self)
00954 {
00955 if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(self)) {
00956 rb_raise(rb_eSecurityError,
00957 "Insecure: can't change method visibility");
00958 }
00959 }
00960
00961 static void
00962 set_method_visibility(VALUE self, int argc, VALUE *argv, rb_method_flag_t ex)
00963 {
00964 int i;
00965 secure_visibility(self);
00966
00967 if (argc == 0) {
00968 rb_warning("%s with no argument is just ignored", rb_id2name(rb_frame_callee()));
00969 }
00970
00971 for (i = 0; i < argc; i++) {
00972 rb_export_method(self, rb_to_id(argv[i]), ex);
00973 }
00974 rb_clear_cache_by_class(self);
00975 }
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987 static VALUE
00988 rb_mod_public(int argc, VALUE *argv, VALUE module)
00989 {
00990 secure_visibility(module);
00991 if (argc == 0) {
00992 SCOPE_SET(NOEX_PUBLIC);
00993 }
00994 else {
00995 set_method_visibility(module, argc, argv, NOEX_PUBLIC);
00996 }
00997 return module;
00998 }
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010 static VALUE
01011 rb_mod_protected(int argc, VALUE *argv, VALUE module)
01012 {
01013 secure_visibility(module);
01014 if (argc == 0) {
01015 SCOPE_SET(NOEX_PROTECTED);
01016 }
01017 else {
01018 set_method_visibility(module, argc, argv, NOEX_PROTECTED);
01019 }
01020 return module;
01021 }
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042 static VALUE
01043 rb_mod_private(int argc, VALUE *argv, VALUE module)
01044 {
01045 secure_visibility(module);
01046 if (argc == 0) {
01047 SCOPE_SET(NOEX_PRIVATE);
01048 }
01049 else {
01050 set_method_visibility(module, argc, argv, NOEX_PRIVATE);
01051 }
01052 return module;
01053 }
01054
01055
01056
01057
01058
01059
01060
01061
01062 static VALUE
01063 rb_mod_public_method(int argc, VALUE *argv, VALUE obj)
01064 {
01065 set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PUBLIC);
01066 return obj;
01067 }
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085 static VALUE
01086 rb_mod_private_method(int argc, VALUE *argv, VALUE obj)
01087 {
01088 set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PRIVATE);
01089 return obj;
01090 }
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102 static VALUE
01103 top_public(int argc, VALUE *argv)
01104 {
01105 return rb_mod_public(argc, argv, rb_cObject);
01106 }
01107
01108 static VALUE
01109 top_private(int argc, VALUE *argv)
01110 {
01111 return rb_mod_private(argc, argv, rb_cObject);
01112 }
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150 static VALUE
01151 rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
01152 {
01153 int i;
01154 ID id;
01155 const rb_method_entry_t *me;
01156
01157 if (TYPE(module) != T_MODULE) {
01158 rb_raise(rb_eTypeError, "module_function must be called for modules");
01159 }
01160
01161 secure_visibility(module);
01162 if (argc == 0) {
01163 SCOPE_SET(NOEX_MODFUNC);
01164 return module;
01165 }
01166
01167 set_method_visibility(module, argc, argv, NOEX_PRIVATE);
01168
01169 for (i = 0; i < argc; i++) {
01170 VALUE m = module;
01171
01172 id = rb_to_id(argv[i]);
01173 for (;;) {
01174 me = search_method(m, id);
01175 if (me == 0) {
01176 me = search_method(rb_cObject, id);
01177 }
01178 if (UNDEFINED_METHOD_ENTRY_P(me)) {
01179 rb_print_undef(module, id, 0);
01180 }
01181 if (me->def->type != VM_METHOD_TYPE_ZSUPER) {
01182 break;
01183 }
01184 m = RCLASS_SUPER(m);
01185 if (!m)
01186 break;
01187 }
01188 rb_method_entry_set(rb_singleton_class(module), id, me, NOEX_PUBLIC);
01189 }
01190 return module;
01191 }
01192
01193 int
01194 rb_method_basic_definition_p(VALUE klass, ID id)
01195 {
01196 const rb_method_entry_t *me = rb_method_entry(klass, id);
01197 if (me && (me->flag & NOEX_BASIC))
01198 return 1;
01199 return 0;
01200 }
01201
01202 static inline int
01203 basic_obj_respond_to(VALUE obj, ID id, int pub)
01204 {
01205 VALUE klass = CLASS_OF(obj);
01206
01207 switch (rb_method_boundp(klass, id, pub|NOEX_RESPONDS)) {
01208 case 2:
01209 return FALSE;
01210 case 0:
01211 return RTEST(rb_funcall(obj, respond_to_missing, 2, ID2SYM(id), pub ? Qfalse : Qtrue));
01212 default:
01213 return TRUE;
01214 }
01215 }
01216
01217 int
01218 rb_obj_respond_to(VALUE obj, ID id, int priv)
01219 {
01220 VALUE klass = CLASS_OF(obj);
01221
01222 if (rb_method_basic_definition_p(klass, idRespond_to)) {
01223 return basic_obj_respond_to(obj, id, !RTEST(priv));
01224 }
01225 else {
01226 return RTEST(rb_funcall(obj, idRespond_to, priv ? 2 : 1, ID2SYM(id), Qtrue));
01227 }
01228 }
01229
01230 int
01231 rb_respond_to(VALUE obj, ID id)
01232 {
01233 return rb_obj_respond_to(obj, id, FALSE);
01234 }
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253 static VALUE
01254 obj_respond_to(int argc, VALUE *argv, VALUE obj)
01255 {
01256 VALUE mid, priv;
01257 ID id;
01258
01259 rb_scan_args(argc, argv, "11", &mid, &priv);
01260 id = rb_to_id(mid);
01261 if (basic_obj_respond_to(obj, id, !RTEST(priv)))
01262 return Qtrue;
01263 return Qfalse;
01264 }
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275 static VALUE
01276 obj_respond_to_missing(VALUE obj, VALUE mid, VALUE priv)
01277 {
01278 return Qfalse;
01279 }
01280
01281 void
01282 Init_eval_method(void)
01283 {
01284 #undef rb_intern
01285 #define rb_intern(str) rb_intern_const(str)
01286
01287 rb_define_method(rb_mKernel, "respond_to?", obj_respond_to, -1);
01288 rb_define_method(rb_mKernel, "respond_to_missing?", obj_respond_to_missing, 2);
01289
01290 rb_define_private_method(rb_cModule, "remove_method", rb_mod_remove_method, -1);
01291 rb_define_private_method(rb_cModule, "undef_method", rb_mod_undef_method, -1);
01292 rb_define_private_method(rb_cModule, "alias_method", rb_mod_alias_method, 2);
01293 rb_define_private_method(rb_cModule, "public", rb_mod_public, -1);
01294 rb_define_private_method(rb_cModule, "protected", rb_mod_protected, -1);
01295 rb_define_private_method(rb_cModule, "private", rb_mod_private, -1);
01296 rb_define_private_method(rb_cModule, "module_function", rb_mod_modfunc, -1);
01297
01298 rb_define_method(rb_cModule, "method_defined?", rb_mod_method_defined, 1);
01299 rb_define_method(rb_cModule, "public_method_defined?", rb_mod_public_method_defined, 1);
01300 rb_define_method(rb_cModule, "private_method_defined?", rb_mod_private_method_defined, 1);
01301 rb_define_method(rb_cModule, "protected_method_defined?", rb_mod_protected_method_defined, 1);
01302 rb_define_method(rb_cModule, "public_class_method", rb_mod_public_method, -1);
01303 rb_define_method(rb_cModule, "private_class_method", rb_mod_private_method, -1);
01304
01305 rb_define_singleton_method(rb_vm_top_self(), "public", top_public, -1);
01306 rb_define_singleton_method(rb_vm_top_self(), "private", top_private, -1);
01307
01308 object_id = rb_intern("object_id");
01309 added = rb_intern("method_added");
01310 singleton_added = rb_intern("singleton_method_added");
01311 removed = rb_intern("method_removed");
01312 singleton_removed = rb_intern("singleton_method_removed");
01313 undefined = rb_intern("method_undefined");
01314 singleton_undefined = rb_intern("singleton_method_undefined");
01315 attached = rb_intern("__attached__");
01316 respond_to_missing = rb_intern("respond_to_missing?");
01317 }
01318
01319