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

ruby/1.9.0/blockinlining.c

    1: /**********************************************************************
    2: 
    3:   blockinlining.c -
    4: 
    5:   $Author: ko1 $
    6:   $Date: 2007-11-14 07:13:04 +0900 (Wed, 14 Nov 2007) $
    7: 
    8:   Copyright (C) 2004-2007 Koichi Sasada
    9: 
   10: **********************************************************************/
   11: 
   12: #include "ruby/ruby.h"
   13: #include "ruby/node.h"
   14: #include "vm_core.h"
   15: 
   16: static VALUE
   17: iseq_special_block(rb_iseq_t *iseq, void *builder)
   18: {
   19: #if OPT_BLOCKINLINING
   20:     VALUE parent = Qfalse;
   21:     VALUE iseqval;
   22: 
   23:     if (iseq->argc > 1 || iseq->arg_simple == 0) {
   24:         /* argument check */
   25:         return 0;
   26:     }
   27: 
   28:     if (iseq->cached_special_block_builder) {
   29:         if (iseq->cached_special_block_builder == builder) {
   30:             return iseq->cached_special_block;
   31:         }
   32:         else {
   33:             return 0;
   34:         }
   35:     }
   36:     else {
   37:         iseq->cached_special_block_builder = (void *)1;
   38:     }
   39:     
   40:     if (iseq->parent_iseq) {
   41:         parent = iseq->parent_iseq->self;
   42:     }
   43:     iseqval = rb_iseq_new_with_bopt(iseq->node, iseq->name, iseq->filename,
   44:                                       parent, iseq->type,
   45:                                       GC_GUARDED_PTR(builder));
   46:     if (0) {
   47:         printf("%s\n", RSTRING_PTR(ruby_iseq_disasm(iseqval)));
   48:     }
   49:     iseq->cached_special_block = iseqval;
   50:     iseq->cached_special_block_builder = builder;
   51:     return iseqval;
   52: #else
   53:     return 0;
   54: #endif
   55: }
   56: 
   57: static NODE *
   58: new_block(NODE * head, NODE * tail)
   59: {
   60:     head = NEW_BLOCK(head);
   61:     tail = NEW_BLOCK(tail);
   62:     head->nd_next = tail;
   63:     return head;
   64: }
   65: 
   66: static NODE *
   67: new_ary(NODE * head, NODE * tail)
   68: {
   69:     head = NEW_ARRAY(head);
   70:     head->nd_next = tail;
   71:     return head;
   72: }
   73: 
   74: static NODE *
   75: new_assign(NODE * lnode, NODE * rhs)
   76: {
   77:     switch (nd_type(lnode)) {
   78:       case NODE_LASGN:{
   79:           return NEW_NODE(NODE_LASGN, lnode->nd_vid, rhs, lnode->nd_cnt);
   80:           /* NEW_LASGN(lnode->nd_vid, rhs); */
   81:       }
   82:       case NODE_GASGN:{
   83:           return NEW_GASGN(lnode->nd_vid, rhs);
   84:       }
   85:       case NODE_DASGN:{
   86:           return NEW_DASGN(lnode->nd_vid, rhs);
   87:       }
   88:       case NODE_ATTRASGN:{
   89:           NODE *args = 0;
   90:           if (lnode->nd_args) {
   91:               args = NEW_ARRAY(lnode->nd_args->nd_head);
   92:               args->nd_next = NEW_ARRAY(rhs);
   93:               args->nd_alen = 2;
   94:           }
   95:           else {
   96:               args = NEW_ARRAY(rhs);
   97:           }
   98: 
   99:           return NEW_ATTRASGN(lnode->nd_recv,
  100:                               lnode->nd_mid,
  101:                               args);
  102:       }
  103:       default:
  104:         rb_bug("unimplemented (block inlining): %s", ruby_node_name(nd_type(lnode)));
  105:     }
  106:     return 0;
  107: }
  108: 
  109: static NODE *
  110: build_Integer_times_node(rb_iseq_t *iseq, NODE * node, NODE * lnode,
  111:                          VALUE param_vars, VALUE local_vars)
  112: {
  113:     /* Special Block for Integer#times
  114:        {|e, _self|
  115:        _e = e
  116:        while(e < _self)
  117:        e = _e
  118:        redo_point:
  119:        BODY
  120:        next_point:
  121:        _e = _e.succ
  122:        end
  123:        }
  124: 
  125:        {|e, _self|
  126:        while(e < _self)
  127:        BODY
  128:        next_point:
  129:        e = e.succ
  130:        end
  131:        }
  132:      */
  133:     ID _self = rb_intern("#_self");
  134:     if (iseq->argc == 0) {
  135:         ID e = rb_intern("#e");
  136:         rb_ary_push(param_vars, ID2SYM(e));
  137:         rb_ary_push(param_vars, ID2SYM(_self));
  138:         iseq->argc += 2;
  139: 
  140:         node =
  141:             NEW_WHILE(NEW_CALL
  142:                       (NEW_DVAR(e), idLT, new_ary(NEW_DVAR(_self), 0)),
  143:                       new_block(NEW_OPTBLOCK(node),
  144:                                 NEW_DASGN(e,
  145:                                           NEW_CALL(NEW_DVAR(e), idSucc, 0))),
  146:                       Qundef);
  147:     }
  148:     else {
  149:         ID _e = rb_intern("#_e");
  150:         ID e = SYM2ID(rb_ary_entry(param_vars, 0));
  151:         NODE *assign;
  152: 
  153:         rb_ary_push(param_vars, ID2SYM(_self));
  154:         rb_ary_push(local_vars, ID2SYM(_e));
  155:         iseq->argc++;
  156: 
  157:         if (nd_type(lnode) == NODE_DASGN_CURR) {
  158:             assign = NEW_DASGN(e, NEW_DVAR(_e));
  159:         }
  160:         else {
  161:             assign = new_assign(lnode, NEW_DVAR(_e));
  162:         }
  163: 
  164:         node =
  165:             new_block(NEW_DASGN(_e, NEW_DVAR(e)),
  166:                       NEW_WHILE(NEW_CALL
  167:                                 (NEW_DVAR(_e), idLT,
  168:                                  new_ary(NEW_DVAR(_self), 0)),
  169:                                 new_block(assign,
  170:                                           new_block(NEW_OPTBLOCK(node),
  171:                                                     NEW_DASGN(_e,
  172:                                                               NEW_CALL
  173:                                                               (NEW_DVAR(_e),
  174:                                                                idSucc, 0)))),
  175:                                 Qundef));
  176:     }
  177:     return node;
  178: }
  179: 
  180: VALUE
  181: invoke_Integer_times_special_block(VALUE num)
  182: {
  183:     rb_thread_t *th = GET_THREAD();
  184:     rb_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]);
  185: 
  186:     if (orig_block && BUILTIN_TYPE(orig_block->iseq) != T_NODE) {
  187:         VALUE tsiseqval = iseq_special_block(orig_block->iseq,
  188:                                              build_Integer_times_node);
  189:         rb_iseq_t *tsiseq;
  190:         VALUE argv[2], val;
  191: 
  192:         if (tsiseqval) {
  193:             rb_block_t block = *orig_block;
  194:             GetISeqPtr(tsiseqval, tsiseq);
  195:             block.iseq = tsiseq;
  196:             th->cfp->lfp[0] = GC_GUARDED_PTR(&block);
  197:             argv[0] = INT2FIX(0);
  198:             argv[1] = num;
  199:             val = vm_yield(th, 2, argv);
  200:             if (val == Qundef) {
  201:                 return num;
  202:             }
  203:             else {
  204:                 return val;
  205:             }
  206:         }
  207:     }
  208:     return Qundef;
  209: }
  210: 
  211: static NODE *
  212: build_Range_each_node(rb_iseq_t *iseq, NODE * node, NODE * lnode,
  213:                       VALUE param_vars, VALUE local_vars, ID mid)
  214: {
  215:     /* Special Block for Range#each
  216:        {|e, _last|
  217:        _e = e
  218:        while _e < _last
  219:        e = _e
  220:        next_point:
  221:        BODY
  222:        redo_point:
  223:        _e = _e.succ
  224:        end
  225:        }
  226:        {|e, _last|
  227:        while e < _last
  228:        BODY
  229:        redo_point:
  230:        e = e.succ
  231:        end
  232:        }
  233:      */
  234:     ID _last = rb_intern("#_last");
  235:     if (iseq->argc == 0) {
  236:         ID e = rb_intern("#e");
  237:         rb_ary_push(param_vars, ID2SYM(e));
  238:         rb_ary_push(param_vars, ID2SYM(_last));
  239:         iseq->argc += 2;
  240: 
  241:         node =
  242:             NEW_WHILE(NEW_CALL(NEW_DVAR(e), mid, new_ary(NEW_DVAR(_last), 0)),
  243:                       new_block(NEW_OPTBLOCK(node),
  244:                                 NEW_DASGN(e,
  245:                                           NEW_CALL(NEW_DVAR(e), idSucc, 0))),
  246:                       Qundef);
  247:     }
  248:     else {
  249:         ID _e = rb_intern("#_e");
  250:         ID e = SYM2ID(rb_ary_entry(param_vars, 0));
  251:         NODE *assign;
  252: 
  253:         rb_ary_push(param_vars, ID2SYM(_last));
  254:         rb_ary_push(local_vars, ID2SYM(_e));
  255:         iseq->argc++;
  256: 
  257:         if (nd_type(lnode) == NODE_DASGN_CURR) {
  258:             assign = NEW_DASGN(e, NEW_DVAR(_e));
  259:         }
  260:         else {
  261:             assign = new_assign(lnode, NEW_DVAR(_e));
  262:         }
  263: 
  264:         node =
  265:             new_block(NEW_DASGN(_e, NEW_DVAR(e)),
  266:                       NEW_WHILE(NEW_CALL
  267:                                 (NEW_DVAR(_e), mid,
  268:                                  new_ary(NEW_DVAR(_last), 0)),
  269:                                 new_block(assign,
  270:                                           new_block(NEW_OPTBLOCK(node),
  271:                                                     NEW_DASGN(_e,
  272:                                                               NEW_CALL
  273:                                                               (NEW_DVAR(_e),
  274:                                                                idSucc, 0)))),
  275:                                 Qundef));
  276:     }
  277:     return node;
  278: }
  279: 
  280: static NODE *
  281: build_Range_each_node_LE(rb_iseq_t *iseq, NODE * node, NODE * lnode,
  282:                          VALUE param_vars, VALUE local_vars)
  283: {
  284:     return build_Range_each_node(iseq, node, lnode,
  285:                                  param_vars, local_vars, idLE);
  286: }
  287: 
  288: static NODE *
  289: build_Range_each_node_LT(rb_iseq_t *iseq, NODE * node, NODE * lnode,
  290:                          VALUE param_vars, VALUE local_vars)
  291: {
  292:     return build_Range_each_node(iseq, node, lnode,
  293:                                  param_vars, local_vars, idLT);
  294: }
  295: 
  296: VALUE
  297: invoke_Range_each_special_block(VALUE range,
  298:                                 VALUE beg, VALUE end, int excl)
  299: {
  300:     rb_thread_t *th = GET_THREAD();
  301:     rb_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]);
  302: 
  303:     if (BUILTIN_TYPE(orig_block->iseq) != T_NODE) {
  304:         void *builder =
  305:             excl ? build_Range_each_node_LT : build_Range_each_node_LE;
  306:         VALUE tsiseqval = iseq_special_block(orig_block->iseq, builder);
  307:         rb_iseq_t *tsiseq;
  308:         VALUE argv[2];
  309: 
  310:         if (tsiseqval) {
  311:             VALUE val;
  312:             rb_block_t block = *orig_block;
  313:             GetISeqPtr(tsiseqval, tsiseq);
  314:             block.iseq = tsiseq;
  315:             th->cfp->lfp[0] = GC_GUARDED_PTR(&block);
  316:             argv[0] = beg;
  317:             argv[1] = end;
  318:             val = vm_yield(th, 2, argv);
  319:             if (val == Qundef) {
  320:                 return range;
  321:             }
  322:             else {
  323:                 return val;
  324:             }
  325:         }
  326:     }
  327:     return Qundef;
  328: }
  329: 
  330: 
  331: static NODE *
  332: build_Array_each_node(rb_iseq_t *iseq, NODE * node, NODE * lnode,
  333:                       VALUE param_vars, VALUE local_vars)
  334: {
  335:     /* Special block for Array#each
  336:        ary.each{|e|
  337:        BODY
  338:        }
  339:        =>
  340:        {|e, _self|
  341:        _i = 0
  342:        while _i < _self.length
  343:        e = _self[_i]
  344:        redo_point:
  345:        BODY
  346:        next_point:
  347:        _i = _i.succ
  348:        end
  349:        }
  350: 
  351:        ary.each{
  352:        BODY
  353:        }
  354:        =>
  355:        {|_i, _self|
  356:        _i = 0
  357:        while _i < _self.length
  358:        redo_point:
  359:        BODY
  360:        next_point:
  361:        _i = _i.succ
  362:        end
  363:        }
  364:      */
  365: 
  366:     ID _self = rb_intern("#_self");
  367:     ID _i = rb_intern("#_i");
  368: 
  369:     if (iseq->argc == 0) {
  370:         ID _e = rb_intern("#_e");
  371:         rb_ary_push(param_vars, ID2SYM(_e));
  372:         rb_ary_push(param_vars, ID2SYM(_self));
  373:         iseq->argc += 2;
  374:         rb_ary_push(local_vars, ID2SYM(_i));
  375: 
  376:         node =
  377:             new_block(NEW_DASGN(_i, NEW_LIT(INT2FIX(0))),
  378:                       NEW_WHILE(NEW_CALL(NEW_DVAR(_i), idLT,
  379:                                          new_ary(NEW_CALL
  380:                                                  (NEW_DVAR(_self), idLength,
  381:                                                   0), 0)),
  382:                                 new_block(NEW_OPTBLOCK(node),
  383:                                           NEW_DASGN(_i,
  384:                                                     NEW_CALL(NEW_DVAR(_i),
  385:                                                              idSucc, 0))),
  386:                                 Qundef));
  387:     }
  388:     else {
  389:         ID e = SYM2ID(rb_ary_entry(param_vars, 0));
  390:         NODE *assign;
  391: 
  392:         rb_ary_push(param_vars, ID2SYM(_self));
  393:         iseq->argc++;
  394:         rb_ary_push(local_vars, ID2SYM(_i));
  395: 
  396:         if (nd_type(lnode) == NODE_DASGN_CURR) {
  397:             assign = NEW_DASGN(e,
  398:                                NEW_CALL(NEW_DVAR(_self), idAREF,
  399:                                         new_ary(NEW_DVAR(_i), 0)));
  400:         }
  401:         else {
  402:             assign = new_assign(lnode,
  403:                                 NEW_CALL(NEW_DVAR(_self), idAREF,
  404:                                          new_ary(NEW_DVAR(_i), 0)));
  405:         }
  406: 
  407:         node =
  408:             new_block(NEW_DASGN(_i, NEW_LIT(INT2FIX(0))),
  409:                       NEW_WHILE(NEW_CALL(NEW_DVAR(_i), idLT,
  410:                                          new_ary(NEW_CALL
  411:                                                  (NEW_DVAR(_self), idLength,
  412:                                                   0), 0)), new_block(assign,
  413:                                                                      new_block
  414:                                                                      (NEW_OPTBLOCK
  415:                                                                       (node),
  416:                                                                       NEW_DASGN
  417:                                                                       (_i,
  418:                                                                        NEW_CALL
  419:                                                                        (NEW_DVAR
  420:                                                                         (_i),
  421:                                                                         idSucc,
  422:                                                                         0)))),
  423:                                 Qundef));
  424:     }
  425:     return node;
  426: }
  427: 
  428: VALUE
  429: invoke_Array_each_special_block(VALUE ary)
  430: {
  431:     rb_thread_t *th = GET_THREAD();
  432:     rb_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]);
  433: 
  434:     if (BUILTIN_TYPE(orig_block->iseq) != T_NODE) {
  435:         VALUE tsiseqval = iseq_special_block(orig_block->iseq,
  436:                                              build_Array_each_node);
  437:         rb_iseq_t *tsiseq;
  438:         VALUE argv[2];
  439: 
  440:         if (tsiseqval) {
  441:             VALUE val;
  442:             rb_block_t block = *orig_block;
  443:             GetISeqPtr(tsiseqval, tsiseq);
  444:             block.iseq = tsiseq;
  445:             th->cfp->lfp[0] = GC_GUARDED_PTR(&block);
  446:             argv[0] = 0;
  447:             argv[1] = ary;
  448:             val = vm_yield(th, 2, argv);
  449:             if (val == Qundef) {
  450:                 return ary;
  451:             }
  452:             else {
  453:                 return val;
  454:             }
  455:         }
  456:     }
  457:     return Qundef;
  458: }
Syntax (Markdown)