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