(linenum→info "unix/slp.c:2238")

ruby/1.9.0/eval_method.c

    1: /* -*-c-*- */
    2: /*
    3:  * This file is included by eval.c
    4:  */
    5: 
    6: #define CACHE_SIZE 0x800
    7: #define CACHE_MASK 0x7ff
    8: #define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK)
    9: 
   10: struct cache_entry {            /* method hash table. */
   11:     ID mid;                     /* method's id */
   12:     ID mid0;                    /* method's original id */
   13:     VALUE klass;                /* receiver's class */
   14:     NODE *method;
   15: };
   16: 
   17: static struct cache_entry cache[CACHE_SIZE];
   18: static int ruby_running = 0;
   19: 
   20: void
   21: rb_clear_cache(void)
   22: {
   23:     struct cache_entry *ent, *end;
   24: 
   25:     rb_vm_change_state();
   26: 
   27:     if (!ruby_running)
   28:         return;
   29:     ent = cache;
   30:     end = ent + CACHE_SIZE;
   31:     while (ent < end) {
   32:         ent->mid = 0;
   33:         ent++;
   34:     }
   35: }
   36: 
   37: static void
   38: rb_clear_cache_for_undef(VALUE klass, ID id)
   39: {
   40:     struct cache_entry *ent, *end;
   41: 
   42:     rb_vm_change_state();
   43: 
   44:     if (!ruby_running)
   45:         return;
   46:     ent = cache;
   47:     end = ent + CACHE_SIZE;
   48:     while (ent < end) {
   49:         if (ent->method && ent->method->nd_clss == klass && ent->mid == id) {
   50:             ent->mid = 0;
   51:         }
   52:         ent++;
   53:     }
   54: }
   55: 
   56: static void
   57: rb_clear_cache_by_id(ID id)
   58: {
   59:     struct cache_entry *ent, *end;
   60: 
   61:     rb_vm_change_state();
   62: 
   63:     if (!ruby_running)
   64:         return;
   65:     ent = cache;
   66:     end = ent + CACHE_SIZE;
   67:     while (ent < end) {
   68:         if (ent->mid == id) {
   69:             ent->mid = 0;
   70:         }
   71:         ent++;
   72:     }
   73: }
   74: 
   75: void
   76: rb_clear_cache_by_class(VALUE klass)
   77: {
   78:     struct cache_entry *ent, *end;
   79: 
   80:     rb_vm_change_state();
   81: 
   82:     if (!ruby_running)
   83:         return;
   84:     ent = cache;
   85:     end = ent + CACHE_SIZE;
   86:     while (ent < end) {
   87:         if ((ent->klass == klass) ||
   88:             (ent->method && ent->method->nd_clss == klass)) {
   89:             ent->mid = 0;
   90:         }
   91:         ent++;
   92:     }
   93: }
   94: 
   95: void
   96: rb_add_method(VALUE klass, ID mid, NODE * node, int noex)
   97: {
   98:     NODE *body;
   99: 
  100:     if (NIL_P(klass)) {
  101:         klass = rb_cObject;
  102:     }
  103:     if (rb_safe_level() >= 4 && (klass == rb_cObject || !OBJ_TAINTED(klass))) {
  104:         rb_raise(rb_eSecurityError, "Insecure: can't define method");
  105:     }
  106:     if (!FL_TEST(klass, FL_SINGLETON) &&
  107:         node && nd_type(node) != NODE_ZSUPER &&
  108:         (mid == rb_intern("initialize") || mid == rb_intern("initialize_copy"))) {
  109:         noex = NOEX_PRIVATE | noex;
  110:     }
  111:     else if (FL_TEST(klass, FL_SINGLETON) && node
  112:              && nd_type(node) == NODE_CFUNC && mid == rb_intern("allocate")) {
  113:         rb_warn
  114:             ("defining %s.allocate is deprecated; use rb_define_alloc_func()",
  115:              rb_class2name(rb_iv_get(klass, "__attached__")));
  116:         mid = ID_ALLOCATOR;
  117:     }
  118:     if (OBJ_FROZEN(klass)) {
  119:         rb_error_frozen("class/module");
  120:     }
  121:     rb_clear_cache_by_id(mid);
  122: 
  123:     /*
  124:      * NODE_METHOD (NEW_METHOD(body, klass, vis)):
  125:      *   nd_body : method body   // (2) // mark
  126:      *   nd_clss : klass         // (1) // mark
  127:      *   nd_noex : visibility    // (3)
  128:      *
  129:      * NODE_FBODY (NEW_FBODY(method, alias)):
  130:      *   nd_body : method (NODE_METHOD)  // (2) // mark
  131:      *   nd_oid  : original id           // (1)
  132:      *   nd_cnt  : alias count           // (3)
  133:      */
  134:     if (node) {
  135:         body = NEW_FBODY(NEW_METHOD(node, klass, NOEX_WITH_SAFE(noex)), 0);
  136:     }
  137:     else {
  138:         body = 0;
  139:     }
  140: 
  141:     {
  142:         /* check re-definition */
  143:         st_data_t data;
  144:         NODE *old_node;
  145: 
  146:         if (st_lookup(RCLASS_M_TBL(klass), mid, &data)) {
  147:             old_node = (NODE *)data;
  148:             if (old_node) {
  149:                 if (nd_type(old_node->nd_body->nd_body) == NODE_CFUNC) {
  150:                     rb_vm_check_redefinition_opt_method(old_node);
  151:                 }
  152:                 if (RTEST(ruby_verbose) && node && old_node->nd_cnt == 0 && old_node->nd_body) {
  153:                     rb_warning("method redefined; discarding old %s", rb_id2name(mid));
  154:                 }
  155:             }
  156:             if (klass == rb_cObject && node && node->nd_mid == init) {
  157:                 rb_warn("redefining Object#initialize may cause infinite loop");
  158:             }
  159:         }
  160: 
  161:         if (mid == object_id || mid == __send__) {
  162:             if (node && nd_type(node) == RUBY_VM_METHOD_NODE) {
  163:                 rb_warn("redefining `%s' may cause serious problem",
  164:                         rb_id2name(mid));
  165:             }
  166:         }
  167:     }
  168: 
  169:     st_insert(RCLASS_M_TBL(klass), mid, (st_data_t) body);
  170: 
  171:     if (node && mid != ID_ALLOCATOR && ruby_running) {
  172:         if (FL_TEST(klass, FL_SINGLETON)) {
  173:             rb_funcall(rb_iv_get(klass, "__attached__"), singleton_added, 1,
  174:                        ID2SYM(mid));
  175:         }
  176:         else {
  177:             rb_funcall(klass, added, 1, ID2SYM(mid));
  178:         }
  179:     }
  180: }
  181: 
  182: void
  183: rb_define_alloc_func(VALUE klass, VALUE (*func) _((VALUE)))
  184: {
  185:     Check_Type(klass, T_CLASS);
  186:     rb_add_method(CLASS_OF(klass), ID_ALLOCATOR, NEW_CFUNC(func, 0),
  187:                   NOEX_PRIVATE);
  188: }
  189: 
  190: void
  191: rb_undef_alloc_func(VALUE klass)
  192: {
  193:     Check_Type(klass, T_CLASS);
  194:     rb_add_method(CLASS_OF(klass), ID_ALLOCATOR, 0, NOEX_UNDEF);
  195: }
  196: 
  197: rb_alloc_func_t
  198: rb_get_alloc_func(VALUE klass)
  199: {
  200:     NODE *n;
  201:     Check_Type(klass, T_CLASS);
  202:     n = rb_method_node(CLASS_OF(klass), ID_ALLOCATOR);
  203:     if (!n) return 0;
  204:     if (nd_type(n) != NODE_METHOD) return 0;
  205:     n = n->nd_body;
  206:     if (nd_type(n) != NODE_CFUNC) return 0;
  207:     return (rb_alloc_func_t)n->nd_cfnc;
  208: }
  209: 
  210: static NODE *
  211: search_method(VALUE klass, ID id, VALUE *klassp)
  212: {
  213:     st_data_t body;
  214: 
  215:     if (!klass) {
  216:         return 0;
  217:     }
  218: 
  219:     while (!st_lookup(RCLASS_M_TBL(klass), id, &body)) {
  220:         klass = RCLASS_SUPER(klass);
  221:         if (!klass)
  222:             return 0;
  223:     }
  224: 
  225:     if (klassp) {
  226:         *klassp = klass;
  227:     }
  228: 
  229:     return (NODE *)body;
  230: }
  231: 
  232: /*
  233:  * search method body (NODE_METHOD)
  234:  *   with    : klass and id
  235:  *   without : method cache
  236:  *
  237:  * if you need method node with method cache, use
  238:  * rb_method_node()
  239:  */
  240: NODE *
  241: rb_get_method_body(VALUE klass, ID id, ID *idp)
  242: {
  243:     NODE *volatile fbody, *body;
  244:     NODE *method;
  245: 
  246:     if ((fbody = search_method(klass, id, 0)) == 0 || !fbody->nd_body) {
  247:         /* store empty info in cache */
  248:         struct cache_entry *ent;
  249:         ent = cache + EXPR1(klass, id);
  250:         ent->klass = klass;
  251:         ent->mid = ent->mid0 = id;
  252:         ent->method = 0;
  253:         return 0;
  254:     }
  255: 
  256:     method = fbody->nd_body;
  257: 
  258:     if (ruby_running) {
  259:         /* store in cache */
  260:         struct cache_entry *ent;
  261:         ent = cache + EXPR1(klass, id);
  262:         ent->klass = klass;
  263:         ent->mid = id;
  264:         ent->mid0 = fbody->nd_oid;
  265:         ent->method = body = method;
  266:     }
  267:     else {
  268:         body = method;
  269:     }
  270: 
  271:     if (idp) {
  272:         *idp = fbody->nd_oid;
  273:     }
  274: 
  275:     return body;
  276: }
  277: 
  278: NODE *
  279: rb_method_node(VALUE klass, ID id)
  280: {
  281:     struct cache_entry *ent;
  282: 
  283:     ent = cache + EXPR1(klass, id);
  284:     if (ent->mid == id && ent->klass == klass && ent->method) {
  285:         return ent->method;
  286:     }
  287: 
  288:     return rb_get_method_body(klass, id, 0);
  289: }
  290: 
  291: static void
  292: remove_method(VALUE klass, ID mid)
  293: {
  294:     st_data_t data;
  295:     NODE *body = 0;
  296: 
  297:     if (klass == rb_cObject) {
  298:         rb_secure(4);
  299:     }
  300:     if (rb_safe_level() >= 4 && !OBJ_TAINTED(klass)) {
  301:         rb_raise(rb_eSecurityError, "Insecure: can't remove method");
  302:     }
  303:     if (OBJ_FROZEN(klass))
  304:         rb_error_frozen("class/module");
  305:     if (mid == object_id || mid == __send__ || mid == init) {
  306:         rb_warn("removing `%s' may cause serious problem", rb_id2name(mid));
  307:     }
  308:     if (st_lookup(RCLASS_M_TBL(klass), mid, &data)) {
  309:         body = (NODE *)data;
  310:         if (!body || !body->nd_body) body = 0;
  311:         else {
  312:             st_delete(RCLASS_M_TBL(klass), &mid, &data);
  313:         }
  314:     }
  315:     if (!body) {
  316:         rb_name_error(mid, "method `%s' not defined in %s",
  317:                       rb_id2name(mid), rb_class2name(klass));
  318:     }
  319: 
  320:     if (nd_type(body->nd_body->nd_body) == NODE_CFUNC) {
  321:         rb_vm_check_redefinition_opt_method(body);
  322:     }
  323: 
  324:     rb_clear_cache_for_undef(klass, mid);
  325:     if (FL_TEST(klass, FL_SINGLETON)) {
  326:         rb_funcall(rb_iv_get(klass, "__attached__"), singleton_removed, 1,
  327:                    ID2SYM(mid));
  328:     }
  329:     else {
  330:         rb_funcall(klass, removed, 1, ID2SYM(mid));
  331:     }
  332: }
  333: 
  334: void
  335: rb_remove_method(VALUE klass, const char *name)
  336: {
  337:     remove_method(klass, rb_intern(name));
  338: }
  339: 
  340: /*
  341:  *  call-seq:
  342:  *     remove_method(symbol)   => self
  343:  *
  344:  *  Removes the method identified by _symbol_ from the current
  345:  *  class. For an example, see <code>Module.undef_method</code>.
  346:  */
  347: 
  348: static VALUE
  349: rb_mod_remove_method(int argc, VALUE *argv, VALUE mod)
  350: {
  351:     int i;
  352: 
  353:     for (i = 0; i < argc; i++) {
  354:         remove_method(mod, rb_to_id(argv[i]));
  355:     }
  356:     return mod;
  357: }
  358: 
  359: #undef rb_disable_super
  360: #undef rb_enable_super
  361: 
  362: void
  363: rb_disable_super(VALUE klass, const char *name)
  364: {
  365:     /* obsolete - no use */
  366: }
  367: 
  368: void
  369: rb_enable_super(VALUE klass, const char *name)
  370: {
  371:     rb_warning("rb_enable_super() is obsolete");
  372: }
  373: 
  374: static void
  375: rb_export_method(VALUE klass, ID name, ID noex)
  376: {
  377:     NODE *fbody;
  378:     VALUE origin;
  379: 
  380:     if (klass == rb_cObject) {
  381:         rb_secure(4);
  382:     }
  383:     fbody = search_method(klass, name, &origin);
  384:     if (!fbody && TYPE(klass) == T_MODULE) {
  385:         fbody = search_method(rb_cObject, name, &origin);
  386:     }
  387:     if (!fbody || !fbody->nd_body) {
  388:         rb_print_undef(klass, name, 0);
  389:     }
  390:     if (fbody->nd_body->nd_noex != noex) {
  391:         if (klass == origin) {
  392:             fbody->nd_body->nd_noex = noex;
  393:         }
  394:         else {
  395:             rb_add_method(klass, name, NEW_ZSUPER(), noex);
  396:         }
  397:     }
  398: }
  399: 
  400: int
  401: rb_method_boundp(VALUE klass, ID id, int ex)
  402: {
  403:     NODE *method;
  404: 
  405:     if ((method = rb_method_node(klass, id)) != 0) {
  406:         if (ex && (method->nd_noex & NOEX_PRIVATE)) {
  407:             return Qfalse;
  408:         }
  409:         return Qtrue;
  410:     }
  411:     return Qfalse;
  412: }
  413: 
  414: void
  415: rb_attr(VALUE klass, ID id, int read, int write, int ex)
  416: {
  417:     const char *name;
  418:     ID attriv;
  419:     int noex;
  420: 
  421:     if (!ex) {
  422:         noex = NOEX_PUBLIC;
  423:     }
  424:     else {
  425:         if (SCOPE_TEST(NOEX_PRIVATE)) {
  426:             noex = NOEX_PRIVATE;
  427:             rb_warning((SCOPE_CHECK(NOEX_MODFUNC)) ?
  428:                        "attribute accessor as module_function" :
  429:                        "private attribute?");
  430:         }
  431:         else if (SCOPE_TEST(NOEX_PROTECTED)) {
  432:             noex = NOEX_PROTECTED;
  433:         }
  434:         else {
  435:             noex = NOEX_PUBLIC;
  436:         }
  437:     }
  438: 
  439:     if (!rb_is_local_id(id) && !rb_is_const_id(id)) {
  440:         rb_name_error(id, "invalid attribute name `%s'", rb_id2name(id));
  441:     }
  442:     name = rb_id2name(id);
  443:     if (!name) {
  444:         rb_raise(rb_eArgError, "argument needs to be symbol or string");
  445:     }
  446:     attriv = rb_intern_str(rb_sprintf("@%s", name));
  447:     if (read) {
  448:         rb_add_method(klass, id, NEW_IVAR(attriv), noex);
  449:     }
  450:     if (write) {
  451:         rb_add_method(klass, rb_id_attrset(id), NEW_ATTRSET(attriv), noex);
  452:     }
  453: }
  454: 
  455: void
  456: rb_undef(VALUE klass, ID id)
  457: {
  458:     VALUE origin;
  459:     NODE *body;
  460: 
  461:     if (ruby_cbase() == rb_cObject && klass == rb_cObject) {
  462:         rb_secure(4);
  463:     }
  464:     if (rb_safe_level() >= 4 && !OBJ_TAINTED(klass)) {
  465:         rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'",
  466:                  rb_id2name(id));
  467:     }
  468:     rb_frozen_class_p(klass);
  469:     if (id == object_id || id == __send__ || id == init) {
  470:         rb_warn("undefining `%s' may cause serious problem", rb_id2name(id));
  471:     }
  472:     body = search_method(klass, id, &origin);
  473:     if (!body || !body->nd_body) {
  474:         char *s0 = " class";
  475:         VALUE c = klass;
  476: 
  477:         if (FL_TEST(c, FL_SINGLETON)) {
  478:             VALUE obj = rb_iv_get(klass, "__attached__");
  479: 
  480:             switch (TYPE(obj)) {
  481:               case T_MODULE:
  482:               case T_CLASS:
  483:                 c = obj;
  484:                 s0 = "";
  485:             }
  486:         }
  487:         else if (TYPE(c) == T_MODULE) {
  488:             s0 = " module";
  489:         }
  490:         rb_name_error(id, "undefined method `%s' for%s `%s'",
  491:                       rb_id2name(id), s0, rb_class2name(c));
  492:     }
  493: 
  494:     rb_add_method(klass, id, 0, NOEX_PUBLIC);
  495: 
  496:     if (FL_TEST(klass, FL_SINGLETON)) {
  497:         rb_funcall(rb_iv_get(klass, "__attached__"),
  498:                    singleton_undefined, 1, ID2SYM(id));
  499:     }
  500:     else {
  501:         rb_funcall(klass, undefined, 1, ID2SYM(id));
  502:     }
  503: }
  504: 
  505: /*
  506:  *  call-seq:
  507:  *     undef_method(symbol)    => self
  508:  *
  509:  *  Prevents the current class from responding to calls to the named
  510:  *  method. Contrast this with <code>remove_method</code>, which deletes
  511:  *  the method from the particular class; Ruby will still search
  512:  *  superclasses and mixed-in modules for a possible receiver.
  513:  *
  514:  *     class Parent
  515:  *       def hello
  516:  *         puts "In parent"
  517:  *       end
  518:  *     end
  519:  *     class Child < Parent
  520:  *       def hello
  521:  *         puts "In child"
  522:  *       end
  523:  *     end
  524:  *
  525:  *
  526:  *     c = Child.new
  527:  *     c.hello
  528:  *
  529:  *
  530:  *     class Child
  531:  *       remove_method :hello  # remove from child, still in parent
  532:  *     end
  533:  *     c.hello
  534:  *
  535:  *
  536:  *     class Child
  537:  *       undef_method :hello   # prevent any calls to 'hello'
  538:  *     end
  539:  *     c.hello
  540:  *
  541:  *  <em>produces:</em>
  542:  *
  543:  *     In child
  544:  *     In parent
  545:  *     prog.rb:23: undefined method `hello' for #<Child:0x401b3bb4> (NoMethodError)
  546:  */
  547: 
  548: static VALUE
  549: rb_mod_undef_method(int argc, VALUE *argv, VALUE mod)
  550: {
  551:     int i;
  552:     for (i = 0; i < argc; i++) {
  553:         rb_undef(mod, rb_to_id(argv[i]));
  554:     }
  555:     return mod;
  556: }
  557: 
  558: void
  559: rb_alias(VALUE klass, ID name, ID def)
  560: {
  561:     NODE *orig_fbody, *node;
  562:     VALUE singleton = 0;
  563:     st_data_t data;
  564: 
  565:     rb_frozen_class_p(klass);
  566:     if (klass == rb_cObject) {
  567:         rb_secure(4);
  568:     }
  569:     orig_fbody = search_method(klass, def, 0);
  570:     if (!orig_fbody || !orig_fbody->nd_body) {
  571:         if (TYPE(klass) == T_MODULE) {
  572:             orig_fbody = search_method(rb_cObject, def, 0);
  573:         }
  574:     }
  575:     if (!orig_fbody || !orig_fbody->nd_body) {
  576:         rb_print_undef(klass, def, 0);
  577:     }
  578:     if (FL_TEST(klass, FL_SINGLETON)) {
  579:         singleton = rb_iv_get(klass, "__attached__");
  580:     }
  581: 
  582:     orig_fbody->nd_cnt++;
  583: 
  584:     if (st_lookup(RCLASS_M_TBL(klass), name, &data)) {
  585:         node = (NODE *)data;
  586:         if (node) {
  587:             if (RTEST(ruby_verbose) && node->nd_cnt == 0 && node->nd_body) {
  588:                 rb_warning("discarding old %s", rb_id2name(name));
  589:             }
  590:             if (nd_type(node->nd_body->nd_body) == NODE_CFUNC) {
  591:                 rb_vm_check_redefinition_opt_method(node);
  592:             }
  593:         }
  594:     }
  595: 
  596:     st_insert(RCLASS_M_TBL(klass), name,
  597:               (st_data_t) NEW_FBODY(
  598:                   NEW_METHOD(orig_fbody->nd_body->nd_body,
  599:                              orig_fbody->nd_body->nd_clss,
  600:                              NOEX_WITH_SAFE(orig_fbody->nd_body->nd_noex)), def));
  601: 
  602:     rb_clear_cache_by_id(name);
  603: 
  604:     if (!ruby_running) return;
  605: 
  606:     if (singleton) {
  607:         rb_funcall(singleton, singleton_added, 1, ID2SYM(name));
  608:     }
  609:     else {
  610:         rb_funcall(klass, added, 1, ID2SYM(name));
  611:     }
  612: }
  613: 
  614: /*
  615:  *  call-seq:
  616:  *     alias_method(new_name, old_name)   => self
  617:  *
  618:  *  Makes <i>new_name</i> a new copy of the method <i>old_name<