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

ruby/1.9.0/iseq.c

    1: /**********************************************************************
    2: 
    3:   iseq.c -
    4: 
    5:   $Author: ko1 $
    6:   $Date: 2007-12-25 18:43:23 +0900 (Tue, 25 Dec 2007) $
    7:   created at: 2006-07-11(Tue) 09:00:03 +0900
    8: 
    9:   Copyright (C) 2006 Koichi Sasada
   10: 
   11: **********************************************************************/
   12: 
   13: #include "ruby/ruby.h"
   14: #include "ruby/node.h"
   15: 
   16: /* #define MARK_FREE_DEBUG 1 */
   17: #include "gc.h"
   18: #include "vm_core.h"
   19: 
   20: #include "insns.inc"
   21: #include "insns_info.inc"
   22: 
   23: /* compile.c */
   24: void iseq_compile(VALUE self, NODE *node);
   25: int iseq_translate_threaded_code(rb_iseq_t *iseq);
   26: 
   27: VALUE rb_cISeq;
   28: 
   29: static void
   30: compile_data_free(struct iseq_compile_data *compile_data)
   31: {
   32:     if (compile_data) {
   33:         struct iseq_compile_data_storage *cur, *next;
   34:         cur = compile_data->storage_head;
   35:         while (cur) {
   36:             next = cur->next;
   37:             ruby_xfree(cur);
   38:             cur = next;
   39:         }
   40:         ruby_xfree(compile_data);
   41:     }
   42: }
   43: 
   44: static void
   45: iseq_free(void *ptr)
   46: {
   47:     rb_iseq_t *iseq;
   48:     RUBY_FREE_ENTER("iseq");
   49: 
   50:     if (ptr) {
   51:         iseq = ptr;
   52:         /* It's possible that strings are freed
   53:          * GC_INFO("%s @ %s\n", RSTRING_PTR(iseq->name),
   54:          *                      RSTRING_PTR(iseq->filename));
   55:          */
   56:         if (iseq->iseq != iseq->iseq_encoded) {
   57:             RUBY_FREE_UNLESS_NULL(iseq->iseq_encoded);
   58:         }
   59: 
   60:         RUBY_FREE_UNLESS_NULL(iseq->iseq);
   61:         RUBY_FREE_UNLESS_NULL(iseq->insn_info_table);
   62:         RUBY_FREE_UNLESS_NULL(iseq->local_table);
   63:         RUBY_FREE_UNLESS_NULL(iseq->catch_table);
   64:         RUBY_FREE_UNLESS_NULL(iseq->arg_opt_table);
   65:         compile_data_free(iseq->compile_data);
   66:         ruby_xfree(ptr);
   67:     }
   68:     RUBY_FREE_LEAVE("iseq");
   69: }
   70: 
   71: static void
   72: iseq_mark(void *ptr)
   73: {
   74:     rb_iseq_t *iseq;
   75:     RUBY_MARK_ENTER("iseq");
   76: 
   77:     if (ptr) {
   78:         iseq = ptr;
   79:         RUBY_GC_INFO("%s @ %s\n", RSTRING_PTR(iseq->name), RSTRING_PTR(iseq->filename));
   80:         RUBY_MARK_UNLESS_NULL(iseq->mark_ary);
   81:         RUBY_MARK_UNLESS_NULL(iseq->name);
   82:         RUBY_MARK_UNLESS_NULL(iseq->filename);
   83:         RUBY_MARK_UNLESS_NULL((VALUE)iseq->cref_stack);
   84:         RUBY_MARK_UNLESS_NULL(iseq->klass);
   85: /*      RUBY_MARK_UNLESS_NULL((VALUE)iseq->node); */
   86: /*      RUBY_MARK_UNLESS_NULL(iseq->cached_special_block); */
   87: 
   88:         if (iseq->compile_data != 0) {
   89:             RUBY_MARK_UNLESS_NULL(iseq->compile_data->mark_ary);
   90:             RUBY_MARK_UNLESS_NULL(iseq->compile_data->err_info);
   91:             RUBY_MARK_UNLESS_NULL(iseq->compile_data->catch_table_ary);
   92:         }
   93:     }
   94:     RUBY_MARK_LEAVE("iseq");
   95: }
   96: 
   97: static VALUE
   98: iseq_alloc(VALUE klass)
   99: {
  100:     VALUE volatile obj;
  101:     rb_iseq_t *iseq;
  102: 
  103:     obj = Data_Make_Struct(klass, rb_iseq_t, iseq_mark, iseq_free, iseq);
  104:     MEMZERO(iseq, rb_iseq_t, 1);
  105:     return obj;
  106: }
  107: 
  108: static void
  109: set_relation(rb_iseq_t *iseq, const VALUE parent)
  110: {
  111:     const int type = iseq->type;
  112:     rb_thread_t *th = GET_THREAD();
  113: 
  114:     /* set class nest stack */
  115:     if (type == ISEQ_TYPE_TOP) {
  116:         /* toplevel is private */
  117:         iseq->cref_stack = NEW_BLOCK(th->top_wrapper ? th->top_wrapper : rb_cObject);
  118:         iseq->cref_stack->nd_file = 0;
  119:         iseq->cref_stack->nd_visi = NOEX_PRIVATE;
  120:     }
  121:     else if (type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) {
  122:         iseq->cref_stack = NEW_BLOCK(0); /* place holder */
  123:         iseq->cref_stack->nd_file = 0;
  124:     }
  125:     else if (RTEST(parent)) {
  126:         rb_iseq_t *piseq;
  127:         GetISeqPtr(parent, piseq);
  128:         iseq->cref_stack = piseq->cref_stack;
  129:     }
  130: 
  131:     if (type == ISEQ_TYPE_TOP ||
  132:         type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) {
  133:         iseq->local_iseq = iseq;
  134:     }
  135:     else if (RTEST(parent)) {
  136:         rb_iseq_t *piseq;
  137:         GetISeqPtr(parent, piseq);
  138:         iseq->local_iseq = piseq->local_iseq;
  139:     }
  140: 
  141:     if (RTEST(parent)) {
  142:         rb_iseq_t *piseq;
  143:         GetISeqPtr(parent, piseq);
  144:         iseq->parent_iseq = piseq;
  145:     }
  146: }
  147: 
  148: static VALUE
  149: prepare_iseq_build(rb_iseq_t *iseq,
  150:                    VALUE name, VALUE filename,
  151:                    VALUE parent, VALUE type, VALUE block_opt,
  152:                    const rb_compile_option_t *option)
  153: {
  154:     OBJ_FREEZE(name);
  155:     OBJ_FREEZE(filename);
  156: 
  157:     iseq->name = name;
  158:     iseq->filename = filename;
  159:     iseq->defined_method_id = 0;
  160:     iseq->mark_ary = rb_ary_new();
  161:     RBASIC(iseq->mark_ary)->klass = 0;
  162: 
  163:     iseq->type = type;
  164:     iseq->arg_rest = -1;
  165:     iseq->arg_block = -1;
  166:     iseq->klass = 0;
  167: 
  168:     /*
  169:      * iseq->special_block_builder = GC_GUARDED_PTR_REF(block_opt);
  170:      * iseq->cached_special_block_builder = 0;
  171:      * iseq->cached_special_block = 0;
  172:      */
  173: 
  174:     iseq->compile_data = ALLOC(struct iseq_compile_data);
  175:     MEMZERO(iseq->compile_data, struct iseq_compile_data, 1);
  176:     iseq->compile_data->mark_ary = rb_ary_new();
  177:     RBASIC(iseq->compile_data->mark_ary)->klass = 0;
  178: 
  179:     iseq->compile_data->storage_head = iseq->compile_data->storage_current =
  180:       (struct iseq_compile_data_storage *)
  181:         ALLOC_N(char, INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE +
  182:                 sizeof(struct iseq_compile_data_storage));
  183: 
  184:     iseq->compile_data->catch_table_ary = rb_ary_new();
  185:     iseq->compile_data->storage_head->pos = 0;
  186:     iseq->compile_data->storage_head->next = 0;
  187:     iseq->compile_data->storage_head->size =
  188:       INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE;
  189:     iseq->compile_data->storage_head->buff =
  190:       (char *)(&iseq->compile_data->storage_head->buff + 1);
  191:     iseq->compile_data->option = option;
  192: 
  193:     set_relation(iseq, parent);
  194: 
  195:     return Qtrue;
  196: }
  197: 
  198: static VALUE
  199: cleanup_iseq_build(rb_iseq_t *iseq)
  200: {
  201:     struct iseq_compile_data *data = iseq->compile_data;
  202:     VALUE err = data->err_info;
  203:     iseq->compile_data = 0;
  204:     compile_data_free(data);
  205: 
  206:     if (RTEST(err)) {
  207:         rb_funcall2(err, rb_intern("set_backtrace"), 1, &iseq->filename);
  208:         rb_exc_raise(err);
  209:     }
  210:     return Qtrue;
  211: }
  212: 
  213: static rb_compile_option_t COMPILE_OPTION_DEFAULT = {
  214:     OPT_INLINE_CONST_CACHE, /* int inline_const_cache; */
  215:     OPT_PEEPHOLE_OPTIMIZATION, /* int peephole_optimization; */
  216:     OPT_TAILCALL_OPTIMIZATION, /* int tailcall_optimization */
  217:     OPT_SPECIALISED_INSTRUCTION, /* int specialized_instruction; */
  218:     OPT_OPERANDS_UNIFICATION, /* int operands_unification; */
  219:     OPT_INSTRUCTIONS_UNIFICATION, /* int instructions_unification; */
  220:     OPT_STACK_CACHING, /* int stack_caching; */
  221:     OPT_TRACE_INSTRUCTION, /* int trace_instruction */
  222: };
  223: static const rb_compile_option_t COMPILE_OPTION_FALSE;
  224: 
  225: static void
  226: make_compile_option(rb_compile_option_t *option, VALUE opt)
  227: {
  228:     if (opt == Qnil) {
  229:         *option = COMPILE_OPTION_DEFAULT;
  230:     }
  231:     else if (opt == Qfalse) {
  232:         *option = COMPILE_OPTION_FALSE;
  233:     }
  234:     else if (opt == Qtrue) {
  235:         memset(option, 1, sizeof(rb_compile_option_t));
  236:     }
  237:     else if (CLASS_OF(opt) == rb_cHash) {
  238:         *option = COMPILE_OPTION_DEFAULT;
  239: 
  240: #define SET_COMPILE_OPTION(o, h, mem) \
  241:   { VALUE flag = rb_hash_aref(h, ID2SYM(rb_intern(#mem))); \
  242:       if (flag == Qtrue)  { o->mem = 1; } \
  243:       else if (flag == Qfalse)  { o->mem = 0; } \
  244:   }
  245:         SET_COMPILE_OPTION(option, opt, inline_const_cache);
  246:         SET_COMPILE_OPTION(option, opt, peephole_optimization);
  247:         SET_COMPILE_OPTION(option, opt, tailcall_optimization);
  248:         SET_COMPILE_OPTION(option, opt, specialized_instruction);
  249:         SET_COMPILE_OPTION(option, opt, operands_unification);
  250:         SET_COMPILE_OPTION(option, opt, instructions_unification);
  251:         SET_COMPILE_OPTION(option, opt, stack_caching);
  252:         SET_COMPILE_OPTION(option, opt, trace_instruction);
  253: #undef SET_COMPILE_OPTION
  254:     }
  255:     else {
  256:         rb_raise(rb_eTypeError, "Compile option must be Hash/true/false/nil");
  257:     }
  258: }
  259: 
  260: static VALUE
  261: make_compile_option_value(rb_compile_option_t *option)
  262: {
  263:     VALUE opt = rb_hash_new();
  264: #define SET_COMPILE_OPTION(o, h, mem) \
  265:   rb_hash_aset(h, ID2SYM(rb_intern(#mem)), o->mem ? Qtrue : Qfalse)
  266:     {
  267:         SET_COMPILE_OPTION(option, opt, inline_const_cache);
  268:         SET_COMPILE_OPTION(option, opt, peephole_optimization);
  269:         SET_COMPILE_OPTION(option, opt, tailcall_optimization);
  270:         SET_COMPILE_OPTION(option, opt, specialized_instruction);
  271:         SET_COMPILE_OPTION(option, opt, operands_unification);
  272:         SET_COMPILE_OPTION(option, opt, instructions_unification);
  273:         SET_COMPILE_OPTION(option, opt, stack_caching);
  274:     }
  275: #undef SET_COMPILE_OPTION
  276:     return opt;
  277: }
  278: 
  279: VALUE
  280: rb_iseq_new(NODE *node, VALUE name, VALUE filename,
  281:               VALUE parent, VALUE type)
  282: {
  283:     return rb_iseq_new_with_opt(node, name, filename, parent, type,
  284:                                 &COMPILE_OPTION_DEFAULT);
  285: }
  286: 
  287: static VALUE
  288: rb_iseq_new_with_bopt_and_opt(NODE *node, VALUE name, VALUE filename,
  289:                                 VALUE parent, VALUE type, VALUE bopt,
  290:                                 const rb_compile_option_t *option)
  291: {
  292:     rb_iseq_t *iseq;
  293:     VALUE self = iseq_alloc(rb_cISeq);
  294: 
  295:     GetISeqPtr(self, iseq);
  296:     iseq->self = self;
  297: 
  298:     prepare_iseq_build(iseq, name, filename, parent, type, bopt, option);
  299:     iseq_compile(self, node);
  300:     cleanup_iseq_build(iseq);
  301:     return self;
  302: }
  303: 
  304: VALUE
  305: rb_iseq_new_with_opt(NODE *node, VALUE name, VALUE filename,
  306:                      VALUE parent, VALUE type,
  307:                      const rb_compile_option_t *option)
  308: {
  309:     return rb_iseq_new_with_bopt_and_opt(node, name, filename, parent, type,
  310:                                            Qfalse, option);
  311: }
  312: 
  313: VALUE
  314: rb_iseq_new_with_bopt(NODE *node, VALUE name, VALUE filename,
  315:                        VALUE parent, VALUE type, VALUE bopt)
  316: {
  317:     return rb_iseq_new_with_bopt_and_opt(node, name, filename, parent, type,
  318:                                            bopt, &COMPILE_OPTION_DEFAULT);
  319: }
  320: 
  321: VALUE iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args,
  322:                           VALUE exception, VALUE body);
  323: 
  324: #define CHECK_ARRAY(v)   rb_convert_type(v, T_ARRAY, "Array", "to_ary")
  325: #define CHECK_STRING(v)  rb_convert_type(v, T_STRING, "String", "to_str")
  326: #define CHECK_SYMBOL(v)  rb_convert_type(v, T_SYMBOL, "Symbol", "to_sym")
  327: #define CHECK_INTEGER(v) (NUM2LONG(v), v)
  328: VALUE
  329: iseq_load(VALUE self, VALUE data, VALUE parent, VALUE opt)
  330: {
  331:     VALUE iseqval = iseq_alloc(rb_cISeq);
  332: 
  333:     VALUE magic, version1, version2, format_type, misc;
  334:     VALUE name, filename, line;
  335:     VALUE type, body, locals, args, exception;
  336: 
  337:     VALUE iseq_type;
  338:     struct st_table *type_map = 0;
  339:     rb_iseq_t *iseq;
  340:     rb_compile_option_t option;
  341: 
  342:     /* [magic, major_version, minor_version, format_type, misc,
  343:      *  name, filename, line,
  344:      *  type, locals, args, exception_table, body]
  345:      */
  346: 
  347:     data        = CHECK_ARRAY(data);
  348: 
  349:     magic       = CHECK_STRING(rb_ary_entry(data, 0));
  350:     version1    = CHECK_INTEGER(rb_ary_entry(data, 1));
  351:     version2    = CHECK_INTEGER(rb_ary_entry(data, 2));
  352:     format_type = CHECK_INTEGER(rb_ary_entry(data, 3));
  353:     misc        = rb_ary_entry(data, 4); /* TODO */
  354: 
  355:     name        = CHECK_STRING(rb_ary_entry(data, 5));
  356:     filename    = CHECK_STRING(rb_ary_entry(data, 6));
  357:     line        = CHECK_ARRAY(rb_ary_entry(data, 7));
  358: 
  359:     type        = CHECK_SYMBOL(rb_ary_entry(data, 8));
  360:     locals      = CHECK_ARRAY(rb_ary_entry(data, 9));
  361: 
  362:     args        = rb_ary_entry(data, 10);
  363:     if (FIXNUM_P(args) || (args = CHECK_ARRAY(args))) {
  364:         /* */
  365:     }
  366: 
  367:     exception   = CHECK_ARRAY(rb_ary_entry(data, 11));
  368:     body        = CHECK_ARRAY(rb_ary_entry(data, 12));
  369: 
  370:     GetISeqPtr(iseqval, iseq);
  371:     iseq->self = iseqval;
  372: 
  373:     if (type_map == 0) {
  374:         type_map = st_init_numtable();
  375:         st_insert(type_map, ID2SYM(rb_intern("top")), ISEQ_TYPE_TOP);
  376:         st_insert(type_map, ID2SYM(rb_intern("method")), ISEQ_TYPE_METHOD);
  377:         st_insert(type_map, ID2SYM(rb_intern("block")), ISEQ_TYPE_BLOCK);
  378:         st_insert(type_map, ID2SYM(rb_intern("class")), ISEQ_TYPE_CLASS);
  379:         st_insert(type_map, ID2SYM(rb_intern("rescue")), ISEQ_TYPE_RESCUE);
  380:         st_insert(type_map, ID2SYM(rb_intern("ensure")), ISEQ_TYPE_ENSURE);
  381:         st_insert(type_map, ID2SYM(rb_intern("eval")), ISEQ_TYPE_EVAL);
  382:     }
  383: 
  384:     if (st_lookup(type_map, type, &iseq_type) == 0) {
  385:         const char *typename = rb_id2name(type);
  386:         if (typename)
  387:             rb_raise(rb_eTypeError, "unsupport type: :%s", typename);
  388:         else
  389:             rb_raise(rb_eTypeError, "unsupport type: %p", (void *)type);
  390:     }
  391: 
  392:     if (parent == Qnil) {
  393:         parent = 0;
  394:     }
  395: 
  396:     make_compile_option(&option, opt);
  397:     prepare_iseq_build(iseq, name, filename,
  398:                        parent, iseq_type, 0, &option);
  399: 
  400:     iseq_build_from_ary(iseq, locals, args, exception, body);
  401: 
  402:     cleanup_iseq_build(iseq);
  403:     return iseqval;
  404: }
  405: 
  406: static VALUE
  407: iseq_s_load(int argc, VALUE *argv, VALUE self)
  408: {
  409:     VALUE data, opt=Qnil;
  410:     rb_scan_args(argc, argv, "11", &data, &opt);
  411: 
  412:     return iseq_load(self, data, 0, opt);
  413: }
  414: 
  415: static NODE *
  416: compile_string(VALUE str, VALUE file, VALUE line)
  417: {
  418:     VALUE parser = rb_parser_new();
  419:     NODE *node = rb_parser_compile_string(parser, StringValueCStr(file),
  420:                                           str, NUM2INT(line));
  421: 
  422:     if (!node) {
  423:         rb_exc_raise(GET_THREAD()->errinfo);   /* TODO: check err */
  424:     }
  425:     return node;
  426: }
  427: 
  428: VALUE
  429: rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE line, VALUE opt)
  430: {
  431:     rb_compile_option_t option;
  432:     NODE *node = compile_string(src, file, line);
  433:     rb_thread_t *th = GET_THREAD();
  434:     make_compile_option(&option, opt);
  435: 
  436:     if (th->base_block) {
  437:         return rb_iseq_new_with_opt(node, th->base_block->iseq->name,
  438:                                     file, th->base_block->iseq->self,
  439:                                     ISEQ_TYPE_EVAL, &option);
  440:     }
  441:     else {
  442:         return rb_iseq_new_with_opt(node, rb_str_new2("<compiled>"), file, Qfalse,
  443:                                     ISEQ_TYPE_TOP, &option);
  444:     }
  445: }
  446: 
  447: VALUE
  448: rb_iseq_compile(VALUE src, VALUE file, VALUE line)
  449: {
  450:     return rb_iseq_compile_with_option(src, file, line, Qnil);
  451: }
  452: 
  453: static VALUE
  454: iseq_s_compile(int argc, VALUE *argv, VALUE self)
  455: {
  456:     VALUE src, file = Qnil, line = INT2FIX(1), opt = Qnil;
  457: 
  458:     rb_secure(1);
  459: 
  460:     rb_scan_args(argc, argv, "13", &src, &file, &line, &opt);
  461:     file = file == Qnil ? rb_str_new2("<compiled>") : file;
  462:     line = line == Qnil ? INT2FIX(1) : line;
  463: 
  464:     return rb_iseq_compile_with_option(src, file, line, opt);
  465: }
  466: 
  467: static VALUE
  468: iseq_s_compile_file(int argc, VALUE *argv, VALUE self)
  469: {
  470:     VALUE file, line = INT2FIX(1), opt = Qnil;
  471:     VALUE parser;
  472:     VALUE f;
  473:     NODE *node;
  474:     const char *fname;
  475:     rb_compile_option_t option;
  476: 
  477:     rb_secure(1);
  478:     rb_scan_args(argc, argv, "11", &file, &opt);
  479:     fname = StringValueCStr(file);
  480: 
  481:     f = rb_file_open(fname, "r");
  482: 
  483:     parser = rb_parser_new();
  484:     node = rb_parser_compile_file(parser, fname, f, NUM2INT(line));
  485:     make_compile_option(&option, opt);
  486:     return rb_iseq_new_with_opt(node, rb_str_new2("<main>"), file, Qfalse,
  487:                                 ISEQ_TYPE_TOP, &option);
  488: }
  489: 
  490: static VALUE
  491: iseq_s_compile_option_set(VALUE self, VALUE opt)
  492: {
  493:     rb_compile_option_t option;
  494:     rb_secure(1);
  495:     make_compile_option(&option, opt);
  496:     COMPILE_OPTION_DEFAULT = option;
  497:     return opt;
  498: }
  499: 
  500: static VALUE
  501: iseq_s_compile_option_get(VALUE self)
  502: {
  503:     return make_compile_option_value(&COMPILE_OPTION_DEFAULT);
  504: }
  505: 
  506: static rb_iseq_t *
  507: iseq_check(VALUE val)
  508: {
  509:     rb_iseq_t *iseq;
  510:     GetISeqPtr(val, iseq);
  511:     if (!iseq->name) {
  512:         rb_raise(rb_eTypeError, "uninitialized InstructionSequence");
  513:     }
  514:     return iseq;
  515: }
  516: 
  517: static VALUE
  518: iseq_eval(VALUE self)
  519: {
  520:     rb_secure(1);
  521:     return rb_iseq_eval(self);
  522: }
  523: 
  524: static VALUE
  525: iseq_inspect(VALUE self)
  526: {
  527:     char buff[0x100];
  528:     rb_iseq_t *iseq = iseq_check(self);
  529: 
  530:     snprintf(buff, sizeof(buff), "<ISeq:%s@%s>",
  531:              RSTRING_PTR(iseq->name), RSTRING_PTR(iseq->filename));
  532: 
  533:     return rb_str_new2(buff);
  534: }
  535: 
  536: VALUE iseq_data_to_ary(rb_iseq_t *iseq);
  537: 
  538: static VALUE
  539: iseq_to_a(VALUE self)
  540: {
  541:     rb_iseq_t *iseq = iseq_check(self);
  542:     rb_secure(1);
  543:     return iseq_data_to_ary(iseq);
  544: }
  545: 
  546: /* TODO: search algorithm is brute force.
  547:          this should be binary search or so. */
  548: 
  549: static struct iseq_insn_info_entry *
  550: get_insn_info(const rb_iseq_t *iseq, const unsigned long pos)
  551: {
  552:     unsigned long i, size = iseq->insn_info_size;
  553:     struct iseq_insn_info_entry *table = iseq->insn_info_table;
  554: 
  555:     for (i = 0; i < size; i++) {
  556:         if (table[i].position == pos) {
  557:             return &table[i];
  558:         }
  559:     }
  560: 
  561:     return 0;
  562: }
  563: 
  564: static unsigned short
  565: find_line_no(rb_iseq_t *iseq, unsigned long pos)
  566: {
  567:     struct iseq_insn_info_entry *entry = get_insn_info(iseq, pos);
  568:     if (entry) {
  569:         return entry->line_no;
  570:     }
  571:     else {
  572:         return 0;
  573:     }
  574: }
  575: 
  576: static unsigned short
  577: find_prev_line_no(rb_iseq_t *iseqdat, unsigned long pos)
  578: {
  579:     unsigned long i, size = iseqdat->insn_info_size;
  580:     struct iseq_insn_info_entry *iiary = iseqdat->insn_info_table;
  581: 
  582:     for (i = 0; i < size; i++) {
  583:         if (iiary[i].position == pos) {
  584:             if (i > 0) {
  585:                 return iiary[i - 1].line_no;