Ruby  2.0.0p353(2013-11-22revision43784)
iseq.c
Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   iseq.c -
00004 
00005   $Author: nagachika $
00006   created at: 2006-07-11(Tue) 09:00:03 +0900
00007 
00008   Copyright (C) 2006 Koichi Sasada
00009 
00010 **********************************************************************/
00011 
00012 #include "ruby/ruby.h"
00013 #include "internal.h"
00014 #include "eval_intern.h"
00015 
00016 /* #define RUBY_MARK_FREE_DEBUG 1 */
00017 #include "gc.h"
00018 #include "vm_core.h"
00019 #include "iseq.h"
00020 
00021 #define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
00022 
00023 #include "insns.inc"
00024 #include "insns_info.inc"
00025 
00026 #define ISEQ_MAJOR_VERSION 2
00027 #define ISEQ_MINOR_VERSION 0
00028 
00029 VALUE rb_cISeq;
00030 
00031 #define hidden_obj_p(obj) (!SPECIAL_CONST_P(obj) && !RBASIC(obj)->klass)
00032 
00033 static inline VALUE
00034 obj_resurrect(VALUE obj)
00035 {
00036     if (hidden_obj_p(obj)) {
00037         switch (BUILTIN_TYPE(obj)) {
00038           case T_STRING:
00039             obj = rb_str_resurrect(obj);
00040             break;
00041           case T_ARRAY:
00042             obj = rb_ary_resurrect(obj);
00043             break;
00044         }
00045     }
00046     return obj;
00047 }
00048 
00049 static void
00050 compile_data_free(struct iseq_compile_data *compile_data)
00051 {
00052     if (compile_data) {
00053         struct iseq_compile_data_storage *cur, *next;
00054         cur = compile_data->storage_head;
00055         while (cur) {
00056             next = cur->next;
00057             ruby_xfree(cur);
00058             cur = next;
00059         }
00060         ruby_xfree(compile_data);
00061     }
00062 }
00063 
00064 static void
00065 iseq_free(void *ptr)
00066 {
00067     rb_iseq_t *iseq;
00068     RUBY_FREE_ENTER("iseq");
00069 
00070     if (ptr) {
00071         iseq = ptr;
00072         if (!iseq->orig) {
00073             /* It's possible that strings are freed */
00074             if (0) {
00075                 RUBY_GC_INFO("%s @ %s\n", RSTRING_PTR(iseq->location.label),
00076                                           RSTRING_PTR(iseq->location.path));
00077             }
00078 
00079             if (iseq->iseq != iseq->iseq_encoded) {
00080                 RUBY_FREE_UNLESS_NULL(iseq->iseq_encoded);
00081             }
00082 
00083             RUBY_FREE_UNLESS_NULL(iseq->iseq);
00084             RUBY_FREE_UNLESS_NULL(iseq->line_info_table);
00085             RUBY_FREE_UNLESS_NULL(iseq->local_table);
00086             RUBY_FREE_UNLESS_NULL(iseq->ic_entries);
00087             RUBY_FREE_UNLESS_NULL(iseq->callinfo_entries);
00088             RUBY_FREE_UNLESS_NULL(iseq->catch_table);
00089             RUBY_FREE_UNLESS_NULL(iseq->arg_opt_table);
00090             RUBY_FREE_UNLESS_NULL(iseq->arg_keyword_table);
00091             compile_data_free(iseq->compile_data);
00092         }
00093         ruby_xfree(ptr);
00094     }
00095     RUBY_FREE_LEAVE("iseq");
00096 }
00097 
00098 static void
00099 iseq_mark(void *ptr)
00100 {
00101     RUBY_MARK_ENTER("iseq");
00102 
00103     if (ptr) {
00104         rb_iseq_t *iseq = ptr;
00105 
00106         RUBY_GC_INFO("%s @ %s\n", RSTRING_PTR(iseq->location.label), RSTRING_PTR(iseq->location.path));
00107         RUBY_MARK_UNLESS_NULL(iseq->mark_ary);
00108 
00109         RUBY_MARK_UNLESS_NULL(iseq->location.label);
00110         RUBY_MARK_UNLESS_NULL(iseq->location.base_label);
00111         RUBY_MARK_UNLESS_NULL(iseq->location.path);
00112         RUBY_MARK_UNLESS_NULL(iseq->location.absolute_path);
00113 
00114         RUBY_MARK_UNLESS_NULL((VALUE)iseq->cref_stack);
00115         RUBY_MARK_UNLESS_NULL(iseq->klass);
00116         RUBY_MARK_UNLESS_NULL(iseq->coverage);
00117 #if 0
00118         RUBY_MARK_UNLESS_NULL((VALUE)iseq->node);
00119         RUBY_MARK_UNLESS_NULL(iseq->cached_special_block);
00120 #endif
00121         RUBY_MARK_UNLESS_NULL(iseq->orig);
00122 
00123         if (iseq->compile_data != 0) {
00124             struct iseq_compile_data *const compile_data = iseq->compile_data;
00125             RUBY_MARK_UNLESS_NULL(compile_data->mark_ary);
00126             RUBY_MARK_UNLESS_NULL(compile_data->err_info);
00127             RUBY_MARK_UNLESS_NULL(compile_data->catch_table_ary);
00128         }
00129     }
00130     RUBY_MARK_LEAVE("iseq");
00131 }
00132 
00133 static size_t
00134 iseq_memsize(const void *ptr)
00135 {
00136     size_t size = sizeof(rb_iseq_t);
00137     const rb_iseq_t *iseq;
00138 
00139     if (ptr) {
00140         iseq = ptr;
00141         if (!iseq->orig) {
00142             if (iseq->iseq != iseq->iseq_encoded) {
00143                 size += iseq->iseq_size * sizeof(VALUE);
00144             }
00145 
00146             size += iseq->iseq_size * sizeof(VALUE);
00147             size += iseq->line_info_size * sizeof(struct iseq_line_info_entry);
00148             size += iseq->local_table_size * sizeof(ID);
00149             size += iseq->catch_table_size * sizeof(struct iseq_catch_table_entry);
00150             size += iseq->arg_opts * sizeof(VALUE);
00151             size += iseq->ic_size * sizeof(struct iseq_inline_cache_entry);
00152             size += iseq->callinfo_size * sizeof(rb_call_info_t);
00153 
00154             if (iseq->compile_data) {
00155                 struct iseq_compile_data_storage *cur;
00156 
00157                 cur = iseq->compile_data->storage_head;
00158                 while (cur) {
00159                     size += cur->size + sizeof(struct iseq_compile_data_storage);
00160                     cur = cur->next;
00161                 }
00162                 size += sizeof(struct iseq_compile_data);
00163             }
00164         }
00165     }
00166 
00167     return size;
00168 }
00169 
00170 static const rb_data_type_t iseq_data_type = {
00171     "iseq",
00172     {
00173         iseq_mark,
00174         iseq_free,
00175         iseq_memsize,
00176     },
00177 };
00178 
00179 static VALUE
00180 iseq_alloc(VALUE klass)
00181 {
00182     rb_iseq_t *iseq;
00183     return TypedData_Make_Struct(klass, rb_iseq_t, &iseq_data_type, iseq);
00184 }
00185 
00186 static rb_iseq_location_t *
00187 iseq_location_setup(rb_iseq_t *iseq, VALUE path, VALUE absolute_path, VALUE name, size_t first_lineno)
00188 {
00189     rb_iseq_location_t *loc = &iseq->location;
00190     loc->path = path;
00191     if (RTEST(absolute_path) && rb_str_cmp(path, absolute_path) == 0)
00192         loc->absolute_path = path;
00193     else
00194         loc->absolute_path = absolute_path;
00195     loc->label = loc->base_label = name;
00196     loc->first_lineno = first_lineno;
00197     return loc;
00198 }
00199 
00200 static void
00201 set_relation(rb_iseq_t *iseq, const VALUE parent)
00202 {
00203     const VALUE type = iseq->type;
00204     rb_thread_t *th = GET_THREAD();
00205     rb_iseq_t *piseq;
00206 
00207     /* set class nest stack */
00208     if (type == ISEQ_TYPE_TOP) {
00209         /* toplevel is private */
00210         iseq->cref_stack = NEW_CREF(rb_cObject);
00211         iseq->cref_stack->nd_refinements = Qnil;
00212         iseq->cref_stack->nd_visi = NOEX_PRIVATE;
00213         if (th->top_wrapper) {
00214             NODE *cref = NEW_CREF(th->top_wrapper);
00215             cref->nd_refinements = Qnil;
00216             cref->nd_visi = NOEX_PRIVATE;
00217             cref->nd_next = iseq->cref_stack;
00218             iseq->cref_stack = cref;
00219         }
00220         iseq->local_iseq = iseq;
00221     }
00222     else if (type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) {
00223         iseq->cref_stack = NEW_CREF(0); /* place holder */
00224         iseq->cref_stack->nd_refinements = Qnil;
00225         iseq->local_iseq = iseq;
00226     }
00227     else if (RTEST(parent)) {
00228         GetISeqPtr(parent, piseq);
00229         iseq->cref_stack = piseq->cref_stack;
00230         iseq->local_iseq = piseq->local_iseq;
00231     }
00232 
00233     if (RTEST(parent)) {
00234         GetISeqPtr(parent, piseq);
00235         iseq->parent_iseq = piseq;
00236     }
00237 
00238     if (type == ISEQ_TYPE_MAIN) {
00239         iseq->local_iseq = iseq;
00240     }
00241 }
00242 
00243 void
00244 rb_iseq_add_mark_object(rb_iseq_t *iseq, VALUE obj)
00245 {
00246     if (!RTEST(iseq->mark_ary)) {
00247         iseq->mark_ary = rb_ary_tmp_new(3);
00248         OBJ_UNTRUST(iseq->mark_ary);
00249         RBASIC(iseq->mark_ary)->klass = 0;
00250     }
00251     rb_ary_push(iseq->mark_ary, obj);
00252 }
00253 
00254 static VALUE
00255 prepare_iseq_build(rb_iseq_t *iseq,
00256                    VALUE name, VALUE path, VALUE absolute_path, VALUE first_lineno,
00257                    VALUE parent, enum iseq_type type, VALUE block_opt,
00258                    const rb_compile_option_t *option)
00259 {
00260     iseq->type = type;
00261     iseq->arg_rest = -1;
00262     iseq->arg_block = -1;
00263     iseq->arg_keyword = -1;
00264     iseq->klass = 0;
00265     set_relation(iseq, parent);
00266 
00267     OBJ_FREEZE(name);
00268     OBJ_FREEZE(path);
00269 
00270     iseq_location_setup(iseq, path, absolute_path, name, first_lineno);
00271     if (iseq != iseq->local_iseq) {
00272         iseq->location.base_label = iseq->local_iseq->location.label;
00273     }
00274 
00275     iseq->defined_method_id = 0;
00276     iseq->mark_ary = 0;
00277 
00278 
00279     /*
00280      * iseq->special_block_builder = GC_GUARDED_PTR_REF(block_opt);
00281      * iseq->cached_special_block_builder = 0;
00282      * iseq->cached_special_block = 0;
00283      */
00284 
00285     iseq->compile_data = ALLOC(struct iseq_compile_data);
00286     MEMZERO(iseq->compile_data, struct iseq_compile_data, 1);
00287     iseq->compile_data->err_info = Qnil;
00288     iseq->compile_data->mark_ary = rb_ary_tmp_new(3);
00289 
00290     iseq->compile_data->storage_head = iseq->compile_data->storage_current =
00291       (struct iseq_compile_data_storage *)
00292         ALLOC_N(char, INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE +
00293                 sizeof(struct iseq_compile_data_storage));
00294 
00295     iseq->compile_data->catch_table_ary = rb_ary_new();
00296     iseq->compile_data->storage_head->pos = 0;
00297     iseq->compile_data->storage_head->next = 0;
00298     iseq->compile_data->storage_head->size =
00299       INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE;
00300     iseq->compile_data->storage_head->buff =
00301       (char *)(&iseq->compile_data->storage_head->buff + 1);
00302     iseq->compile_data->option = option;
00303     iseq->compile_data->last_coverable_line = -1;
00304 
00305     iseq->coverage = Qfalse;
00306     if (!GET_THREAD()->parse_in_eval) {
00307         VALUE coverages = rb_get_coverages();
00308         if (RTEST(coverages)) {
00309             iseq->coverage = rb_hash_lookup(coverages, path);
00310             if (NIL_P(iseq->coverage)) iseq->coverage = Qfalse;
00311         }
00312     }
00313 
00314     return Qtrue;
00315 }
00316 
00317 static VALUE
00318 cleanup_iseq_build(rb_iseq_t *iseq)
00319 {
00320     struct iseq_compile_data *data = iseq->compile_data;
00321     VALUE err = data->err_info;
00322     iseq->compile_data = 0;
00323     compile_data_free(data);
00324 
00325     if (RTEST(err)) {
00326         rb_funcall2(err, rb_intern("set_backtrace"), 1, &iseq->location.path);
00327         rb_exc_raise(err);
00328     }
00329     return Qtrue;
00330 }
00331 
00332 static rb_compile_option_t COMPILE_OPTION_DEFAULT = {
00333     OPT_INLINE_CONST_CACHE, /* int inline_const_cache; */
00334     OPT_PEEPHOLE_OPTIMIZATION, /* int peephole_optimization; */
00335     OPT_TAILCALL_OPTIMIZATION, /* int tailcall_optimization */
00336     OPT_SPECIALISED_INSTRUCTION, /* int specialized_instruction; */
00337     OPT_OPERANDS_UNIFICATION, /* int operands_unification; */
00338     OPT_INSTRUCTIONS_UNIFICATION, /* int instructions_unification; */
00339     OPT_STACK_CACHING, /* int stack_caching; */
00340     OPT_TRACE_INSTRUCTION, /* int trace_instruction */
00341 };
00342 static const rb_compile_option_t COMPILE_OPTION_FALSE = {0};
00343 
00344 static void
00345 make_compile_option(rb_compile_option_t *option, VALUE opt)
00346 {
00347     if (opt == Qnil) {
00348         *option = COMPILE_OPTION_DEFAULT;
00349     }
00350     else if (opt == Qfalse) {
00351         *option = COMPILE_OPTION_FALSE;
00352     }
00353     else if (opt == Qtrue) {
00354         memset(option, 1, sizeof(rb_compile_option_t));
00355     }
00356     else if (CLASS_OF(opt) == rb_cHash) {
00357         *option = COMPILE_OPTION_DEFAULT;
00358 
00359 #define SET_COMPILE_OPTION(o, h, mem) \
00360   { VALUE flag = rb_hash_aref((h), ID2SYM(rb_intern(#mem))); \
00361       if (flag == Qtrue)  { (o)->mem = 1; } \
00362       else if (flag == Qfalse)  { (o)->mem = 0; } \
00363   }
00364 #define SET_COMPILE_OPTION_NUM(o, h, mem) \
00365   { VALUE num = rb_hash_aref(opt, ID2SYM(rb_intern(#mem))); \
00366       if (!NIL_P(num)) (o)->mem = NUM2INT(num); \
00367   }
00368         SET_COMPILE_OPTION(option, opt, inline_const_cache);
00369         SET_COMPILE_OPTION(option, opt, peephole_optimization);
00370         SET_COMPILE_OPTION(option, opt, tailcall_optimization);
00371         SET_COMPILE_OPTION(option, opt, specialized_instruction);
00372         SET_COMPILE_OPTION(option, opt, operands_unification);
00373         SET_COMPILE_OPTION(option, opt, instructions_unification);
00374         SET_COMPILE_OPTION(option, opt, stack_caching);
00375         SET_COMPILE_OPTION(option, opt, trace_instruction);
00376         SET_COMPILE_OPTION_NUM(option, opt, debug_level);
00377 #undef SET_COMPILE_OPTION
00378 #undef SET_COMPILE_OPTION_NUM
00379     }
00380     else {
00381         rb_raise(rb_eTypeError, "Compile option must be Hash/true/false/nil");
00382     }
00383 }
00384 
00385 static VALUE
00386 make_compile_option_value(rb_compile_option_t *option)
00387 {
00388     VALUE opt = rb_hash_new();
00389 #define SET_COMPILE_OPTION(o, h, mem) \
00390   rb_hash_aset((h), ID2SYM(rb_intern(#mem)), (o)->mem ? Qtrue : Qfalse)
00391 #define SET_COMPILE_OPTION_NUM(o, h, mem) \
00392   rb_hash_aset((h), ID2SYM(rb_intern(#mem)), INT2NUM((o)->mem))
00393     {
00394         SET_COMPILE_OPTION(option, opt, inline_const_cache);
00395         SET_COMPILE_OPTION(option, opt, peephole_optimization);
00396         SET_COMPILE_OPTION(option, opt, tailcall_optimization);
00397         SET_COMPILE_OPTION(option, opt, specialized_instruction);
00398         SET_COMPILE_OPTION(option, opt, operands_unification);
00399         SET_COMPILE_OPTION(option, opt, instructions_unification);
00400         SET_COMPILE_OPTION(option, opt, stack_caching);
00401         SET_COMPILE_OPTION(option, opt, trace_instruction);
00402         SET_COMPILE_OPTION_NUM(option, opt, debug_level);
00403     }
00404 #undef SET_COMPILE_OPTION
00405 #undef SET_COMPILE_OPTION_NUM
00406     return opt;
00407 }
00408 
00409 VALUE
00410 rb_iseq_new(NODE *node, VALUE name, VALUE path, VALUE absolute_path,
00411             VALUE parent, enum iseq_type type)
00412 {
00413     return rb_iseq_new_with_opt(node, name, path, absolute_path, INT2FIX(0), parent, type,
00414                                 &COMPILE_OPTION_DEFAULT);
00415 }
00416 
00417 VALUE
00418 rb_iseq_new_top(NODE *node, VALUE name, VALUE path, VALUE absolute_path, VALUE parent)
00419 {
00420     return rb_iseq_new_with_opt(node, name, path, absolute_path, INT2FIX(0), parent, ISEQ_TYPE_TOP,
00421                                 &COMPILE_OPTION_DEFAULT);
00422 }
00423 
00424 VALUE
00425 rb_iseq_new_main(NODE *node, VALUE path, VALUE absolute_path)
00426 {
00427     rb_thread_t *th = GET_THREAD();
00428     VALUE parent = th->base_block->iseq->self;
00429     return rb_iseq_new_with_opt(node, rb_str_new2("<main>"), path, absolute_path, INT2FIX(0),
00430                                 parent, ISEQ_TYPE_MAIN, &COMPILE_OPTION_DEFAULT);
00431 }
00432 
00433 static VALUE
00434 rb_iseq_new_with_bopt_and_opt(NODE *node, VALUE name, VALUE path, VALUE absolute_path, VALUE first_lineno,
00435                                 VALUE parent, enum iseq_type type, VALUE bopt,
00436                                 const rb_compile_option_t *option)
00437 {
00438     rb_iseq_t *iseq;
00439     VALUE self = iseq_alloc(rb_cISeq);
00440 
00441     GetISeqPtr(self, iseq);
00442     iseq->self = self;
00443 
00444     prepare_iseq_build(iseq, name, path, absolute_path, first_lineno, parent, type, bopt, option);
00445     rb_iseq_compile_node(self, node);
00446     cleanup_iseq_build(iseq);
00447     return self;
00448 }
00449 
00450 VALUE
00451 rb_iseq_new_with_opt(NODE *node, VALUE name, VALUE path, VALUE absolute_path, VALUE first_lineno,
00452                      VALUE parent, enum iseq_type type,
00453                      const rb_compile_option_t *option)
00454 {
00455     /* TODO: argument check */
00456     return rb_iseq_new_with_bopt_and_opt(node, name, path, absolute_path, first_lineno, parent, type,
00457                                            Qfalse, option);
00458 }
00459 
00460 VALUE
00461 rb_iseq_new_with_bopt(NODE *node, VALUE name, VALUE path, VALUE absolute_path, VALUE first_lineno,
00462                        VALUE parent, enum iseq_type type, VALUE bopt)
00463 {
00464     /* TODO: argument check */
00465     return rb_iseq_new_with_bopt_and_opt(node, name, path, absolute_path, first_lineno, parent, type,
00466                                            bopt, &COMPILE_OPTION_DEFAULT);
00467 }
00468 
00469 #define CHECK_ARRAY(v)   rb_convert_type((v), T_ARRAY, "Array", "to_ary")
00470 #define CHECK_STRING(v)  rb_convert_type((v), T_STRING, "String", "to_str")
00471 #define CHECK_SYMBOL(v)  rb_convert_type((v), T_SYMBOL, "Symbol", "to_sym")
00472 static inline VALUE CHECK_INTEGER(VALUE v) {(void)NUM2LONG(v); return v;}
00473 static VALUE
00474 iseq_load(VALUE self, VALUE data, VALUE parent, VALUE opt)
00475 {
00476     VALUE iseqval = iseq_alloc(self);
00477 
00478     VALUE magic, version1, version2, format_type, misc;
00479     VALUE name, path, absolute_path, first_lineno;
00480     VALUE type, body, locals, args, exception;
00481 
00482     st_data_t iseq_type;
00483     struct st_table *type_map = 0;
00484     rb_iseq_t *iseq;
00485     rb_compile_option_t option;
00486     int i = 0;
00487 
00488     /* [magic, major_version, minor_version, format_type, misc,
00489      *  label, path, first_lineno,
00490      *  type, locals, args, exception_table, body]
00491      */
00492 
00493     data        = CHECK_ARRAY(data);
00494 
00495     magic       = CHECK_STRING(rb_ary_entry(data, i++));
00496     version1    = CHECK_INTEGER(rb_ary_entry(data, i++));
00497     version2    = CHECK_INTEGER(rb_ary_entry(data, i++));
00498     format_type = CHECK_INTEGER(rb_ary_entry(data, i++));
00499     misc        = rb_ary_entry(data, i++); /* TODO */
00500     ((void)magic, (void)version1, (void)version2, (void)format_type, (void)misc);
00501 
00502     name        = CHECK_STRING(rb_ary_entry(data, i++));
00503     path        = CHECK_STRING(rb_ary_entry(data, i++));
00504     absolute_path = rb_ary_entry(data, i++);
00505     absolute_path = NIL_P(absolute_path) ? Qnil : CHECK_STRING(absolute_path);
00506     first_lineno = CHECK_INTEGER(rb_ary_entry(data, i++));
00507 
00508     type        = CHECK_SYMBOL(rb_ary_entry(data, i++));
00509     locals      = CHECK_ARRAY(rb_ary_entry(data, i++));
00510 
00511     args        = rb_ary_entry(data, i++);
00512     if (FIXNUM_P(args) || (args = CHECK_ARRAY(args))) {
00513         /* */
00514     }
00515 
00516     exception   = CHECK_ARRAY(rb_ary_entry(data, i++));
00517     body        = CHECK_ARRAY(rb_ary_entry(data, i++));
00518 
00519     GetISeqPtr(iseqval, iseq);
00520     iseq->self = iseqval;
00521 
00522     if (type_map == 0) {
00523         type_map = st_init_numtable();
00524         st_insert(type_map, ID2SYM(rb_intern("top")), ISEQ_TYPE_TOP);
00525         st_insert(type_map, ID2SYM(rb_intern("method")), ISEQ_TYPE_METHOD);
00526         st_insert(type_map, ID2SYM(rb_intern("block")), ISEQ_TYPE_BLOCK);
00527         st_insert(type_map, ID2SYM(rb_intern("class")), ISEQ_TYPE_CLASS);
00528         st_insert(type_map, ID2SYM(rb_intern("rescue")), ISEQ_TYPE_RESCUE);
00529         st_insert(type_map, ID2SYM(rb_intern("ensure")), ISEQ_TYPE_ENSURE);
00530         st_insert(type_map, ID2SYM(rb_intern("eval")), ISEQ_TYPE_EVAL);
00531         st_insert(type_map, ID2SYM(rb_intern("main")), ISEQ_TYPE_MAIN);
00532         st_insert(type_map, ID2SYM(rb_intern("defined_guard")), ISEQ_TYPE_DEFINED_GUARD);
00533     }
00534 
00535     if (st_lookup(type_map, type, &iseq_type) == 0) {
00536         ID typeid = SYM2ID(type);
00537         VALUE typename = rb_id2str(typeid);
00538         if (typename)
00539             rb_raise(rb_eTypeError, "unsupport type: :%"PRIsVALUE, typename);
00540         else
00541             rb_raise(rb_eTypeError, "unsupport type: %p", (void *)typeid);
00542     }
00543 
00544     if (parent == Qnil) {
00545         parent = 0;
00546     }
00547 
00548     make_compile_option(&option, opt);
00549     prepare_iseq_build(iseq, name, path, absolute_path, first_lineno,
00550                        parent, (enum iseq_type)iseq_type, 0, &option);
00551 
00552     rb_iseq_build_from_ary(iseq, locals, args, exception, body);
00553 
00554     cleanup_iseq_build(iseq);
00555     return iseqval;
00556 }
00557 
00558 /*
00559  * :nodoc:
00560  */
00561 static VALUE
00562 iseq_s_load(int argc, VALUE *argv, VALUE self)
00563 {
00564     VALUE data, opt=Qnil;
00565     rb_scan_args(argc, argv, "11", &data, &opt);
00566 
00567     return iseq_load(self, data, 0, opt);
00568 }
00569 
00570 VALUE
00571 rb_iseq_load(VALUE data, VALUE parent, VALUE opt)
00572 {
00573     return iseq_load(rb_cISeq, data, parent, opt);
00574 }
00575 
00576 static NODE *
00577 parse_string(VALUE str, const char *file, int line)
00578 {
00579     VALUE parser = rb_parser_new();
00580     NODE *node = rb_parser_compile_string(parser, file, str, line);
00581 
00582     if (!node) {
00583         rb_exc_raise(GET_THREAD()->errinfo);    /* TODO: check err */
00584     }
00585     return node;
00586 }
00587 
00588 VALUE
00589 rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE absolute_path, VALUE line, rb_block_t *base_block, VALUE opt)
00590 {
00591     int state;
00592     rb_thread_t *th = GET_THREAD();
00593     rb_block_t *prev_base_block = th->base_block;
00594     VALUE iseqval = Qundef;
00595 
00596     th->base_block = base_block;
00597 
00598     TH_PUSH_TAG(th);
00599     if ((state = EXEC_TAG()) == 0) {
00600         int ln = NUM2INT(line);
00601         const char *fn = StringValueCStr(file);
00602         NODE *node;
00603         rb_compile_option_t option;
00604 
00605         make_compile_option(&option, opt);
00606 
00607         if (RB_TYPE_P((src), T_FILE))
00608             node = rb_compile_file(fn, src, ln);
00609         else
00610             node = parse_string(StringValue(src), fn, ln);
00611 
00612         if (base_block && base_block->iseq) {
00613             iseqval = rb_iseq_new_with_opt(node, base_block->iseq->location.label,
00614                                            file, absolute_path, line, base_block->iseq->self,
00615                                            ISEQ_TYPE_EVAL, &option);
00616         }
00617         else {
00618             iseqval = rb_iseq_new_with_opt(node, rb_str_new2("<compiled>"), file, absolute_path, line, Qfalse,
00619                                            ISEQ_TYPE_TOP, &option);
00620         }
00621     }
00622     TH_POP_TAG();
00623 
00624     th->base_block = prev_base_block;
00625 
00626     if (state) {
00627         JUMP_TAG(state);
00628     }
00629 
00630     return iseqval;
00631 }
00632 
00633 VALUE
00634 rb_iseq_compile(VALUE src, VALUE file, VALUE line)
00635 {
00636     return rb_iseq_compile_with_option(src, file, Qnil, line, 0, Qnil);
00637 }
00638 
00639 VALUE
00640 rb_iseq_compile_on_base(VALUE src, VALUE file, VALUE line, rb_block_t *base_block)
00641 {
00642     return rb_iseq_compile_with_option(src, file, Qnil, line, base_block, Qnil);
00643 }
00644 
00645 /*
00646  *  call-seq:
00647  *     InstructionSequence.compile(source[, file[, path[, line[, options]]]]) -> iseq
00648  *     InstructionSequence.new(source[, file[, path[, line[, options]]]]) -> iseq
00649  *
00650  *  Takes +source+, a String of Ruby code and compiles it to an
00651  *  InstructionSequence.
00652  *
00653  *  Optionally takes +file+, +path+, and +line+ which describe the filename,
00654  *  absolute path and first line number of the ruby code in +source+ which are
00655  *  metadata attached to the returned +iseq+.
00656  *
00657  *  +options+, which can be +true+, +false+ or a +Hash+, is used to
00658  *  modify the default behavior of the Ruby iseq compiler.
00659  *
00660  *  For details regarding valid compile options see ::compile_option=.
00661  *
00662  *     RubyVM::InstructionSequence.compile("a = 1 + 2")
00663  *     #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
00664  *
00665  */
00666 static VALUE
00667 iseq_s_compile(int argc, VALUE *argv, VALUE self)
00668 {
00669     VALUE src, file = Qnil, path = Qnil, line = INT2FIX(1), opt = Qnil;
00670 
00671     rb_secure(1);
00672 
00673     rb_scan_args(argc, argv, "14", &src, &file, &path, &line, &opt);
00674     if (NIL_P(file)) file = rb_str_new2("<compiled>");
00675     if (NIL_P(line)) line = INT2FIX(1);
00676 
00677     return rb_iseq_compile_with_option(src, file, path, line, 0, opt);
00678 }
00679 
00680 /*
00681  *  call-seq:
00682  *      InstructionSequence.compile_file(file[, options]) -> iseq
00683  *
00684  *  Takes +file+, a String with the location of a Ruby source file, reads,
00685  *  parses and compiles the file, and returns +iseq+, the compiled
00686  *  InstructionSequence with source location metadata set.
00687  *
00688  *  Optionally takes +options+, which can be +true+, +false+ or a +Hash+, to
00689  *  modify the default behavior of the Ruby iseq compiler.
00690  *
00691  *  For details regarding valid compile options see ::compile_option=.
00692  *
00693  *      # /tmp/hello.rb
00694  *      puts "Hello, world!"
00695  *
00696  *      # elsewhere
00697  *      RubyVM::InstructionSequence.compile_file("/tmp/hello.rb")
00698  *      #=> <RubyVM::InstructionSequence:<main>@/tmp/hello.rb>
00699  */
00700 static VALUE
00701 iseq_s_compile_file(int argc, VALUE *argv, VALUE self)
00702 {
00703     VALUE file, line = INT2FIX(1), opt = Qnil;
00704     VALUE parser;
00705     VALUE f;
00706     NODE *node;
00707     const char *fname;
00708     rb_compile_option_t option;
00709 
00710     rb_secure(1);
00711     rb_scan_args(argc, argv, "11", &file, &opt);
00712     FilePathValue(file);
00713     fname = StringValueCStr(file);
00714 
00715     f = rb_file_open_str(file, "r");
00716 
00717     parser = rb_parser_new();
00718     node = rb_parser_compile_file(parser, fname, f, NUM2INT(line));
00719     make_compile_option(&option, opt);
00720     return rb_iseq_new_with_opt(node, rb_str_new2("<main>"), file,
00721                                 rb_realpath_internal(Qnil, file, 1), line, Qfalse,
00722                                 ISEQ_TYPE_TOP, &option);
00723 }
00724 
00725 /*
00726  *  call-seq:
00727  *     InstructionSequence.compile_option = options
00728  *
00729  *  Sets the default values for various optimizations in the Ruby iseq
00730  *  compiler.
00731  *
00732  *  Possible values for +options+ include +true+, which enables all options,
00733  *  +false+ which disables all options, and +nil+ which leaves all options
00734  *  unchanged.
00735  *
00736  *  You can also pass a +Hash+ of +options+ that you want to change, any
00737  *  options not present in the hash will be left unchanged.
00738  *
00739  *  Possible option names (which are keys in +options+) which can be set to
00740  *  +true+ or +false+ include:
00741  *
00742  *  * +:inline_const_cache+
00743  *  * +:instructions_unification+
00744  *  * +:operands_unification+
00745  *  * +:peephole_optimization+
00746  *  * +:specialized_instruction+
00747  *  * +:stack_caching+
00748  *  * +:tailcall_optimization+
00749  *  * +:trace_instruction+
00750  *
00751  *  Additionally, +:debug_level+ can be set to an integer.
00752  *
00753  *  These default options can be overwritten for a single run of the iseq
00754  *  compiler by passing any of the above values as the +options+ parameter to
00755  *  ::new, ::compile and ::compile_file.
00756  */
00757 static VALUE
00758 iseq_s_compile_option_set(VALUE self, VALUE opt)
00759 {
00760     rb_compile_option_t option;
00761     rb_secure(1);
00762     make_compile_option(&option, opt);
00763     COMPILE_OPTION_DEFAULT = option;
00764     return opt;
00765 }
00766 
00767 /*
00768  *  call-seq:
00769  *     InstructionSequence.compile_option -> options
00770  *
00771  *  Returns a hash of default options used by the Ruby iseq compiler.
00772  *
00773  *  For details, see InstructionSequence.compile_option=.
00774  */
00775 static VALUE
00776 iseq_s_compile_option_get(VALUE self)
00777 {
00778     return make_compile_option_value(&COMPILE_OPTION_DEFAULT);
00779 }
00780 
00781 static rb_iseq_t *
00782 iseq_check(VALUE val)
00783 {
00784     rb_iseq_t *iseq;
00785     GetISeqPtr(val, iseq);
00786     if (!iseq->location.label) {
00787         rb_raise(rb_eTypeError, "uninitialized InstructionSequence");
00788     }
00789     return iseq;
00790 }
00791 
00792 /*
00793  *  call-seq:
00794  *     iseq.eval -> obj
00795  *
00796  *  Evaluates the instruction sequence and returns the result.
00797  *
00798  *      RubyVM::InstructionSequence.compile("1 + 2").eval #=> 3
00799  */
00800 static VALUE
00801 iseq_eval(VALUE self)
00802 {
00803     rb_secure(1);
00804     return rb_iseq_eval(self);
00805 }
00806 
00807 /*
00808  *  Returns a human-readable string representation of this instruction
00809  *  sequence, including the #label and #path.
00810  */
00811 static VALUE
00812 iseq_inspect(VALUE self)
00813 {
00814     rb_iseq_t *iseq;
00815     GetISeqPtr(self, iseq);
00816     if (!iseq->location.label) {
00817         return rb_sprintf("#<%s: uninitialized>", rb_obj_classname(self));
00818     }
00819 
00820     return rb_sprintf("<%s:%s@%s>",
00821                       rb_obj_classname(self),
00822                       RSTRING_PTR(iseq->location.label), RSTRING_PTR(iseq->location.path));
00823 }
00824 
00825 /*
00826  *  Returns the path of this instruction sequence.
00827  *
00828  *  <code><compiled></code> if the iseq was evaluated from a string.
00829  *
00830  *  For example, using irb:
00831  *
00832  *      iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
00833  *      #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
00834  *      iseq.path
00835  *      #=> "<compiled>"
00836  *
00837  *  Using ::compile_file:
00838  *
00839  *      # /tmp/method.rb
00840  *      def hello
00841  *        puts "hello, world"
00842  *      end
00843  *
00844  *      # in irb
00845  *      > iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
00846  *      > iseq.path #=> /tmp/method.rb
00847  */
00848 static VALUE
00849 iseq_path(VALUE self)
00850 {
00851     rb_iseq_t *iseq;
00852     GetISeqPtr(self, iseq);
00853     return iseq->location.path;
00854 }
00855 
00856 /*
00857  *  Returns the absolute path of this instruction sequence.
00858  *
00859  *  +nil+ if the iseq was evaluated from a string.
00860  *
00861  *  For example, using ::compile_file:
00862  *
00863  *      # /tmp/method.rb
00864  *      def hello
00865  *        puts "hello, world"
00866  *      end
00867  *
00868  *      # in irb
00869  *      > iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
00870  *      > iseq.absolute_path #=> /tmp/method.rb
00871  */
00872 static VALUE
00873 iseq_absolute_path(VALUE self)
00874 {
00875     rb_iseq_t *iseq;
00876     GetISeqPtr(self, iseq);
00877     return iseq->location.absolute_path;
00878 }
00879 
00880 /*  Returns the label of this instruction sequence.
00881  *
00882  *  <code><main></code> if it's at the top level, <code><compiled></code> if it
00883  *  was evaluated from a string.
00884  *
00885  *  For example, using irb:
00886  *
00887  *      iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
00888  *      #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
00889  *      iseq.label
00890  *      #=> "<compiled>"
00891  *
00892  *  Using ::compile_file:
00893  *
00894  *      # /tmp/method.rb
00895  *      def hello
00896  *        puts "hello, world"
00897  *      end
00898  *
00899  *      # in irb
00900  *      > iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
00901  *      > iseq.label #=> <main>
00902  */
00903 static VALUE
00904 iseq_label(VALUE self)
00905 {
00906     rb_iseq_t *iseq;
00907     GetISeqPtr(self, iseq);
00908     return iseq->location.label;
00909 }
00910 
00911 /*  Returns the base label of this instruction sequence.
00912  *
00913  *  For example, using irb:
00914  *
00915  *      iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
00916  *      #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
00917  *      iseq.base_label
00918  *      #=> "<compiled>"
00919  *
00920  *  Using ::compile_file:
00921  *
00922  *      # /tmp/method.rb
00923  *      def hello
00924  *        puts "hello, world"
00925  *      end
00926  *
00927  *      # in irb
00928  *      > iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
00929  *      > iseq.base_label #=> <main>
00930  */
00931 static VALUE
00932 iseq_base_label(VALUE self)
00933 {
00934     rb_iseq_t *iseq;
00935     GetISeqPtr(self, iseq);
00936     return iseq->location.base_label;
00937 }
00938 
00939 /*  Returns the number of the first source line where the instruction sequence
00940  *  was loaded from.
00941  *
00942  *  For example, using irb:
00943  *
00944  *      iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
00945  *      #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
00946  *      iseq.first_lineno
00947  *      #=> 1
00948  */
00949 static VALUE
00950 iseq_first_lineno(VALUE self)
00951 {
00952     rb_iseq_t *iseq;
00953     GetISeqPtr(self, iseq);
00954     return iseq->location.first_lineno;
00955 }
00956 
00957 static
00958 VALUE iseq_data_to_ary(rb_iseq_t *iseq);
00959 
00960 /*
00961  *  call-seq:
00962  *     iseq.to_a -> ary
00963  *
00964  *  Returns an Array with 14 elements representing the instruction sequence
00965  *  with the following data:
00966  *
00967  *  [magic]
00968  *    A string identifying the data format. <b>Always
00969  *    +YARVInstructionSequence/SimpleDataFormat+.</b>
00970  *
00971  *  [major_version]
00972  *    The major version of the instruction sequence.
00973  *
00974  *  [minor_version]
00975  *    The minor version of the instruction sequence.
00976  *
00977  *  [format_type]
00978  *    A number identifying the data format. <b>Always 1</b>.
00979  *
00980  *  [misc]
00981  *    A hash containing:
00982  *
00983  *    [+:arg_size+]
00984  *      the total number of arguments taken by the method or the block (0 if
00985  *      _iseq_ doesn't represent a method or block)
00986  *    [+:local_size+]
00987  *      the number of local variables + 1
00988  *    [+:stack_max+]
00989  *      used in calculating the stack depth at which a SystemStackError is
00990  *      thrown.
00991  *
00992  *  [#label]
00993  *    The name of the context (block, method, class, module, etc.) that this
00994  *    instruction sequence belongs to.
00995  *
00996  *    <code><main></code> if it's at the top level, <code><compiled></code> if
00997  *    it was evaluated from a string.
00998  *
00999  *  [#path]
01000  *    The relative path to the Ruby file where the instruction sequence was
01001  *    loaded from.
01002  *
01003  *    <code><compiled></code> if the iseq was evaluated from a string.
01004  *
01005  *  [#absolute_path]
01006  *    The absolute path to the Ruby file where the instruction sequence was
01007  *    loaded from.
01008  *
01009  *    +nil+ if the iseq was evaluated from a string.
01010  *
01011  *  [#first_lineno]
01012  *    The number of the first source line where the instruction sequence was
01013  *    loaded from.
01014  *
01015  *  [type]
01016  *    The type of the instruction sequence.
01017  *
01018  *    Valid values are +:top+, +:method+, +:block+, +:class+, +:rescue+,
01019  *    +:ensure+, +:eval+, +:main+, and +:defined_guard+.
01020  *
01021  *  [locals]
01022  *    An array containing the names of all arguments and local variables as
01023  *    symbols.
01024  *
01025  *  [args]
01026  *    The arity if the method or block only has required arguments.
01027  *
01028  *    Otherwise an array of:
01029  *
01030  *      [required_argc, [optional_arg_labels, ...],
01031  *       splat_index, post_splat_argc, post_splat_index,
01032  *       block_index, simple]
01033  *
01034  *    More info about these values can be found in +vm_core.h+.
01035  *
01036  *  [catch_table]
01037  *    A list of exceptions and control flow operators (rescue, next, redo,
01038  *    break, etc.).
01039  *
01040  *  [bytecode]
01041  *    An array of arrays containing the instruction names and operands that
01042  *    make up the body of the instruction sequence.
01043  *
01044  */
01045 static VALUE
01046 iseq_to_a(VALUE self)
01047 {
01048     rb_iseq_t *iseq = iseq_check(self);
01049     rb_secure(1);
01050     return iseq_data_to_ary(iseq);
01051 }
01052 
01053 int
01054 rb_iseq_first_lineno(const rb_iseq_t *iseq)
01055 {
01056     return FIX2INT(iseq->location.first_lineno);
01057 }
01058 
01059 /* TODO: search algorithm is brute force.
01060          this should be binary search or so. */
01061 
01062 static struct iseq_line_info_entry *
01063 get_line_info(const rb_iseq_t *iseq, size_t pos)
01064 {
01065     size_t i = 0, size = iseq->line_info_size;
01066     struct iseq_line_info_entry *table = iseq->line_info_table;
01067     const int debug = 0;
01068 
01069     if (debug) {
01070         printf("size: %"PRIdSIZE"\n", size);
01071         printf("table[%"PRIdSIZE"]: position: %d, line: %d, pos: %"PRIdSIZE"\n",
01072                i, table[i].position, table[i].line_no, pos);
01073     }
01074 
01075     if (size == 0) {
01076         return 0;
01077     }
01078     else if (size == 1) {
01079         return &table[0];
01080     }
01081     else {
01082         for (i=1; i<size; i++) {
01083             if (debug) printf("table[%"PRIdSIZE"]: position: %d, line: %d, pos: %"PRIdSIZE"\n",
01084                               i, table[i].position, table[i].line_no, pos);
01085 
01086             if (table[i].position == pos) {
01087                 return &table[i];
01088             }
01089             if (table[i].position > pos) {
01090                 return &table[i-1];
01091             }
01092         }
01093     }
01094     return &table[i-1];
01095 }
01096 
01097 static unsigned int
01098 find_line_no(const rb_iseq_t *iseq, size_t pos)
01099 {
01100     struct iseq_line_info_entry *entry = get_line_info(iseq, pos);
01101     if (entry) {
01102         return entry->line_no;
01103     }
01104     else {
01105         return 0;
01106     }
01107 }
01108 
01109 unsigned int
01110 rb_iseq_line_no(const rb_iseq_t *iseq, size_t pos)
01111 {
01112     if (pos == 0) {
01113         return find_line_no(iseq, pos);
01114     }
01115     else {
01116         return find_line_no(iseq, pos - 1);
01117     }
01118 }
01119 
01120 static VALUE
01121 id_to_name(ID id, VALUE default_value)
01122 {
01123     VALUE str = rb_id2str(id);
01124     if (!str) {
01125         str = default_value;
01126     }
01127     else if (!rb_str_symname_p(str)) {
01128         str = rb_str_inspect(str);
01129     }
01130     return str;
01131 }
01132 
01133 VALUE
01134 insn_operand_intern(rb_iseq_t *iseq,
01135                     VALUE insn, int op_no, VALUE op,
01136                     int len, size_t pos, VALUE *pnop, VALUE child)
01137 {
01138     const char *types = insn_op_types(insn);
01139     char type = types[op_no];
01140     VALUE ret;
01141 
01142     switch (type) {
01143       case TS_OFFSET:           /* LONG */
01144         ret = rb_sprintf("%"PRIdVALUE, (VALUE)(pos + len + op));
01145         break;
01146 
01147       case TS_NUM:              /* ULONG */
01148         ret = rb_sprintf("%"PRIuVALUE, op);
01149         break;
01150 
01151       case TS_LINDEX:{
01152         if (insn == BIN(getlocal) || insn == BIN(setlocal)) {
01153             if (pnop) {
01154                 rb_iseq_t *diseq = iseq;
01155                 VALUE level = *pnop, i;
01156 
01157                 for (i = 0; i < level; i++) {
01158                     diseq = diseq->parent_iseq;
01159                 }
01160                 ret = id_to_name(diseq->local_table[diseq->local_size - op], INT2FIX('*'));
01161             }
01162             else {
01163                 ret = rb_sprintf("%"PRIuVALUE, op);
01164             }
01165         }
01166         else {
01167             ret = rb_inspect(INT2FIX(op));
01168         }
01169         break;
01170       }
01171       case TS_ID:               /* ID (symbol) */
01172         op = ID2SYM(op);
01173 
01174       case TS_VALUE:            /* VALUE */
01175         op = obj_resurrect(op);
01176         ret = rb_inspect(op);
01177         if (CLASS_OF(op) == rb_cISeq) {
01178             if (child) {
01179                 rb_ary_push(child, op);
01180             }
01181         }
01182         break;
01183 
01184       case TS_ISEQ:             /* iseq */
01185         {
01186             rb_iseq_t *iseq = (rb_iseq_t *)op;
01187             if (iseq) {
01188                 ret = iseq->location.label;
01189                 if (child) {
01190                     rb_ary_push(child, iseq->self);
01191                 }
01192             }
01193             else {
01194                 ret = rb_str_new2("nil");
01195             }
01196             break;
01197         }
01198       case TS_GENTRY:
01199         {
01200             struct rb_global_entry *entry = (struct rb_global_entry *)op;
01201             ret = rb_str_dup(rb_id2str(entry->id));
01202         }
01203         break;
01204 
01205       case TS_IC:
01206         ret = rb_sprintf("<ic:%"PRIdPTRDIFF">", (struct iseq_inline_cache_entry *)op - iseq->ic_entries);
01207         break;
01208 
01209       case TS_CALLINFO:
01210         {
01211             rb_call_info_t *ci = (rb_call_info_t *)op;
01212             VALUE ary = rb_ary_new();
01213 
01214             if (ci->mid) {
01215                 rb_ary_push(ary, rb_sprintf("mid:%s", rb_id2name(ci->mid)));
01216             }
01217 
01218             rb_ary_push(ary, rb_sprintf("argc:%d", ci->orig_argc));
01219 
01220             if (ci->blockiseq) {
01221                 if (child) {
01222                     rb_ary_push(child, ci->blockiseq->self);
01223                 }
01224                 rb_ary_push(ary, rb_sprintf("block:%"PRIsVALUE, ci->blockiseq->location.label));
01225             }
01226 
01227             if (ci->flag) {
01228                 VALUE flags = rb_ary_new();
01229                 if (ci->flag & VM_CALL_ARGS_SPLAT) rb_ary_push(flags, rb_str_new2("ARGS_SPLAT"));
01230                 if (ci->flag & VM_CALL_ARGS_BLOCKARG) rb_ary_push(flags, rb_str_new2("ARGS_BLOCKARG"));
01231                 if (ci->flag & VM_CALL_FCALL) rb_ary_push(flags, rb_str_new2("FCALL"));
01232                 if (ci->flag & VM_CALL_VCALL) rb_ary_push(flags, rb_str_new2("VCALL"));
01233                 if (ci->flag & VM_CALL_TAILCALL) rb_ary_push(flags, rb_str_new2("TAILCALL"));
01234                 if (ci->flag & VM_CALL_SUPER) rb_ary_push(flags, rb_str_new2("SUPER"));
01235                 if (ci->flag & VM_CALL_OPT_SEND) rb_ary_push(flags, rb_str_new2("SNED")); /* maybe not reachable */
01236                 if (ci->flag & VM_CALL_ARGS_SKIP_SETUP) rb_ary_push(flags, rb_str_new2("ARGS_SKIP")); /* maybe not reachable */
01237                 rb_ary_push(ary, rb_ary_join(flags, rb_str_new2("|")));
01238             }
01239             ret = rb_sprintf("<callinfo!%"PRIsVALUE">", rb_ary_join(ary, rb_str_new2(", ")));
01240         }
01241         break;
01242 
01243       case TS_CDHASH:
01244         ret = rb_str_new2("<cdhash>");
01245         break;
01246 
01247       case TS_FUNCPTR:
01248         ret = rb_str_new2("<funcptr>");
01249         break;
01250 
01251       default:
01252         rb_bug("insn_operand_intern: unknown operand type: %c", type);
01253     }
01254     return ret;
01255 }
01256 
01261 int
01262 rb_iseq_disasm_insn(VALUE ret, VALUE *iseq, size_t pos,
01263                     rb_iseq_t *iseqdat, VALUE child)
01264 {
01265     VALUE insn = iseq[pos];
01266     int len = insn_len(insn);
01267     int j;
01268     const char *types = insn_op_types(insn);
01269     VALUE str = rb_str_new(0, 0);
01270     const char *insn_name_buff;
01271 
01272     insn_name_buff = insn_name(insn);
01273     if (1) {
01274         rb_str_catf(str, "%04"PRIdSIZE" %-16s ", pos, insn_name_buff);
01275     }
01276     else {
01277         rb_str_catf(str, "%04"PRIdSIZE" %-16.*s ", pos,
01278                     (int)strcspn(insn_name_buff, "_"), insn_name_buff);
01279     }
01280 
01281     for (j = 0; types[j]; j++) {
01282         const char *types = insn_op_types(insn);
01283         VALUE opstr = insn_operand_intern(iseqdat, insn, j, iseq[pos + j + 1],
01284                                           len, pos, &iseq[pos + j + 2],
01285                                           child);
01286         rb_str_concat(str, opstr);
01287 
01288         if (types[j + 1]) {
01289             rb_str_cat2(str, ", ");
01290         }
01291     }
01292 
01293     {
01294         unsigned int line_no = find_line_no(iseqdat, pos);
01295         unsigned int prev = pos == 0 ? 0 : find_line_no(iseqdat, pos - 1);
01296         if (line_no && line_no != prev) {
01297             long slen = RSTRING_LEN(str);
01298             slen = (slen > 70) ? 0 : (70 - slen);
01299             str = rb_str_catf(str, "%*s(%4d)", (int)slen, "", line_no);
01300         }
01301     }
01302 
01303     if (ret) {
01304         rb_str_cat2(str, "\n");
01305         rb_str_concat(ret, str);
01306     }
01307     else {
01308         printf("%s\n", RSTRING_PTR(str));
01309     }
01310     return len;
01311 }
01312 
01313 static const char *
01314 catch_type(int type)
01315 {
01316     switch (type) {
01317       case CATCH_TYPE_RESCUE:
01318         return "rescue";
01319       case CATCH_TYPE_ENSURE:
01320         return "ensure";
01321       case CATCH_TYPE_RETRY:
01322         return "retry";
01323       case CATCH_TYPE_BREAK:
01324         return "break";
01325       case CATCH_TYPE_REDO:
01326         return "redo";
01327       case CATCH_TYPE_NEXT:
01328         return "next";
01329       default:
01330         rb_bug("unknown catch type (%d)", type);
01331         return 0;
01332     }
01333 }
01334 
01335 /*
01336  *  call-seq:
01337  *     iseq.disasm -> str
01338  *     iseq.disassemble -> str
01339  *
01340  *  Returns the instruction sequence as a +String+ in human readable form.
01341  *
01342  *    puts RubyVM::InstructionSequence.compile('1 + 2').disasm
01343  *
01344  *  Produces:
01345  *
01346  *    == disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>==========
01347  *    0000 trace            1                                               (   1)
01348  *    0002 putobject        1
01349  *    0004 putobject        2
01350  *    0006 opt_plus         <ic:1>
01351  *    0008 leave
01352  */
01353 VALUE
01354 rb_iseq_disasm(VALUE self)
01355 {
01356     rb_iseq_t *iseqdat = iseq_check(self);
01357     VALUE *iseq;
01358     VALUE str = rb_str_new(0, 0);
01359     VALUE child = rb_ary_new();
01360     unsigned long size;
01361     int i;
01362     long l;
01363     ID *tbl;
01364     size_t n;
01365     enum {header_minlen = 72};
01366 
01367     rb_secure(1);
01368 
01369     iseq = iseqdat->iseq;
01370     size = iseqdat->iseq_size;
01371 
01372     rb_str_cat2(str, "== disasm: ");
01373 
01374     rb_str_concat(str, iseq_inspect(iseqdat->self));
01375     if ((l = RSTRING_LEN(str)) < header_minlen) {
01376         rb_str_resize(str, header_minlen);
01377         memset(RSTRING_PTR(str) + l, '=', header_minlen - l);
01378     }
01379     rb_str_cat2(str, "\n");
01380 
01381     /* show catch table information */
01382     if (iseqdat->catch_table_size != 0) {
01383         rb_str_cat2(str, "== catch table\n");
01384     }
01385     for (i = 0; i < iseqdat->catch_table_size; i++) {
01386         struct iseq_catch_table_entry *entry = &iseqdat->catch_table[i];
01387         rb_str_catf(str,
01388                     "| catch type: %-6s st: %04d ed: %04d sp: %04d cont: %04d\n",
01389                     catch_type((int)entry->type), (int)entry->start,
01390                     (int)entry->end, (int)entry->sp, (int)entry->cont);
01391         if (entry->iseq) {
01392             rb_str_concat(str, rb_iseq_disasm(entry->iseq));
01393         }
01394     }
01395     if (iseqdat->catch_table_size != 0) {
01396         rb_str_cat2(str, "|-------------------------------------"
01397                     "-----------------------------------\n");
01398     }
01399 
01400     /* show local table information */
01401     tbl = iseqdat->local_table;
01402 
01403     if (tbl) {
01404         rb_str_catf(str,
01405                     "local table (size: %d, argc: %d "
01406                     "[opts: %d, rest: %d, post: %d, block: %d] s%d)\n",
01407                     iseqdat->local_size, iseqdat->argc,
01408                     iseqdat->arg_opts, iseqdat->arg_rest,
01409                     iseqdat->arg_post_len, iseqdat->arg_block,
01410                     iseqdat->arg_simple);
01411 
01412         for (i = 0; i < iseqdat->local_table_size; i++) {
01413             long width;
01414             VALUE name = id_to_name(tbl[i], 0);
01415             char argi[0x100] = "";
01416             char opti[0x100] = "";
01417 
01418             if (iseqdat->arg_opts) {
01419                 int argc = iseqdat->argc;
01420                 int opts = iseqdat->arg_opts;
01421                 if (i >= argc && i < argc + opts - 1) {
01422                     snprintf(opti, sizeof(opti), "Opt=%"PRIdVALUE,
01423                              iseqdat->arg_opt_table[i - argc]);
01424                 }
01425             }
01426 
01427             snprintf(argi, sizeof(argi), "%s%s%s%s%s",  /* arg, opts, rest, post  block */
01428                      iseqdat->argc > i ? "Arg" : "",
01429                      opti,
01430                      iseqdat->arg_rest == i ? "Rest" : "",
01431                      (iseqdat->arg_post_start <= i &&
01432                       i < iseqdat->arg_post_start + iseqdat->arg_post_len) ? "Post" : "",
01433                      iseqdat->arg_block == i ? "Block" : "");
01434 
01435             rb_str_catf(str, "[%2d] ", iseqdat->local_size - i);
01436             width = RSTRING_LEN(str) + 11;
01437             if (name)
01438                 rb_str_append(str, name);
01439             else
01440                 rb_str_cat2(str, "?");
01441             if (*argi) rb_str_catf(str, "<%s>", argi);
01442             if ((width -= RSTRING_LEN(str)) > 0) rb_str_catf(str, "%*s", (int)width, "");
01443         }
01444         rb_str_cat2(str, "\n");
01445     }
01446 
01447     /* show each line */
01448     for (n = 0; n < size;) {
01449         n += rb_iseq_disasm_insn(str, iseq, n, iseqdat, child);
01450     }
01451 
01452     for (i = 0; i < RARRAY_LEN(child); i++) {
01453         VALUE isv = rb_ary_entry(child, i);
01454         rb_str_concat(str, rb_iseq_disasm(isv));
01455     }
01456 
01457     return str;
01458 }
01459 
01460 /*
01461  *  Returns the instruction sequence containing the given proc or method.
01462  *
01463  *  For example, using irb:
01464  *
01465  *      # a proc
01466  *      > p = proc { num = 1 + 2 }
01467  *      > RubyVM::InstructionSequence.of(p)
01468  *      > #=> <RubyVM::InstructionSequence:block in irb_binding@(irb)>
01469  *
01470  *      # for a method
01471  *      > def foo(bar); puts bar; end
01472  *      > RubyVM::InstructionSequence.of(method(:foo))
01473  *      > #=> <RubyVM::InstructionSequence:foo@(irb)>
01474  *
01475  *  Using ::compile_file:
01476  *
01477  *      # /tmp/iseq_of.rb
01478  *      def hello
01479  *        puts "hello, world"
01480  *      end
01481  *
01482  *      $a_global_proc = proc { str = 'a' + 'b' }
01483  *
01484  *      # in irb
01485  *      > require '/tmp/iseq_of.rb'
01486  *
01487  *      # first the method hello
01488  *      > RubyVM::InstructionSequence.of(method(:hello))
01489  *      > #=> #<RubyVM::InstructionSequence:0x007fb73d7cb1d0>
01490  *
01491  *      # then the global proc
01492  *      > RubyVM::InstructionSequence.of($a_global_proc)
01493  *      > #=> #<RubyVM::InstructionSequence:0x007fb73d7caf78>
01494  */
01495 static VALUE
01496 iseq_s_of(VALUE klass, VALUE body)
01497 {
01498     VALUE ret = Qnil;
01499     rb_iseq_t *iseq;
01500 
01501     rb_secure(1);
01502 
01503     if (rb_obj_is_proc(body)) {
01504         rb_proc_t *proc;
01505         GetProcPtr(body, proc);
01506         iseq = proc->block.iseq;
01507         if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
01508             ret = iseq->self;
01509         }
01510     }
01511     else if ((iseq = rb_method_get_iseq(body)) != 0) {
01512         ret = iseq->self;
01513     }
01514     return ret;
01515 }
01516 
01517 /*
01518  *  call-seq:
01519  *     InstructionSequence.disasm(body) -> str
01520  *     InstructionSequence.disassemble(body) -> str
01521  *
01522  *  Takes +body+, a Method or Proc object, and returns a String with the
01523  *  human readable instructions for +body+.
01524  *
01525  *  For a Method object:
01526  *
01527  *    # /tmp/method.rb
01528  *    def hello
01529  *      puts "hello, world"
01530  *    end
01531  *
01532  *    puts RubyVM::InstructionSequence.disasm(method(:hello))
01533  *
01534  *  Produces:
01535  *
01536  *    == disasm: <RubyVM::InstructionSequence:hello@/tmp/method.rb>============
01537  *    0000 trace            8                                               (   1)
01538  *    0002 trace            1                                               (   2)
01539  *    0004 putself
01540  *    0005 putstring        "hello, world"
01541  *    0007 send             :puts, 1, nil, 8, <ic:0>
01542  *    0013 trace            16                                              (   3)
01543  *    0015 leave                                                            (   2)
01544  *
01545  *  For a Proc:
01546  *
01547  *    # /tmp/proc.rb
01548  *    p = proc { num = 1 + 2 }
01549  *    puts RubyVM::InstructionSequence.disasm(p)
01550  *
01551  *  Produces:
01552  *
01553  *    == disasm: <RubyVM::InstructionSequence:block in <main>@/tmp/proc.rb>===
01554  *    == catch table
01555  *    | catch type: redo   st: 0000 ed: 0012 sp: 0000 cont: 0000
01556  *    | catch type: next   st: 0000 ed: 0012 sp: 0000 cont: 0012
01557  *    |------------------------------------------------------------------------
01558  *    local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1] s1)
01559  *    [ 2] num
01560  *    0000 trace            1                                               (   1)
01561  *    0002 putobject        1
01562  *    0004 putobject        2
01563  *    0006 opt_plus         <ic:1>
01564  *    0008 dup
01565  *    0009 setlocal         num, 0
01566  *    0012 leave
01567  *
01568  */
01569 
01570 static VALUE
01571 iseq_s_disasm(VALUE klass, VALUE body)
01572 {
01573     VALUE iseqval = iseq_s_of(klass, body);
01574     return NIL_P(iseqval) ? Qnil : rb_iseq_disasm(iseqval);
01575 }
01576 
01577 const char *
01578 ruby_node_name(int node)
01579 {
01580     switch (node) {
01581 #include "node_name.inc"
01582       default:
01583         rb_bug("unknown node (%d)", node);
01584         return 0;
01585     }
01586 }
01587 
01588 #define DECL_SYMBOL(name) \
01589   static VALUE sym_##name
01590 
01591 #define INIT_SYMBOL(name) \
01592   sym_##name = ID2SYM(rb_intern(#name))
01593 
01594 static VALUE
01595 register_label(struct st_table *table, unsigned long idx)
01596 {
01597     VALUE sym;
01598     char buff[8 + (sizeof(idx) * CHAR_BIT * 32 / 100)];
01599 
01600     snprintf(buff, sizeof(buff), "label_%lu", idx);
01601     sym = ID2SYM(rb_intern(buff));
01602     st_insert(table, idx, sym);
01603     return sym;
01604 }
01605 
01606 static VALUE
01607 exception_type2symbol(VALUE type)
01608 {
01609     ID id;
01610     switch (type) {
01611       case CATCH_TYPE_RESCUE: CONST_ID(id, "rescue"); break;
01612       case CATCH_TYPE_ENSURE: CONST_ID(id, "ensure"); break;
01613       case CATCH_TYPE_RETRY:  CONST_ID(id, "retry");  break;
01614       case CATCH_TYPE_BREAK:  CONST_ID(id, "break");  break;
01615       case CATCH_TYPE_REDO:   CONST_ID(id, "redo");   break;
01616       case CATCH_TYPE_NEXT:   CONST_ID(id, "next");   break;
01617       default:
01618         rb_bug("...");
01619     }
01620     return ID2SYM(id);
01621 }
01622 
01623 static int
01624 cdhash_each(VALUE key, VALUE value, VALUE ary)
01625 {
01626     rb_ary_push(ary, obj_resurrect(key));
01627     rb_ary_push(ary, value);
01628     return ST_CONTINUE;
01629 }
01630 
01631 static VALUE
01632 iseq_data_to_ary(rb_iseq_t *iseq)
01633 {
01634     long i;
01635     size_t ti;
01636     unsigned int pos;
01637     unsigned int line = 0;
01638     VALUE *seq;
01639 
01640     VALUE val = rb_ary_new();
01641     VALUE type; /* Symbol */
01642     VALUE locals = rb_ary_new();
01643     VALUE args = rb_ary_new();
01644     VALUE body = rb_ary_new(); /* [[:insn1, ...], ...] */
01645     VALUE nbody;
01646     VALUE exception = rb_ary_new(); /* [[....]] */
01647     VALUE misc = rb_hash_new();
01648 
01649     static VALUE insn_syms[VM_INSTRUCTION_SIZE];
01650     struct st_table *labels_table = st_init_numtable();
01651 
01652     DECL_SYMBOL(top);
01653     DECL_SYMBOL(method);
01654     DECL_SYMBOL(block);
01655     DECL_SYMBOL(class);
01656     DECL_SYMBOL(rescue);
01657     DECL_SYMBOL(ensure);
01658     DECL_SYMBOL(eval);
01659     DECL_SYMBOL(main);
01660     DECL_SYMBOL(defined_guard);
01661 
01662     if (sym_top == 0) {
01663         int i;
01664         for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
01665             insn_syms[i] = ID2SYM(rb_intern(insn_name(i)));
01666         }
01667         INIT_SYMBOL(top);
01668         INIT_SYMBOL(method);
01669         INIT_SYMBOL(block);
01670         INIT_SYMBOL(class);
01671         INIT_SYMBOL(rescue);
01672         INIT_SYMBOL(ensure);
01673         INIT_SYMBOL(eval);
01674         INIT_SYMBOL(main);
01675         INIT_SYMBOL(defined_guard);
01676     }
01677 
01678     /* type */
01679     switch (iseq->type) {
01680       case ISEQ_TYPE_TOP:    type = sym_top;    break;
01681       case ISEQ_TYPE_METHOD: type = sym_method; break;
01682       case ISEQ_TYPE_BLOCK:  type = sym_block;  break;
01683       case ISEQ_TYPE_CLASS:  type = sym_class;  break;
01684       case ISEQ_TYPE_RESCUE: type = sym_rescue; break;
01685       case ISEQ_TYPE_ENSURE: type = sym_ensure; break;
01686       case ISEQ_TYPE_EVAL:   type = sym_eval;   break;
01687       case ISEQ_TYPE_MAIN:   type = sym_main;   break;
01688       case ISEQ_TYPE_DEFINED_GUARD: type = sym_defined_guard; break;
01689       default: rb_bug("unsupported iseq type");
01690     };
01691 
01692     /* locals */
01693     for (i=0; i<iseq->local_table_size; i++) {
01694         ID lid = iseq->local_table[i];
01695         if (lid) {
01696             if (rb_id2str(lid)) rb_ary_push(locals, ID2SYM(lid));
01697         }
01698         else {
01699             rb_ary_push(locals, ID2SYM(rb_intern("#arg_rest")));
01700         }
01701     }
01702 
01703     /* args */
01704     {
01705         /*
01706          * [argc,                 # argc
01707          *  [label1, label2, ...] # opts
01708          *  rest index,
01709          *  post_len
01710          *  post_start
01711          *  block index,
01712          *  simple,
01713          * ]
01714          */
01715         VALUE arg_opt_labels = rb_ary_new();
01716         int j;
01717 
01718         for (j=0; j<iseq->arg_opts; j++) {
01719             rb_ary_push(arg_opt_labels,
01720                         register_label(labels_table, iseq->arg_opt_table[j]));
01721         }
01722 
01723         /* commit */
01724         if (iseq->arg_simple == 1) {
01725             args = INT2FIX(iseq->argc);
01726         }
01727         else {
01728             rb_ary_push(args, INT2FIX(iseq->argc));
01729             rb_ary_push(args, arg_opt_labels);
01730             rb_ary_push(args, INT2FIX(iseq->arg_post_len));
01731             rb_ary_push(args, INT2FIX(iseq->arg_post_start));
01732             rb_ary_push(args, INT2FIX(iseq->arg_rest));
01733             rb_ary_push(args, INT2FIX(iseq->arg_block));
01734             rb_ary_push(args, INT2FIX(iseq->arg_simple));
01735         }
01736     }
01737 
01738     /* body */
01739     for (seq = iseq->iseq; seq < iseq->iseq + iseq->iseq_size; ) {
01740         VALUE insn = *seq++;
01741         int j, len = insn_len(insn);
01742         VALUE *nseq = seq + len - 1;
01743         VALUE ary = rb_ary_new2(len);
01744 
01745         rb_ary_push(ary, insn_syms[insn]);
01746         for (j=0; j<len-1; j++, seq++) {
01747             switch (insn_op_type(insn, j)) {
01748               case TS_OFFSET: {
01749                 unsigned long idx = nseq - iseq->iseq + *seq;
01750                 rb_ary_push(ary, register_label(labels_table, idx));
01751                 break;
01752               }
01753               case TS_LINDEX:
01754               case TS_NUM:
01755                 rb_ary_push(ary, INT2FIX(*seq));
01756                 break;
01757               case TS_VALUE:
01758                 rb_ary_push(ary, obj_resurrect(*seq));
01759                 break;
01760               case TS_ISEQ:
01761                 {
01762                     rb_iseq_t *iseq = (rb_iseq_t *)*seq;
01763                     if (iseq) {
01764                         VALUE val = iseq_data_to_ary(iseq);
01765                         rb_ary_push(ary, val);
01766                     }
01767                     else {
01768                         rb_ary_push(ary, Qnil);
01769                     }
01770                 }
01771                 break;
01772               case TS_GENTRY:
01773                 {
01774                     struct rb_global_entry *entry = (struct rb_global_entry *)*seq;
01775                     rb_ary_push(ary, ID2SYM(entry->id));
01776                 }
01777                 break;
01778               case TS_IC: {
01779                   struct iseq_inline_cache_entry *ic = (struct iseq_inline_cache_entry *)*seq;
01780                     rb_ary_push(ary, INT2FIX(ic - iseq->ic_entries));
01781                 }
01782                 break;
01783               case TS_CALLINFO:
01784                 {
01785                     rb_call_info_t *ci = (rb_call_info_t *)*seq;
01786                     VALUE e = rb_hash_new();
01787                     rb_hash_aset(e, ID2SYM(rb_intern("mid")), ci->mid ? ID2SYM(ci->mid) : Qnil);
01788                     rb_hash_aset(e, ID2SYM(rb_intern("flag")), ULONG2NUM(ci->flag));
01789                     rb_hash_aset(e, ID2SYM(rb_intern("orig_argc")), INT2FIX(ci->orig_argc));
01790                     rb_hash_aset(e, ID2SYM(rb_intern("blockptr")), ci->blockiseq ? iseq_data_to_ary(ci->blockiseq) : Qnil);
01791                     rb_ary_push(ary, e);
01792                 }
01793                 break;
01794               case TS_ID:
01795                 rb_ary_push(ary, ID2SYM(*seq));
01796                 break;
01797               case TS_CDHASH:
01798                 {
01799                     VALUE hash = *seq;
01800                     VALUE val = rb_ary_new();
01801                     int i;
01802 
01803                     rb_hash_foreach(hash, cdhash_each, val);
01804 
01805                     for (i=0; i<RARRAY_LEN(val); i+=2) {
01806                         VALUE pos = FIX2INT(rb_ary_entry(val, i+1));
01807                         unsigned long idx = nseq - iseq->iseq + pos;
01808 
01809                         rb_ary_store(val, i+1,
01810                                      register_label(labels_table, idx));
01811                     }
01812                     rb_ary_push(ary, val);
01813                 }
01814                 break;
01815               default:
01816                 rb_bug("unknown operand: %c", insn_op_type(insn, j));
01817             }
01818         }
01819         rb_ary_push(body, ary);
01820     }
01821 
01822     nbody = body;
01823 
01824     /* exception */
01825     for (i=0; i<iseq->catch_table_size; i++) {
01826         VALUE ary = rb_ary_new();
01827         struct iseq_catch_table_entry *entry = &iseq->catch_table[i];
01828         rb_ary_push(ary, exception_type2symbol(entry->type));
01829         if (entry->iseq) {
01830             rb_iseq_t *eiseq;
01831             GetISeqPtr(entry->iseq, eiseq);
01832             rb_ary_push(ary, iseq_data_to_ary(eiseq));
01833         }
01834         else {
01835             rb_ary_push(ary, Qnil);
01836         }
01837         rb_ary_push(ary, register_label(labels_table, entry->start));
01838         rb_ary_push(ary, register_label(labels_table, entry->end));
01839         rb_ary_push(ary, register_label(labels_table, entry->cont));
01840         rb_ary_push(ary, INT2FIX(entry->sp));
01841         rb_ary_push(exception, ary);
01842     }
01843 
01844     /* make body with labels and insert line number */
01845     body = rb_ary_new();
01846     ti = 0;
01847 
01848     for (i=0, pos=0; i<RARRAY_LEN(nbody); i++) {
01849         VALUE ary = RARRAY_PTR(nbody)[i];
01850         st_data_t label;
01851 
01852         if (st_lookup(labels_table, pos, &label)) {
01853             rb_ary_push(body, (VALUE)label);
01854         }
01855 
01856         if (ti < iseq->line_info_size && iseq->line_info_table[ti].position == pos) {
01857             line = iseq->line_info_table[ti].line_no;
01858             rb_ary_push(body, INT2FIX(line));
01859             ti++;
01860         }
01861 
01862         rb_ary_push(body, ary);
01863         pos += RARRAY_LENINT(ary); /* reject too huge data */
01864     }
01865 
01866     st_free_table(labels_table);
01867 
01868     rb_hash_aset(misc, ID2SYM(rb_intern("arg_size")), INT2FIX(iseq->arg_size));
01869     rb_hash_aset(misc, ID2SYM(rb_intern("local_size")), INT2FIX(iseq->local_size));
01870     rb_hash_aset(misc, ID2SYM(rb_intern("stack_max")), INT2FIX(iseq->stack_max));
01871 
01872     /* TODO: compatibility issue */
01873     /*
01874      * [:magic, :major_version, :minor_version, :format_type, :misc,
01875      *  :name, :path, :absolute_path, :start_lineno, :type, :locals, :args,
01876      *  :catch_table, :bytecode]
01877      */
01878     rb_ary_push(val, rb_str_new2("YARVInstructionSequence/SimpleDataFormat"));
01879     rb_ary_push(val, INT2FIX(ISEQ_MAJOR_VERSION)); /* major */
01880     rb_ary_push(val, INT2FIX(ISEQ_MINOR_VERSION)); /* minor */
01881     rb_ary_push(val, INT2FIX(1));
01882     rb_ary_push(val, misc);
01883     rb_ary_push(val, iseq->location.label);
01884     rb_ary_push(val, iseq->location.path);
01885     rb_ary_push(val, iseq->location.absolute_path);
01886     rb_ary_push(val, iseq->location.first_lineno);
01887     rb_ary_push(val, type);
01888     rb_ary_push(val, locals);
01889     rb_ary_push(val, args);
01890     rb_ary_push(val, exception);
01891     rb_ary_push(val, body);
01892     return val;
01893 }
01894 
01895 VALUE
01896 rb_iseq_clone(VALUE iseqval, VALUE newcbase)
01897 {
01898     VALUE newiseq = iseq_alloc(rb_cISeq);
01899     rb_iseq_t *iseq0, *iseq1;
01900 
01901     GetISeqPtr(iseqval, iseq0);
01902     GetISeqPtr(newiseq, iseq1);
01903 
01904     *iseq1 = *iseq0;
01905     iseq1->self = newiseq;
01906     if (!iseq1->orig) {
01907         iseq1->orig = iseqval;
01908     }
01909     if (iseq0->local_iseq == iseq0) {
01910         iseq1->local_iseq = iseq1;
01911     }
01912     if (newcbase) {
01913         iseq1->cref_stack = NEW_CREF(newcbase);
01914         iseq1->cref_stack->nd_refinements = iseq0->cref_stack->nd_refinements;
01915         iseq1->cref_stack->nd_visi = iseq0->cref_stack->nd_visi;
01916         if (iseq0->cref_stack->nd_next) {
01917             iseq1->cref_stack->nd_next = iseq0->cref_stack->nd_next;
01918         }
01919         iseq1->klass = newcbase;
01920     }
01921 
01922     return newiseq;
01923 }
01924 
01925 VALUE
01926 rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
01927 {
01928     int i, r;
01929     VALUE a, args = rb_ary_new2(iseq->arg_size);
01930     ID req, opt, rest, block, key, keyrest;
01931 #define PARAM_TYPE(type) rb_ary_push(a = rb_ary_new2(2), ID2SYM(type))
01932 #define PARAM_ID(i) iseq->local_table[(i)]
01933 #define PARAM(i, type) (                      \
01934         PARAM_TYPE(type),                     \
01935         rb_id2str(PARAM_ID(i)) ?              \
01936         rb_ary_push(a, ID2SYM(PARAM_ID(i))) : \
01937         a)
01938 
01939     CONST_ID(req, "req");
01940     CONST_ID(opt, "opt");
01941     if (is_proc) {
01942         for (i = 0; i < iseq->argc; i++) {
01943             PARAM_TYPE(opt);
01944             rb_ary_push(a, rb_id2str(PARAM_ID(i)) ? ID2SYM(PARAM_ID(i)) : Qnil);
01945             rb_ary_push(args, a);
01946         }
01947     }
01948     else {
01949         for (i = 0; i < iseq->argc; i++) {
01950             rb_ary_push(args, PARAM(i, req));
01951         }
01952     }
01953     r = iseq->argc + iseq->arg_opts - 1;
01954     for (; i < r; i++) {
01955         PARAM_TYPE(opt);
01956         if (rb_id2str(PARAM_ID(i))) {
01957             rb_ary_push(a, ID2SYM(PARAM_ID(i)));
01958         }
01959         rb_ary_push(args, a);
01960     }
01961     if (iseq->arg_rest != -1) {
01962         CONST_ID(rest, "rest");
01963         rb_ary_push(args, PARAM(iseq->arg_rest, rest));
01964     }
01965     r = iseq->arg_post_start + iseq->arg_post_len;
01966     if (is_proc) {
01967         for (i = iseq->arg_post_start; i < r; i++) {
01968             PARAM_TYPE(opt);
01969             rb_ary_push(a, rb_id2str(PARAM_ID(i)) ? ID2SYM(PARAM_ID(i)) : Qnil);
01970             rb_ary_push(args, a);
01971         }
01972     }
01973     else {
01974         for (i = iseq->arg_post_start; i < r; i++) {
01975             rb_ary_push(args, PARAM(i, req));
01976         }
01977     }
01978     if (iseq->arg_keyword != -1) {
01979         CONST_ID(key, "key");
01980         for (i = 0; i < iseq->arg_keywords; i++) {
01981             PARAM_TYPE(key);
01982             if (rb_id2str(iseq->arg_keyword_table[i])) {
01983                 rb_ary_push(a, ID2SYM(iseq->arg_keyword_table[i]));
01984             }
01985             rb_ary_push(args, a);
01986         }
01987         if (rb_id2str(iseq->local_table[iseq->arg_keyword])) {
01988             CONST_ID(keyrest, "keyrest");
01989             rb_ary_push(args, PARAM(iseq->arg_keyword, keyrest));
01990         }
01991     }
01992     if (iseq->arg_block != -1) {
01993         CONST_ID(block, "block");
01994         rb_ary_push(args, PARAM(iseq->arg_block, block));
01995     }
01996     return args;
01997 }
01998 
01999 VALUE
02000 rb_iseq_defined_string(enum defined_type type)
02001 {
02002     static const char expr_names[][18] = {
02003         "nil",
02004         "instance-variable",
02005         "local-variable",
02006         "global-variable",
02007         "class variable",
02008         "constant",
02009         "method",
02010         "yield",
02011         "super",
02012         "self",
02013         "true",
02014         "false",
02015         "assignment",
02016         "expression",
02017     };
02018     const char *estr;
02019     VALUE *defs, str;
02020 
02021     if ((unsigned)(type - 1) >= (unsigned)numberof(expr_names)) return 0;
02022     estr = expr_names[type - 1];
02023     if (!estr[0]) return 0;
02024     defs = GET_VM()->defined_strings;
02025     if (!defs) {
02026         defs = ruby_xcalloc(numberof(expr_names), sizeof(VALUE));
02027         GET_VM()->defined_strings = defs;
02028     }
02029     str = defs[type-1];
02030     if (!str) {
02031         str = rb_str_new_cstr(estr);;
02032         OBJ_FREEZE(str);
02033         defs[type-1] = str;
02034     }
02035     return str;
02036 }
02037 
02038 /* ruby2cext */
02039 
02040 VALUE
02041 rb_iseq_build_for_ruby2cext(
02042     const rb_iseq_t *iseq_template,
02043     const rb_insn_func_t *func,
02044     const struct iseq_line_info_entry *line_info_table,
02045     const char **local_table,
02046     const VALUE *arg_opt_table,
02047     const struct iseq_catch_table_entry *catch_table,
02048     const char *name,
02049     const char *path,
02050     const unsigned short first_lineno)
02051 {
02052     unsigned long i;
02053     VALUE iseqval = iseq_alloc(rb_cISeq);
02054     rb_iseq_t *iseq;
02055     GetISeqPtr(iseqval, iseq);
02056 
02057     /* copy iseq */
02058     *iseq = *iseq_template;
02059     iseq->location.label = rb_str_new2(name);
02060     iseq->location.path = rb_str_new2(path);
02061     iseq->location.first_lineno = first_lineno;
02062     iseq->mark_ary = 0;
02063     iseq->self = iseqval;
02064 
02065     iseq->iseq = ALLOC_N(VALUE, iseq->iseq_size);
02066 
02067     for (i=0; i<iseq->iseq_size; i+=2) {
02068         iseq->iseq[i] = BIN(opt_call_c_function);
02069         iseq->iseq[i+1] = (VALUE)func;
02070     }
02071 
02072     rb_iseq_translate_threaded_code(iseq);
02073 
02074 #define ALLOC_AND_COPY(dst, src, type, size) do { \
02075   if (size) { \
02076       (dst) = ALLOC_N(type, (size)); \
02077       MEMCPY((dst), (src), type, (size)); \
02078   } \
02079 } while (0)
02080 
02081     ALLOC_AND_COPY(iseq->line_info_table, line_info_table,
02082                    struct iseq_line_info_entry, iseq->line_info_size);
02083 
02084     ALLOC_AND_COPY(iseq->catch_table, catch_table,
02085                    struct iseq_catch_table_entry, iseq->catch_table_size);
02086 
02087     ALLOC_AND_COPY(iseq->arg_opt_table, arg_opt_table,
02088                    VALUE, iseq->arg_opts);
02089 
02090     set_relation(iseq, 0);
02091 
02092     return iseqval;
02093 }
02094 
02095 /* Experimental tracing support: trace(line) -> trace(specified_line)
02096  * MRI Specific.
02097  */
02098 
02099 int
02100 rb_iseq_line_trace_each(VALUE iseqval, int (*func)(int line, rb_event_flag_t *events_ptr, void *d), void *data)
02101 {
02102     int trace_num = 0;
02103     size_t pos, insn;
02104     rb_iseq_t *iseq;
02105     int cont = 1;
02106     GetISeqPtr(iseqval, iseq);
02107 
02108     for (pos = 0; cont && pos < iseq->iseq_size; pos += insn_len(insn)) {
02109         insn = iseq->iseq[pos];
02110 
02111         if (insn == BIN(trace)) {
02112             rb_event_flag_t current_events = (VALUE)iseq->iseq[pos+1];
02113 
02114             if (current_events & RUBY_EVENT_LINE) {
02115                 rb_event_flag_t events = current_events & RUBY_EVENT_SPECIFIED_LINE;
02116                 trace_num++;
02117 
02118                 if (func) {
02119                     int line = find_line_no(iseq, pos);
02120                     /* printf("line: %d\n", line); */
02121                     cont = (*func)(line, &events, data);
02122                     if (current_events != events) {
02123                         iseq->iseq[pos+1] = iseq->iseq_encoded[pos+1] =
02124                           (VALUE)(current_events | (events & RUBY_EVENT_SPECIFIED_LINE));
02125                     }
02126                 }
02127             }
02128         }
02129     }
02130     return trace_num;
02131 }
02132 
02133 static int
02134 collect_trace(int line, rb_event_flag_t *events_ptr, void *ptr)
02135 {
02136     VALUE result = (VALUE)ptr;
02137     rb_ary_push(result, INT2NUM(line));
02138     return 1;
02139 }
02140 
02141 /*
02142  * <b>Experimental MRI specific feature, only available as C level api.</b>
02143  *
02144  * Returns all +specified_line+ events.
02145  */
02146 VALUE
02147 rb_iseq_line_trace_all(VALUE iseqval)
02148 {
02149     VALUE result = rb_ary_new();
02150     rb_iseq_line_trace_each(iseqval, collect_trace, (void *)result);
02151     return result;
02152 }
02153 
02154 struct set_specifc_data {
02155     int pos;
02156     int set;
02157     int prev; /* 1: set, 2: unset, 0: not found */
02158 };
02159 
02160 static int
02161 line_trace_specify(int line, rb_event_flag_t *events_ptr, void *ptr)
02162 {
02163     struct set_specifc_data *data = (struct set_specifc_data *)ptr;
02164 
02165     if (data->pos == 0) {
02166         data->prev = *events_ptr & RUBY_EVENT_SPECIFIED_LINE ? 1 : 2;
02167         if (data->set) {
02168             *events_ptr = *events_ptr | RUBY_EVENT_SPECIFIED_LINE;
02169         }
02170         else {
02171             *events_ptr = *events_ptr & ~RUBY_EVENT_SPECIFIED_LINE;
02172         }
02173         return 0; /* found */
02174     }
02175     else {
02176         data->pos--;
02177         return 1;
02178     }
02179 }
02180 
02181 /*
02182  * <b>Experimental MRI specific feature, only available as C level api.</b>
02183  *
02184  * Set a +specified_line+ event at the given line position, if the +set+
02185  * parameter is +true+.
02186  *
02187  * This method is useful for building a debugger breakpoint at a specific line.
02188  *
02189  * A TypeError is raised if +set+ is not boolean.
02190  *
02191  * If +pos+ is a negative integer a TypeError exception is raised.
02192  */
02193 VALUE
02194 rb_iseq_line_trace_specify(VALUE iseqval, VALUE pos, VALUE set)
02195 {
02196     struct set_specifc_data data;
02197 
02198     data.prev = 0;
02199     data.pos = NUM2INT(pos);
02200     if (data.pos < 0) rb_raise(rb_eTypeError, "`pos' is negative");
02201 
02202     switch (set) {
02203       case Qtrue:  data.set = 1; break;
02204       case Qfalse: data.set = 0; break;
02205       default:
02206         rb_raise(rb_eTypeError, "`set' should be true/false");
02207     }
02208 
02209     rb_iseq_line_trace_each(iseqval, line_trace_specify, (void *)&data);
02210 
02211     if (data.prev == 0) {
02212         rb_raise(rb_eTypeError, "`pos' is out of range.");
02213     }
02214     return data.prev == 1 ? Qtrue : Qfalse;
02215 }
02216 
02217 /*
02218  *  Document-class: RubyVM::InstructionSequence
02219  *
02220  *  The InstructionSequence class represents a compiled sequence of
02221  *  instructions for the Ruby Virtual Machine.
02222  *
02223  *  With it, you can get a handle to the instructions that make up a method or
02224  *  a proc, compile strings of Ruby code down to VM instructions, and
02225  *  disassemble instruction sequences to strings for easy inspection. It is
02226  *  mostly useful if you want to learn how the Ruby VM works, but it also lets
02227  *  you control various settings for the Ruby iseq compiler.
02228  *
02229  *  You can find the source for the VM instructions in +insns.def+ in the Ruby
02230  *  source.
02231  *
02232  *  The instruction sequence results will almost certainly change as Ruby
02233  *  changes, so example output in this documentation may be different from what
02234  *  you see.
02235  */
02236 
02237 void
02238 Init_ISeq(void)
02239 {
02240     /* declare ::RubyVM::InstructionSequence */
02241     rb_cISeq = rb_define_class_under(rb_cRubyVM, "InstructionSequence", rb_cObject);
02242     rb_define_alloc_func(rb_cISeq, iseq_alloc);
02243     rb_define_method(rb_cISeq, "inspect", iseq_inspect, 0);
02244     rb_define_method(rb_cISeq, "disasm", rb_iseq_disasm, 0);
02245     rb_define_method(rb_cISeq, "disassemble", rb_iseq_disasm, 0);
02246     rb_define_method(rb_cISeq, "to_a", iseq_to_a, 0);
02247     rb_define_method(rb_cISeq, "eval", iseq_eval, 0);
02248 
02249     /* location APIs */
02250     rb_define_method(rb_cISeq, "path", iseq_path, 0);
02251     rb_define_method(rb_cISeq, "absolute_path", iseq_absolute_path, 0);
02252     rb_define_method(rb_cISeq, "label", iseq_label, 0);
02253     rb_define_method(rb_cISeq, "base_label", iseq_base_label, 0);
02254     rb_define_method(rb_cISeq, "first_lineno", iseq_first_lineno, 0);
02255 
02256 #if 0
02257     /* Now, it is experimental. No discussions, no tests. */
02258     /* They can be used from C level. Please give us feedback. */
02259     rb_define_method(rb_cISeq, "line_trace_all", rb_iseq_line_trace_all, 0);
02260     rb_define_method(rb_cISeq, "line_trace_specify", rb_iseq_line_trace_specify, 2);
02261 #else
02262     (void)rb_iseq_line_trace_all;
02263     (void)rb_iseq_line_trace_specify;
02264 #endif
02265 
02266 #if 0 /* TBD */
02267     rb_define_private_method(rb_cISeq, "marshal_dump", iseq_marshal_dump, 0);
02268     rb_define_private_method(rb_cISeq, "marshal_load", iseq_marshal_load, 1);
02269 #endif
02270 
02271     /* disable this feature because there is no verifier. */
02272     /* rb_define_singleton_method(rb_cISeq, "load", iseq_s_load, -1); */
02273     (void)iseq_s_load;
02274 
02275     rb_define_singleton_method(rb_cISeq, "compile", iseq_s_compile, -1);
02276     rb_define_singleton_method(rb_cISeq, "new", iseq_s_compile, -1);
02277     rb_define_singleton_method(rb_cISeq, "compile_file", iseq_s_compile_file, -1);
02278     rb_define_singleton_method(rb_cISeq, "compile_option", iseq_s_compile_option_get, 0);
02279     rb_define_singleton_method(rb_cISeq, "compile_option=", iseq_s_compile_option_set, 1);
02280     rb_define_singleton_method(rb_cISeq, "disasm", iseq_s_disasm, 1);
02281     rb_define_singleton_method(rb_cISeq, "disassemble", iseq_s_disasm, 1);
02282     rb_define_singleton_method(rb_cISeq, "of", iseq_s_of, 1);
02283 }
02284