Ruby  1.9.3p537(2014-02-19revision0)
iseq.c
Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   iseq.c -
00004 
00005   $Author$
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 
00015 /* #define RUBY_MARK_FREE_DEBUG 1 */
00016 #include "gc.h"
00017 #include "vm_core.h"
00018 #include "iseq.h"
00019 
00020 #include "insns.inc"
00021 #include "insns_info.inc"
00022 
00023 #define ISEQ_MAJOR_VERSION 1
00024 #define ISEQ_MINOR_VERSION 2
00025 
00026 VALUE rb_cISeq;
00027 
00028 #define hidden_obj_p(obj) (!SPECIAL_CONST_P(obj) && !RBASIC(obj)->klass)
00029 
00030 static inline VALUE
00031 obj_resurrect(VALUE obj)
00032 {
00033     if (hidden_obj_p(obj)) {
00034         switch (BUILTIN_TYPE(obj)) {
00035           case T_STRING:
00036             obj = rb_str_resurrect(obj);
00037             break;
00038           case T_ARRAY:
00039             obj = rb_ary_resurrect(obj);
00040             break;
00041         }
00042     }
00043     return obj;
00044 }
00045 
00046 static void
00047 compile_data_free(struct iseq_compile_data *compile_data)
00048 {
00049     if (compile_data) {
00050         struct iseq_compile_data_storage *cur, *next;
00051         cur = compile_data->storage_head;
00052         while (cur) {
00053             next = cur->next;
00054             ruby_xfree(cur);
00055             cur = next;
00056         }
00057         ruby_xfree(compile_data);
00058     }
00059 }
00060 
00061 static void
00062 iseq_free(void *ptr)
00063 {
00064     rb_iseq_t *iseq;
00065     RUBY_FREE_ENTER("iseq");
00066 
00067     if (ptr) {
00068         iseq = ptr;
00069         if (!iseq->orig) {
00070             /* It's possible that strings are freed */
00071             if (0) {
00072                 RUBY_GC_INFO("%s @ %s\n", RSTRING_PTR(iseq->name),
00073                                           RSTRING_PTR(iseq->filename));
00074             }
00075 
00076             if (iseq->iseq != iseq->iseq_encoded) {
00077                 RUBY_FREE_UNLESS_NULL(iseq->iseq_encoded);
00078             }
00079 
00080             RUBY_FREE_UNLESS_NULL(iseq->iseq);
00081             RUBY_FREE_UNLESS_NULL(iseq->insn_info_table);
00082             RUBY_FREE_UNLESS_NULL(iseq->local_table);
00083             RUBY_FREE_UNLESS_NULL(iseq->ic_entries);
00084             RUBY_FREE_UNLESS_NULL(iseq->catch_table);
00085             RUBY_FREE_UNLESS_NULL(iseq->arg_opt_table);
00086             compile_data_free(iseq->compile_data);
00087         }
00088         ruby_xfree(ptr);
00089     }
00090     RUBY_FREE_LEAVE("iseq");
00091 }
00092 
00093 static void
00094 iseq_mark(void *ptr)
00095 {
00096     RUBY_MARK_ENTER("iseq");
00097 
00098     if (ptr) {
00099         rb_iseq_t *iseq = ptr;
00100 
00101         RUBY_GC_INFO("%s @ %s\n", RSTRING_PTR(iseq->name), RSTRING_PTR(iseq->filename));
00102         RUBY_MARK_UNLESS_NULL(iseq->mark_ary);
00103         RUBY_MARK_UNLESS_NULL(iseq->name);
00104         RUBY_MARK_UNLESS_NULL(iseq->filename);
00105         RUBY_MARK_UNLESS_NULL(iseq->filepath);
00106         RUBY_MARK_UNLESS_NULL((VALUE)iseq->cref_stack);
00107         RUBY_MARK_UNLESS_NULL(iseq->klass);
00108         RUBY_MARK_UNLESS_NULL(iseq->coverage);
00109 #if 0
00110         RUBY_MARK_UNLESS_NULL((VALUE)iseq->node);
00111         RUBY_MARK_UNLESS_NULL(iseq->cached_special_block);
00112 #endif
00113         RUBY_MARK_UNLESS_NULL(iseq->orig);
00114 
00115         if (iseq->compile_data != 0) {
00116             struct iseq_compile_data *const compile_data = iseq->compile_data;
00117             RUBY_MARK_UNLESS_NULL(compile_data->mark_ary);
00118             RUBY_MARK_UNLESS_NULL(compile_data->err_info);
00119             RUBY_MARK_UNLESS_NULL(compile_data->catch_table_ary);
00120         }
00121     }
00122     RUBY_MARK_LEAVE("iseq");
00123 }
00124 
00125 static size_t
00126 iseq_memsize(const void *ptr)
00127 {
00128     size_t size = sizeof(rb_iseq_t);
00129     const rb_iseq_t *iseq;
00130 
00131     if (ptr) {
00132         iseq = ptr;
00133         if (!iseq->orig) {
00134             if (iseq->iseq != iseq->iseq_encoded) {
00135                 size += iseq->iseq_size * sizeof(VALUE);
00136             }
00137 
00138             size += iseq->iseq_size * sizeof(VALUE);
00139             size += iseq->insn_info_size * sizeof(struct iseq_insn_info_entry);
00140             size += iseq->local_table_size * sizeof(ID);
00141             size += iseq->catch_table_size * sizeof(struct iseq_catch_table_entry);
00142             size += iseq->arg_opts * sizeof(VALUE);
00143             size += iseq->ic_size * sizeof(struct iseq_inline_cache_entry);
00144 
00145             if (iseq->compile_data) {
00146                 struct iseq_compile_data_storage *cur;
00147 
00148                 cur = iseq->compile_data->storage_head;
00149                 while (cur) {
00150                     size += cur->size + sizeof(struct iseq_compile_data_storage);
00151                     cur = cur->next;
00152                 }
00153                 size += sizeof(struct iseq_compile_data);
00154             }
00155         }
00156     }
00157 
00158     return size;
00159 }
00160 
00161 static const rb_data_type_t iseq_data_type = {
00162     "iseq",
00163     {
00164         iseq_mark,
00165         iseq_free,
00166         iseq_memsize,
00167     },
00168 };
00169 
00170 static VALUE
00171 iseq_alloc(VALUE klass)
00172 {
00173     rb_iseq_t *iseq;
00174     return TypedData_Make_Struct(klass, rb_iseq_t, &iseq_data_type, iseq);
00175 }
00176 
00177 static void
00178 set_relation(rb_iseq_t *iseq, const VALUE parent)
00179 {
00180     const VALUE type = iseq->type;
00181     rb_thread_t *th = GET_THREAD();
00182 
00183     /* set class nest stack */
00184     if (type == ISEQ_TYPE_TOP) {
00185         /* toplevel is private */
00186         iseq->cref_stack = NEW_BLOCK(rb_cObject);
00187         iseq->cref_stack->nd_visi = NOEX_PRIVATE;
00188         if (th->top_wrapper) {
00189             NODE *cref = NEW_BLOCK(th->top_wrapper);
00190             cref->nd_visi = NOEX_PRIVATE;
00191             cref->nd_next = iseq->cref_stack;
00192             iseq->cref_stack = cref;
00193         }
00194     }
00195     else if (type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) {
00196         iseq->cref_stack = NEW_BLOCK(0); /* place holder */
00197     }
00198     else if (RTEST(parent)) {
00199         rb_iseq_t *piseq;
00200         GetISeqPtr(parent, piseq);
00201         iseq->cref_stack = piseq->cref_stack;
00202     }
00203 
00204     if (type == ISEQ_TYPE_TOP ||
00205         type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) {
00206         iseq->local_iseq = iseq;
00207     }
00208     else if (RTEST(parent)) {
00209         rb_iseq_t *piseq;
00210         GetISeqPtr(parent, piseq);
00211         iseq->local_iseq = piseq->local_iseq;
00212     }
00213 
00214     if (RTEST(parent)) {
00215         rb_iseq_t *piseq;
00216         GetISeqPtr(parent, piseq);
00217         iseq->parent_iseq = piseq;
00218     }
00219 
00220     if (type == ISEQ_TYPE_MAIN) {
00221         iseq->local_iseq = iseq;
00222     }
00223 }
00224 
00225 static VALUE
00226 prepare_iseq_build(rb_iseq_t *iseq,
00227                    VALUE name, VALUE filename, VALUE filepath, VALUE line_no,
00228                    VALUE parent, enum iseq_type type, VALUE block_opt,
00229                    const rb_compile_option_t *option)
00230 {
00231     OBJ_FREEZE(name);
00232     OBJ_FREEZE(filename);
00233 
00234     iseq->name = name;
00235     iseq->filename = filename;
00236     iseq->filepath = filepath;
00237     iseq->line_no = (unsigned short)line_no; /* TODO: really enough? */
00238     iseq->defined_method_id = 0;
00239     iseq->mark_ary = rb_ary_tmp_new(3);
00240     OBJ_UNTRUST(iseq->mark_ary);
00241     RBASIC(iseq->mark_ary)->klass = 0;
00242 
00243     iseq->type = type;
00244     iseq->arg_rest = -1;
00245     iseq->arg_block = -1;
00246     iseq->klass = 0;
00247 
00248     /*
00249      * iseq->special_block_builder = GC_GUARDED_PTR_REF(block_opt);
00250      * iseq->cached_special_block_builder = 0;
00251      * iseq->cached_special_block = 0;
00252      */
00253 
00254     iseq->compile_data = ALLOC(struct iseq_compile_data);
00255     MEMZERO(iseq->compile_data, struct iseq_compile_data, 1);
00256     iseq->compile_data->err_info = Qnil;
00257     iseq->compile_data->mark_ary = rb_ary_tmp_new(3);
00258 
00259     iseq->compile_data->storage_head = iseq->compile_data->storage_current =
00260       (struct iseq_compile_data_storage *)
00261         ALLOC_N(char, INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE +
00262                 sizeof(struct iseq_compile_data_storage));
00263 
00264     iseq->compile_data->catch_table_ary = rb_ary_new();
00265     iseq->compile_data->storage_head->pos = 0;
00266     iseq->compile_data->storage_head->next = 0;
00267     iseq->compile_data->storage_head->size =
00268       INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE;
00269     iseq->compile_data->storage_head->buff =
00270       (char *)(&iseq->compile_data->storage_head->buff + 1);
00271     iseq->compile_data->option = option;
00272     iseq->compile_data->last_coverable_line = -1;
00273 
00274     set_relation(iseq, parent);
00275 
00276     iseq->coverage = Qfalse;
00277     if (!GET_THREAD()->parse_in_eval) {
00278         VALUE coverages = rb_get_coverages();
00279         if (RTEST(coverages)) {
00280             iseq->coverage = rb_hash_lookup(coverages, filename);
00281             if (NIL_P(iseq->coverage)) iseq->coverage = Qfalse;
00282         }
00283     }
00284 
00285     return Qtrue;
00286 }
00287 
00288 static VALUE
00289 cleanup_iseq_build(rb_iseq_t *iseq)
00290 {
00291     struct iseq_compile_data *data = iseq->compile_data;
00292     VALUE err = data->err_info;
00293     iseq->compile_data = 0;
00294     compile_data_free(data);
00295 
00296     if (RTEST(err)) {
00297         rb_funcall2(err, rb_intern("set_backtrace"), 1, &iseq->filename);
00298         rb_exc_raise(err);
00299     }
00300     return Qtrue;
00301 }
00302 
00303 static rb_compile_option_t COMPILE_OPTION_DEFAULT = {
00304     OPT_INLINE_CONST_CACHE, /* int inline_const_cache; */
00305     OPT_PEEPHOLE_OPTIMIZATION, /* int peephole_optimization; */
00306     OPT_TAILCALL_OPTIMIZATION, /* int tailcall_optimization */
00307     OPT_SPECIALISED_INSTRUCTION, /* int specialized_instruction; */
00308     OPT_OPERANDS_UNIFICATION, /* int operands_unification; */
00309     OPT_INSTRUCTIONS_UNIFICATION, /* int instructions_unification; */
00310     OPT_STACK_CACHING, /* int stack_caching; */
00311     OPT_TRACE_INSTRUCTION, /* int trace_instruction */
00312 };
00313 static const rb_compile_option_t COMPILE_OPTION_FALSE = {0};
00314 
00315 static void
00316 make_compile_option(rb_compile_option_t *option, VALUE opt)
00317 {
00318     if (opt == Qnil) {
00319         *option = COMPILE_OPTION_DEFAULT;
00320     }
00321     else if (opt == Qfalse) {
00322         *option = COMPILE_OPTION_FALSE;
00323     }
00324     else if (opt == Qtrue) {
00325         memset(option, 1, sizeof(rb_compile_option_t));
00326     }
00327     else if (CLASS_OF(opt) == rb_cHash) {
00328         *option = COMPILE_OPTION_DEFAULT;
00329 
00330 #define SET_COMPILE_OPTION(o, h, mem) \
00331   { VALUE flag = rb_hash_aref((h), ID2SYM(rb_intern(#mem))); \
00332       if (flag == Qtrue)  { (o)->mem = 1; } \
00333       else if (flag == Qfalse)  { (o)->mem = 0; } \
00334   }
00335 #define SET_COMPILE_OPTION_NUM(o, h, mem) \
00336   { VALUE num = rb_hash_aref(opt, ID2SYM(rb_intern(#mem))); \
00337       if (!NIL_P(num)) (o)->mem = NUM2INT(num); \
00338   }
00339         SET_COMPILE_OPTION(option, opt, inline_const_cache);
00340         SET_COMPILE_OPTION(option, opt, peephole_optimization);
00341         SET_COMPILE_OPTION(option, opt, tailcall_optimization);
00342         SET_COMPILE_OPTION(option, opt, specialized_instruction);
00343         SET_COMPILE_OPTION(option, opt, operands_unification);
00344         SET_COMPILE_OPTION(option, opt, instructions_unification);
00345         SET_COMPILE_OPTION(option, opt, stack_caching);
00346         SET_COMPILE_OPTION(option, opt, trace_instruction);
00347         SET_COMPILE_OPTION_NUM(option, opt, debug_level);
00348 #undef SET_COMPILE_OPTION
00349 #undef SET_COMPILE_OPTION_NUM
00350     }
00351     else {
00352         rb_raise(rb_eTypeError, "Compile option must be Hash/true/false/nil");
00353     }
00354 }
00355 
00356 static VALUE
00357 make_compile_option_value(rb_compile_option_t *option)
00358 {
00359     VALUE opt = rb_hash_new();
00360 #define SET_COMPILE_OPTION(o, h, mem) \
00361   rb_hash_aset((h), ID2SYM(rb_intern(#mem)), (o)->mem ? Qtrue : Qfalse)
00362 #define SET_COMPILE_OPTION_NUM(o, h, mem) \
00363   rb_hash_aset((h), ID2SYM(rb_intern(#mem)), INT2NUM((o)->mem))
00364     {
00365         SET_COMPILE_OPTION(option, opt, inline_const_cache);
00366         SET_COMPILE_OPTION(option, opt, peephole_optimization);
00367         SET_COMPILE_OPTION(option, opt, tailcall_optimization);
00368         SET_COMPILE_OPTION(option, opt, specialized_instruction);
00369         SET_COMPILE_OPTION(option, opt, operands_unification);
00370         SET_COMPILE_OPTION(option, opt, instructions_unification);
00371         SET_COMPILE_OPTION(option, opt, stack_caching);
00372         SET_COMPILE_OPTION_NUM(option, opt, debug_level);
00373     }
00374 #undef SET_COMPILE_OPTION
00375 #undef SET_COMPILE_OPTION_NUM
00376     return opt;
00377 }
00378 
00379 VALUE
00380 rb_iseq_new(NODE *node, VALUE name, VALUE filename, VALUE filepath,
00381             VALUE parent, enum iseq_type type)
00382 {
00383     return rb_iseq_new_with_opt(node, name, filename, filepath, INT2FIX(0), parent, type,
00384                                 &COMPILE_OPTION_DEFAULT);
00385 }
00386 
00387 VALUE
00388 rb_iseq_new_top(NODE *node, VALUE name, VALUE filename, VALUE filepath, VALUE parent)
00389 {
00390     return rb_iseq_new_with_opt(node, name, filename, filepath, INT2FIX(0), parent, ISEQ_TYPE_TOP,
00391                                 &COMPILE_OPTION_DEFAULT);
00392 }
00393 
00394 VALUE
00395 rb_iseq_new_main(NODE *node, VALUE filename, VALUE filepath)
00396 {
00397     rb_thread_t *th = GET_THREAD();
00398     VALUE parent = th->base_block->iseq->self;
00399     return rb_iseq_new_with_opt(node, rb_str_new2("<main>"), filename, filepath, INT2FIX(0),
00400                                 parent, ISEQ_TYPE_MAIN, &COMPILE_OPTION_DEFAULT);
00401 }
00402 
00403 static VALUE
00404 rb_iseq_new_with_bopt_and_opt(NODE *node, VALUE name, VALUE filename, VALUE filepath, VALUE line_no,
00405                                 VALUE parent, enum iseq_type type, VALUE bopt,
00406                                 const rb_compile_option_t *option)
00407 {
00408     rb_iseq_t *iseq;
00409     VALUE self = iseq_alloc(rb_cISeq);
00410 
00411     GetISeqPtr(self, iseq);
00412     iseq->self = self;
00413 
00414     prepare_iseq_build(iseq, name, filename, filepath, line_no, parent, type, bopt, option);
00415     rb_iseq_compile_node(self, node);
00416     cleanup_iseq_build(iseq);
00417     return self;
00418 }
00419 
00420 VALUE
00421 rb_iseq_new_with_opt(NODE *node, VALUE name, VALUE filename, VALUE filepath, VALUE line_no,
00422                      VALUE parent, enum iseq_type type,
00423                      const rb_compile_option_t *option)
00424 {
00425     /* TODO: argument check */
00426     return rb_iseq_new_with_bopt_and_opt(node, name, filename, filepath, line_no, parent, type,
00427                                            Qfalse, option);
00428 }
00429 
00430 VALUE
00431 rb_iseq_new_with_bopt(NODE *node, VALUE name, VALUE filename, VALUE filepath, VALUE line_no,
00432                        VALUE parent, enum iseq_type type, VALUE bopt)
00433 {
00434     /* TODO: argument check */
00435     return rb_iseq_new_with_bopt_and_opt(node, name, filename, filepath, line_no, parent, type,
00436                                            bopt, &COMPILE_OPTION_DEFAULT);
00437 }
00438 
00439 #define CHECK_ARRAY(v)   rb_convert_type((v), T_ARRAY, "Array", "to_ary")
00440 #define CHECK_STRING(v)  rb_convert_type((v), T_STRING, "String", "to_str")
00441 #define CHECK_SYMBOL(v)  rb_convert_type((v), T_SYMBOL, "Symbol", "to_sym")
00442 static inline VALUE CHECK_INTEGER(VALUE v) {(void)NUM2LONG(v); return v;}
00443 static VALUE
00444 iseq_load(VALUE self, VALUE data, VALUE parent, VALUE opt)
00445 {
00446     VALUE iseqval = iseq_alloc(self);
00447 
00448     VALUE magic, version1, version2, format_type, misc;
00449     VALUE name, filename, filepath, line_no;
00450     VALUE type, body, locals, args, exception;
00451 
00452     st_data_t iseq_type;
00453     static struct st_table *type_map_cache = 0;
00454     struct st_table *type_map = 0;
00455     rb_iseq_t *iseq;
00456     rb_compile_option_t option;
00457     int i = 0;
00458 
00459     /* [magic, major_version, minor_version, format_type, misc,
00460      *  name, filename, line_no,
00461      *  type, locals, args, exception_table, body]
00462      */
00463 
00464     data        = CHECK_ARRAY(data);
00465 
00466     magic       = CHECK_STRING(rb_ary_entry(data, i++));
00467     version1    = CHECK_INTEGER(rb_ary_entry(data, i++));
00468     version2    = CHECK_INTEGER(rb_ary_entry(data, i++));
00469     format_type = CHECK_INTEGER(rb_ary_entry(data, i++));
00470     misc        = rb_ary_entry(data, i++); /* TODO */
00471 
00472     name        = CHECK_STRING(rb_ary_entry(data, i++));
00473     filename    = CHECK_STRING(rb_ary_entry(data, i++));
00474     filepath    = rb_ary_entry(data, i++);
00475     filepath    = NIL_P(filepath) ? Qnil : CHECK_STRING(filepath);
00476     line_no     = CHECK_INTEGER(rb_ary_entry(data, i++));
00477 
00478     type        = CHECK_SYMBOL(rb_ary_entry(data, i++));
00479     locals      = CHECK_ARRAY(rb_ary_entry(data, i++));
00480 
00481     args        = rb_ary_entry(data, i++);
00482     if (FIXNUM_P(args) || (args = CHECK_ARRAY(args))) {
00483         /* */
00484     }
00485 
00486     exception   = CHECK_ARRAY(rb_ary_entry(data, i++));
00487     body        = CHECK_ARRAY(rb_ary_entry(data, i++));
00488 
00489     GetISeqPtr(iseqval, iseq);
00490     iseq->self = iseqval;
00491 
00492     type_map = type_map_cache;
00493     if (type_map == 0) {
00494         struct st_table *cached_map;
00495         type_map = st_init_numtable();
00496         st_insert(type_map, ID2SYM(rb_intern("top")), ISEQ_TYPE_TOP);
00497         st_insert(type_map, ID2SYM(rb_intern("method")), ISEQ_TYPE_METHOD);
00498         st_insert(type_map, ID2SYM(rb_intern("block")), ISEQ_TYPE_BLOCK);
00499         st_insert(type_map, ID2SYM(rb_intern("class")), ISEQ_TYPE_CLASS);
00500         st_insert(type_map, ID2SYM(rb_intern("rescue")), ISEQ_TYPE_RESCUE);
00501         st_insert(type_map, ID2SYM(rb_intern("ensure")), ISEQ_TYPE_ENSURE);
00502         st_insert(type_map, ID2SYM(rb_intern("eval")), ISEQ_TYPE_EVAL);
00503         st_insert(type_map, ID2SYM(rb_intern("main")), ISEQ_TYPE_MAIN);
00504         st_insert(type_map, ID2SYM(rb_intern("defined_guard")), ISEQ_TYPE_DEFINED_GUARD);
00505         cached_map = ATOMIC_PTR_CAS(type_map_cache, (struct st_table *)0, type_map);
00506         if (cached_map) {
00507             st_free_table(type_map);
00508             type_map = cached_map;
00509         }
00510     }
00511 
00512     if (st_lookup(type_map, type, &iseq_type) == 0) {
00513         const char *typename = rb_id2name(type);
00514         if (typename)
00515             rb_raise(rb_eTypeError, "unsupport type: :%s", typename);
00516         else
00517             rb_raise(rb_eTypeError, "unsupport type: %p", (void *)type);
00518     }
00519 
00520     if (parent == Qnil) {
00521         parent = 0;
00522     }
00523 
00524     make_compile_option(&option, opt);
00525     prepare_iseq_build(iseq, name, filename, filepath, line_no,
00526                        parent, (enum iseq_type)iseq_type, 0, &option);
00527 
00528     rb_iseq_build_from_ary(iseq, locals, args, exception, body);
00529 
00530     cleanup_iseq_build(iseq);
00531     return iseqval;
00532 }
00533 
00534 static VALUE
00535 iseq_s_load(int argc, VALUE *argv, VALUE self)
00536 {
00537     VALUE data, opt=Qnil;
00538     rb_scan_args(argc, argv, "11", &data, &opt);
00539 
00540     return iseq_load(self, data, 0, opt);
00541 }
00542 
00543 VALUE
00544 rb_iseq_load(VALUE data, VALUE parent, VALUE opt)
00545 {
00546     return iseq_load(rb_cISeq, data, parent, opt);
00547 }
00548 
00549 static NODE *
00550 parse_string(VALUE str, const char *file, int line)
00551 {
00552     VALUE parser = rb_parser_new();
00553     NODE *node = rb_parser_compile_string(parser, file, str, line);
00554 
00555     if (!node) {
00556         rb_exc_raise(GET_THREAD()->errinfo);    /* TODO: check err */
00557     }
00558     return node;
00559 }
00560 
00561 VALUE
00562 rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE filepath, VALUE line, VALUE opt)
00563 {
00564     rb_compile_option_t option;
00565     const char *fn = StringValueCStr(file);
00566     int ln = NUM2INT(line);
00567     NODE *node = parse_string(StringValue(src), fn, ln);
00568     rb_thread_t *th = GET_THREAD();
00569     make_compile_option(&option, opt);
00570 
00571     if (th->base_block && th->base_block->iseq) {
00572         return rb_iseq_new_with_opt(node, th->base_block->iseq->name,
00573                                     file, filepath, line, th->base_block->iseq->self,
00574                                     ISEQ_TYPE_EVAL, &option);
00575     }
00576     else {
00577         return rb_iseq_new_with_opt(node, rb_str_new2("<compiled>"), file, filepath, line, Qfalse,
00578                                     ISEQ_TYPE_TOP, &option);
00579     }
00580 }
00581 
00582 VALUE
00583 rb_iseq_compile(VALUE src, VALUE file, VALUE line)
00584 {
00585     return rb_iseq_compile_with_option(src, file, Qnil, line, Qnil);
00586 }
00587 
00588 static VALUE
00589 iseq_s_compile(int argc, VALUE *argv, VALUE self)
00590 {
00591     VALUE src, file = Qnil, path = Qnil, line = INT2FIX(1), opt = Qnil;
00592 
00593     rb_secure(1);
00594 
00595     rb_scan_args(argc, argv, "14", &src, &file, &path, &line, &opt);
00596     if (NIL_P(file)) file = rb_str_new2("<compiled>");
00597     if (NIL_P(line)) line = INT2FIX(1);
00598 
00599     return rb_iseq_compile_with_option(src, file, path, line, opt);
00600 }
00601 
00602 static VALUE
00603 iseq_s_compile_file(int argc, VALUE *argv, VALUE self)
00604 {
00605     VALUE file, line = INT2FIX(1), opt = Qnil;
00606     VALUE parser;
00607     VALUE f;
00608     NODE *node;
00609     const char *fname;
00610     rb_compile_option_t option;
00611 
00612     rb_secure(1);
00613     rb_scan_args(argc, argv, "11", &file, &opt);
00614     FilePathValue(file);
00615     fname = StringValueCStr(file);
00616 
00617     f = rb_file_open_str(file, "r");
00618 
00619     parser = rb_parser_new();
00620     node = rb_parser_compile_file(parser, fname, f, NUM2INT(line));
00621     make_compile_option(&option, opt);
00622     return rb_iseq_new_with_opt(node, rb_str_new2("<main>"), file,
00623                                 rb_realpath_internal(Qnil, file, 1), line, Qfalse,
00624                                 ISEQ_TYPE_TOP, &option);
00625 }
00626 
00627 static VALUE
00628 iseq_s_compile_option_set(VALUE self, VALUE opt)
00629 {
00630     rb_compile_option_t option;
00631     rb_secure(1);
00632     make_compile_option(&option, opt);
00633     COMPILE_OPTION_DEFAULT = option;
00634     return opt;
00635 }
00636 
00637 static VALUE
00638 iseq_s_compile_option_get(VALUE self)
00639 {
00640     return make_compile_option_value(&COMPILE_OPTION_DEFAULT);
00641 }
00642 
00643 static rb_iseq_t *
00644 iseq_check(VALUE val)
00645 {
00646     rb_iseq_t *iseq;
00647     GetISeqPtr(val, iseq);
00648     if (!iseq->name) {
00649         rb_raise(rb_eTypeError, "uninitialized InstructionSequence");
00650     }
00651     return iseq;
00652 }
00653 
00654 static VALUE
00655 iseq_eval(VALUE self)
00656 {
00657     rb_secure(1);
00658     return rb_iseq_eval(self);
00659 }
00660 
00661 static VALUE
00662 iseq_inspect(VALUE self)
00663 {
00664     rb_iseq_t *iseq;
00665     GetISeqPtr(self, iseq);
00666     if (!iseq->name) {
00667         return rb_sprintf("#<%s: uninitialized>", rb_obj_classname(self));
00668     }
00669 
00670     return rb_sprintf("<%s:%s@%s>",
00671                       rb_obj_classname(self),
00672                       RSTRING_PTR(iseq->name), RSTRING_PTR(iseq->filename));
00673 }
00674 
00675 static
00676 VALUE iseq_data_to_ary(rb_iseq_t *iseq);
00677 
00678 static VALUE
00679 iseq_to_a(VALUE self)
00680 {
00681     rb_iseq_t *iseq = iseq_check(self);
00682     rb_secure(1);
00683     return iseq_data_to_ary(iseq);
00684 }
00685 
00686 int
00687 rb_iseq_first_lineno(rb_iseq_t *iseq)
00688 {
00689     return FIX2INT(iseq->line_no);
00690 }
00691 
00692 /* TODO: search algorithm is brute force.
00693          this should be binary search or so. */
00694 
00695 static struct iseq_insn_info_entry *
00696 get_insn_info(const rb_iseq_t *iseq, const unsigned long pos)
00697 {
00698     unsigned long i, size = iseq->insn_info_size;
00699     struct iseq_insn_info_entry *table = iseq->insn_info_table;
00700 
00701     for (i = 0; i < size; i++) {
00702         if (table[i].position == pos) {
00703             return &table[i];
00704         }
00705     }
00706 
00707     return 0;
00708 }
00709 
00710 static unsigned short
00711 find_line_no(rb_iseq_t *iseq, unsigned long pos)
00712 {
00713     struct iseq_insn_info_entry *entry = get_insn_info(iseq, pos);
00714     if (entry) {
00715         return entry->line_no;
00716     }
00717     else {
00718         return 0;
00719     }
00720 }
00721 
00722 static unsigned short
00723 find_prev_line_no(rb_iseq_t *iseqdat, unsigned long pos)
00724 {
00725     unsigned long i, size = iseqdat->insn_info_size;
00726     struct iseq_insn_info_entry *iiary = iseqdat->insn_info_table;
00727 
00728     for (i = 0; i < size; i++) {
00729         if (iiary[i].position == pos) {
00730             if (i > 0) {
00731                 return iiary[i - 1].line_no;
00732             }
00733             else {
00734                 return 0;
00735             }
00736         }
00737     }
00738 
00739     return 0;
00740 }
00741 
00742 static VALUE
00743 insn_operand_intern(rb_iseq_t *iseq,
00744                     VALUE insn, int op_no, VALUE op,
00745                     int len, size_t pos, VALUE *pnop, VALUE child)
00746 {
00747     const char *types = insn_op_types(insn);
00748     char type = types[op_no];
00749     VALUE ret;
00750 
00751     switch (type) {
00752       case TS_OFFSET:           /* LONG */
00753         ret = rb_sprintf("%"PRIdVALUE, (VALUE)(pos + len + op));
00754         break;
00755 
00756       case TS_NUM:              /* ULONG */
00757         ret = rb_sprintf("%"PRIuVALUE, op);
00758         break;
00759 
00760       case TS_LINDEX:
00761         {
00762             rb_iseq_t *liseq = iseq->local_iseq;
00763             int lidx = liseq->local_size - (int)op;
00764             const char *name = rb_id2name(liseq->local_table[lidx]);
00765 
00766             if (name) {
00767                 ret = rb_str_new2(name);
00768             }
00769             else {
00770                 ret = rb_str_new2("*");
00771             }
00772             break;
00773         }
00774       case TS_DINDEX:{
00775         if (insn == BIN(getdynamic) || insn == BIN(setdynamic)) {
00776             rb_iseq_t *diseq = iseq;
00777             VALUE level = *pnop, i;
00778             const char *name;
00779             for (i = 0; i < level; i++) {
00780                 diseq = diseq->parent_iseq;
00781             }
00782             name = rb_id2name(diseq->local_table[diseq->local_size - op]);
00783 
00784             if (!name) {
00785                 name = "*";
00786             }
00787             ret = rb_str_new2(name);
00788         }
00789         else {
00790             ret = rb_inspect(INT2FIX(op));
00791         }
00792         break;
00793       }
00794       case TS_ID:               /* ID (symbol) */
00795         op = ID2SYM(op);
00796 
00797       case TS_VALUE:            /* VALUE */
00798         op = obj_resurrect(op);
00799         ret = rb_inspect(op);
00800         if (CLASS_OF(op) == rb_cISeq) {
00801             rb_ary_push(child, op);
00802         }
00803         break;
00804 
00805       case TS_ISEQ:             /* iseq */
00806         {
00807             rb_iseq_t *iseq = (rb_iseq_t *)op;
00808             if (iseq) {
00809                 ret = iseq->name;
00810                 if (child) {
00811                     rb_ary_push(child, iseq->self);
00812                 }
00813             }
00814             else {
00815                 ret = rb_str_new2("nil");
00816             }
00817             break;
00818         }
00819       case TS_GENTRY:
00820         {
00821             struct rb_global_entry *entry = (struct rb_global_entry *)op;
00822             ret = rb_str_dup(rb_id2str(entry->id));
00823         }
00824         break;
00825 
00826       case TS_IC:
00827         ret = rb_sprintf("<ic:%"PRIdPTRDIFF">", (struct iseq_inline_cache_entry *)op - iseq->ic_entries);
00828         break;
00829 
00830       case TS_CDHASH:
00831         ret = rb_str_new2("<cdhash>");
00832         break;
00833 
00834       case TS_FUNCPTR:
00835         ret = rb_str_new2("<funcptr>");
00836         break;
00837 
00838       default:
00839         rb_bug("rb_iseq_disasm: unknown operand type: %c", type);
00840     }
00841     return ret;
00842 }
00843 
00848 int
00849 rb_iseq_disasm_insn(VALUE ret, VALUE *iseq, size_t pos,
00850                     rb_iseq_t *iseqdat, VALUE child)
00851 {
00852     VALUE insn = iseq[pos];
00853     int len = insn_len(insn);
00854     int j;
00855     const char *types = insn_op_types(insn);
00856     VALUE str = rb_str_new(0, 0);
00857     const char *insn_name_buff;
00858 
00859     insn_name_buff = insn_name(insn);
00860     if (1) {
00861         rb_str_catf(str, "%04"PRIdSIZE" %-16s ", pos, insn_name_buff);
00862     }
00863     else {
00864         rb_str_catf(str, "%04"PRIdSIZE" %-16.*s ", pos,
00865                     (int)strcspn(insn_name_buff, "_"), insn_name_buff);
00866     }
00867 
00868     for (j = 0; types[j]; j++) {
00869         const char *types = insn_op_types(insn);
00870         VALUE opstr = insn_operand_intern(iseqdat, insn, j, iseq[pos + j + 1],
00871                                           len, pos, &iseq[pos + j + 2],
00872                                           child);
00873         rb_str_concat(str, opstr);
00874 
00875         if (types[j + 1]) {
00876             rb_str_cat2(str, ", ");
00877         }
00878     }
00879 
00880     if (1) {
00881         int line_no = find_line_no(iseqdat, pos);
00882         int prev = find_prev_line_no(iseqdat, pos);
00883         if (line_no && line_no != prev) {
00884             long slen = RSTRING_LEN(str);
00885             slen = (slen > 70) ? 0 : (70 - slen);
00886             str = rb_str_catf(str, "%*s(%4d)", (int)slen, "", line_no);
00887         }
00888     }
00889     else {
00890         /* for debug */
00891         struct iseq_insn_info_entry *entry = get_insn_info(iseqdat, pos);
00892         long slen = RSTRING_LEN(str);
00893         slen = (slen > 60) ? 0 : (60 - slen);
00894         str = rb_str_catf(str, "%*s(line: %d, sp: %d)",
00895                           (int)slen, "", entry->line_no, entry->sp);
00896     }
00897 
00898     if (ret) {
00899         rb_str_cat2(str, "\n");
00900         rb_str_concat(ret, str);
00901     }
00902     else {
00903         printf("%s\n", RSTRING_PTR(str));
00904     }
00905     return len;
00906 }
00907 
00908 static const char *
00909 catch_type(int type)
00910 {
00911     switch (type) {
00912       case CATCH_TYPE_RESCUE:
00913         return "rescue";
00914       case CATCH_TYPE_ENSURE:
00915         return "ensure";
00916       case CATCH_TYPE_RETRY:
00917         return "retry";
00918       case CATCH_TYPE_BREAK:
00919         return "break";
00920       case CATCH_TYPE_REDO:
00921         return "redo";
00922       case CATCH_TYPE_NEXT:
00923         return "next";
00924       default:
00925         rb_bug("unknown catch type (%d)", type);
00926         return 0;
00927     }
00928 }
00929 
00930 VALUE
00931 rb_iseq_disasm(VALUE self)
00932 {
00933     rb_iseq_t *iseqdat = iseq_check(self);
00934     VALUE *iseq;
00935     VALUE str = rb_str_new(0, 0);
00936     VALUE child = rb_ary_new();
00937     unsigned long size;
00938     int i;
00939     long l;
00940     ID *tbl;
00941     size_t n;
00942     enum {header_minlen = 72};
00943 
00944     rb_secure(1);
00945 
00946     iseq = iseqdat->iseq;
00947     size = iseqdat->iseq_size;
00948 
00949     rb_str_cat2(str, "== disasm: ");
00950 
00951     rb_str_concat(str, iseq_inspect(iseqdat->self));
00952     if ((l = RSTRING_LEN(str)) < header_minlen) {
00953         rb_str_resize(str, header_minlen);
00954         memset(RSTRING_PTR(str) + l, '=', header_minlen - l);
00955     }
00956     rb_str_cat2(str, "\n");
00957 
00958     /* show catch table information */
00959     if (iseqdat->catch_table_size != 0) {
00960         rb_str_cat2(str, "== catch table\n");
00961     }
00962     for (i = 0; i < iseqdat->catch_table_size; i++) {
00963         struct iseq_catch_table_entry *entry = &iseqdat->catch_table[i];
00964         rb_str_catf(str,
00965                     "| catch type: %-6s st: %04d ed: %04d sp: %04d cont: %04d\n",
00966                     catch_type((int)entry->type), (int)entry->start,
00967                     (int)entry->end, (int)entry->sp, (int)entry->cont);
00968         if (entry->iseq) {
00969             rb_str_concat(str, rb_iseq_disasm(entry->iseq));
00970         }
00971     }
00972     if (iseqdat->catch_table_size != 0) {
00973         rb_str_cat2(str, "|-------------------------------------"
00974                     "-----------------------------------\n");
00975     }
00976 
00977     /* show local table information */
00978     tbl = iseqdat->local_table;
00979 
00980     if (tbl) {
00981         rb_str_catf(str,
00982                     "local table (size: %d, argc: %d "
00983                     "[opts: %d, rest: %d, post: %d, block: %d] s%d)\n",
00984                     iseqdat->local_size, iseqdat->argc,
00985                     iseqdat->arg_opts, iseqdat->arg_rest,
00986                     iseqdat->arg_post_len, iseqdat->arg_block,
00987                     iseqdat->arg_simple);
00988 
00989         for (i = 0; i < iseqdat->local_table_size; i++) {
00990             const char *name = rb_id2name(tbl[i]);
00991             char info[0x100];
00992             char argi[0x100] = "";
00993             char opti[0x100] = "";
00994 
00995             if (iseqdat->arg_opts) {
00996                 int argc = iseqdat->argc;
00997                 int opts = iseqdat->arg_opts;
00998                 if (i >= argc && i < argc + opts - 1) {
00999                     snprintf(opti, sizeof(opti), "Opt=%"PRIdVALUE,
01000                              iseqdat->arg_opt_table[i - argc]);
01001                 }
01002             }
01003 
01004             snprintf(argi, sizeof(argi), "%s%s%s%s%s",  /* arg, opts, rest, post  block */
01005                      iseqdat->argc > i ? "Arg" : "",
01006                      opti,
01007                      iseqdat->arg_rest == i ? "Rest" : "",
01008                      (iseqdat->arg_post_start <= i &&
01009                       i < iseqdat->arg_post_start + iseqdat->arg_post_len) ? "Post" : "",
01010                      iseqdat->arg_block == i ? "Block" : "");
01011 
01012             snprintf(info, sizeof(info), "%s%s%s%s", name ? name : "?",
01013                      *argi ? "<" : "", argi, *argi ? ">" : "");
01014 
01015             rb_str_catf(str, "[%2d] %-11s", iseqdat->local_size - i, info);
01016         }
01017         rb_str_cat2(str, "\n");
01018     }
01019 
01020     /* show each line */
01021     for (n = 0; n < size;) {
01022         n += rb_iseq_disasm_insn(str, iseq, n, iseqdat, child);
01023     }
01024 
01025     for (i = 0; i < RARRAY_LEN(child); i++) {
01026         VALUE isv = rb_ary_entry(child, i);
01027         rb_str_concat(str, rb_iseq_disasm(isv));
01028     }
01029 
01030     return str;
01031 }
01032 
01033 static VALUE
01034 iseq_s_disasm(VALUE klass, VALUE body)
01035 {
01036     VALUE ret = Qnil;
01037     rb_iseq_t *iseq;
01038 
01039     rb_secure(1);
01040 
01041     if (rb_obj_is_proc(body)) {
01042         rb_proc_t *proc;
01043         GetProcPtr(body, proc);
01044         iseq = proc->block.iseq;
01045         if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
01046             ret = rb_iseq_disasm(iseq->self);
01047         }
01048     }
01049     else if ((iseq = rb_method_get_iseq(body)) != 0) {
01050         ret = rb_iseq_disasm(iseq->self);
01051     }
01052 
01053     return ret;
01054 }
01055 
01056 const char *
01057 ruby_node_name(int node)
01058 {
01059     switch (node) {
01060 #include "node_name.inc"
01061       default:
01062         rb_bug("unknown node (%d)", node);
01063         return 0;
01064     }
01065 }
01066 
01067 #define DECL_SYMBOL(name) \
01068   static VALUE sym_##name
01069 
01070 #define INIT_SYMBOL(name) \
01071   sym_##name = ID2SYM(rb_intern(#name))
01072 
01073 static VALUE
01074 register_label(struct st_table *table, unsigned long idx)
01075 {
01076     VALUE sym;
01077     char buff[8 + (sizeof(idx) * CHAR_BIT * 32 / 100)];
01078 
01079     snprintf(buff, sizeof(buff), "label_%lu", idx);
01080     sym = ID2SYM(rb_intern(buff));
01081     st_insert(table, idx, sym);
01082     return sym;
01083 }
01084 
01085 static VALUE
01086 exception_type2symbol(VALUE type)
01087 {
01088     ID id;
01089     switch(type) {
01090       case CATCH_TYPE_RESCUE: CONST_ID(id, "rescue"); break;
01091       case CATCH_TYPE_ENSURE: CONST_ID(id, "ensure"); break;
01092       case CATCH_TYPE_RETRY:  CONST_ID(id, "retry");  break;
01093       case CATCH_TYPE_BREAK:  CONST_ID(id, "break");  break;
01094       case CATCH_TYPE_REDO:   CONST_ID(id, "redo");   break;
01095       case CATCH_TYPE_NEXT:   CONST_ID(id, "next");   break;
01096       default:
01097         rb_bug("...");
01098     }
01099     return ID2SYM(id);
01100 }
01101 
01102 static int
01103 cdhash_each(VALUE key, VALUE value, VALUE ary)
01104 {
01105     rb_ary_push(ary, obj_resurrect(key));
01106     rb_ary_push(ary, value);
01107     return ST_CONTINUE;
01108 }
01109 
01110 static VALUE
01111 iseq_data_to_ary(rb_iseq_t *iseq)
01112 {
01113     long i, pos;
01114     int line = 0;
01115     VALUE *seq;
01116 
01117     VALUE val = rb_ary_new();
01118     VALUE type; /* Symbol */
01119     VALUE locals = rb_ary_new();
01120     VALUE args = rb_ary_new();
01121     VALUE body = rb_ary_new(); /* [[:insn1, ...], ...] */
01122     VALUE nbody;
01123     VALUE exception = rb_ary_new(); /* [[....]] */
01124     VALUE misc = rb_hash_new();
01125 
01126     static VALUE insn_syms[VM_INSTRUCTION_SIZE];
01127     struct st_table *labels_table = st_init_numtable();
01128 
01129     DECL_SYMBOL(top);
01130     DECL_SYMBOL(method);
01131     DECL_SYMBOL(block);
01132     DECL_SYMBOL(class);
01133     DECL_SYMBOL(rescue);
01134     DECL_SYMBOL(ensure);
01135     DECL_SYMBOL(eval);
01136     DECL_SYMBOL(main);
01137     DECL_SYMBOL(defined_guard);
01138 
01139     if (sym_top == 0) {
01140         int i;
01141         for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
01142             insn_syms[i] = ID2SYM(rb_intern(insn_name(i)));
01143         }
01144         INIT_SYMBOL(top);
01145         INIT_SYMBOL(method);
01146         INIT_SYMBOL(block);
01147         INIT_SYMBOL(class);
01148         INIT_SYMBOL(rescue);
01149         INIT_SYMBOL(ensure);
01150         INIT_SYMBOL(eval);
01151         INIT_SYMBOL(main);
01152         INIT_SYMBOL(defined_guard);
01153     }
01154 
01155     /* type */
01156     switch(iseq->type) {
01157       case ISEQ_TYPE_TOP:    type = sym_top;    break;
01158       case ISEQ_TYPE_METHOD: type = sym_method; break;
01159       case ISEQ_TYPE_BLOCK:  type = sym_block;  break;
01160       case ISEQ_TYPE_CLASS:  type = sym_class;  break;
01161       case ISEQ_TYPE_RESCUE: type = sym_rescue; break;
01162       case ISEQ_TYPE_ENSURE: type = sym_ensure; break;
01163       case ISEQ_TYPE_EVAL:   type = sym_eval;   break;
01164       case ISEQ_TYPE_MAIN:   type = sym_main;   break;
01165       case ISEQ_TYPE_DEFINED_GUARD: type = sym_defined_guard; break;
01166       default: rb_bug("unsupported iseq type");
01167     };
01168 
01169     /* locals */
01170     for (i=0; i<iseq->local_table_size; i++) {
01171         ID lid = iseq->local_table[i];
01172         if (lid) {
01173             if (rb_id2str(lid)) rb_ary_push(locals, ID2SYM(lid));
01174         }
01175         else {
01176             rb_ary_push(locals, ID2SYM(rb_intern("#arg_rest")));
01177         }
01178     }
01179 
01180     /* args */
01181     {
01182         /*
01183          * [argc,                 # argc
01184          *  [label1, label2, ...] # opts
01185          *  rest index,
01186          *  post_len
01187          *  post_start
01188          *  block index,
01189          *  simple,
01190          * ]
01191          */
01192         VALUE arg_opt_labels = rb_ary_new();
01193         int j;
01194 
01195         for (j=0; j<iseq->arg_opts; j++) {
01196             rb_ary_push(arg_opt_labels,
01197                         register_label(labels_table, iseq->arg_opt_table[j]));
01198         }
01199 
01200         /* commit */
01201         if (iseq->arg_simple == 1) {
01202             args = INT2FIX(iseq->argc);
01203         }
01204         else {
01205             rb_ary_push(args, INT2FIX(iseq->argc));
01206             rb_ary_push(args, arg_opt_labels);
01207             rb_ary_push(args, INT2FIX(iseq->arg_post_len));
01208             rb_ary_push(args, INT2FIX(iseq->arg_post_start));
01209             rb_ary_push(args, INT2FIX(iseq->arg_rest));
01210             rb_ary_push(args, INT2FIX(iseq->arg_block));
01211             rb_ary_push(args, INT2FIX(iseq->arg_simple));
01212         }
01213     }
01214 
01215     /* body */
01216     for (seq = iseq->iseq; seq < iseq->iseq + iseq->iseq_size; ) {
01217         VALUE insn = *seq++;
01218         int j, len = insn_len(insn);
01219         VALUE *nseq = seq + len - 1;
01220         VALUE ary = rb_ary_new2(len);
01221 
01222         rb_ary_push(ary, insn_syms[insn]);
01223         for (j=0; j<len-1; j++, seq++) {
01224             switch (insn_op_type(insn, j)) {
01225               case TS_OFFSET: {
01226                 unsigned long idx = nseq - iseq->iseq + *seq;
01227                 rb_ary_push(ary, register_label(labels_table, idx));
01228                 break;
01229               }
01230               case TS_LINDEX:
01231               case TS_DINDEX:
01232               case TS_NUM:
01233                 rb_ary_push(ary, INT2FIX(*seq));
01234                 break;
01235               case TS_VALUE:
01236                 rb_ary_push(ary, obj_resurrect(*seq));
01237                 break;
01238               case TS_ISEQ:
01239                 {
01240                     rb_iseq_t *iseq = (rb_iseq_t *)*seq;
01241                     if (iseq) {
01242                         VALUE val = iseq_data_to_ary(iseq);
01243                         rb_ary_push(ary, val);
01244                     }
01245                     else {
01246                         rb_ary_push(ary, Qnil);
01247                     }
01248                 }
01249                 break;
01250               case TS_GENTRY:
01251                 {
01252                     struct rb_global_entry *entry = (struct rb_global_entry *)*seq;
01253                     rb_ary_push(ary, ID2SYM(entry->id));
01254                 }
01255                 break;
01256               case TS_IC: {
01257                   struct iseq_inline_cache_entry *ic = (struct iseq_inline_cache_entry *)*seq;
01258                     rb_ary_push(ary, INT2FIX(ic - iseq->ic_entries));
01259                 }
01260                 break;
01261               case TS_ID:
01262                 rb_ary_push(ary, ID2SYM(*seq));
01263                 break;
01264               case TS_CDHASH:
01265                 {
01266                     VALUE hash = *seq;
01267                     VALUE val = rb_ary_new();
01268                     int i;
01269 
01270                     rb_hash_foreach(hash, cdhash_each, val);
01271 
01272                     for (i=0; i<RARRAY_LEN(val); i+=2) {
01273                         VALUE pos = FIX2INT(rb_ary_entry(val, i+1));
01274                         unsigned long idx = nseq - iseq->iseq + pos;
01275 
01276                         rb_ary_store(val, i+1,
01277                                      register_label(labels_table, idx));
01278                     }
01279                     rb_ary_push(ary, val);
01280                 }
01281                 break;
01282               default:
01283                 rb_bug("unknown operand: %c", insn_op_type(insn, j));
01284             }
01285         }
01286         rb_ary_push(body, ary);
01287     }
01288 
01289     nbody = body;
01290 
01291     /* exception */
01292     for (i=0; i<iseq->catch_table_size; i++) {
01293         VALUE ary = rb_ary_new();
01294         struct iseq_catch_table_entry *entry = &iseq->catch_table[i];
01295         rb_ary_push(ary, exception_type2symbol(entry->type));
01296         if (entry->iseq) {
01297             rb_iseq_t *eiseq;
01298             GetISeqPtr(entry->iseq, eiseq);
01299             rb_ary_push(ary, iseq_data_to_ary(eiseq));
01300         }
01301         else {
01302             rb_ary_push(ary, Qnil);
01303         }
01304         rb_ary_push(ary, register_label(labels_table, entry->start));
01305         rb_ary_push(ary, register_label(labels_table, entry->end));
01306         rb_ary_push(ary, register_label(labels_table, entry->cont));
01307         rb_ary_push(ary, INT2FIX(entry->sp));
01308         rb_ary_push(exception, ary);
01309     }
01310 
01311     /* make body with labels and insert line number */
01312     body = rb_ary_new();
01313 
01314     for (i=0, pos=0; i<RARRAY_LEN(nbody); i++) {
01315         VALUE ary = RARRAY_PTR(nbody)[i];
01316         st_data_t label;
01317 
01318         if (st_lookup(labels_table, pos, &label)) {
01319             rb_ary_push(body, (VALUE)label);
01320         }
01321 
01322         if (iseq->insn_info_table[i].line_no != line) {
01323             line = iseq->insn_info_table[i].line_no;
01324             rb_ary_push(body, INT2FIX(line));
01325         }
01326 
01327         rb_ary_push(body, ary);
01328         pos += RARRAY_LENINT(ary); /* reject too huge data */
01329     }
01330 
01331     st_free_table(labels_table);
01332 
01333     rb_hash_aset(misc, ID2SYM(rb_intern("arg_size")), INT2FIX(iseq->arg_size));
01334     rb_hash_aset(misc, ID2SYM(rb_intern("local_size")), INT2FIX(iseq->local_size));
01335     rb_hash_aset(misc, ID2SYM(rb_intern("stack_max")), INT2FIX(iseq->stack_max));
01336 
01337     /*
01338      * [:magic, :major_version, :minor_version, :format_type, :misc,
01339      *  :name, :filename, :filepath, :line_no, :type, :locals, :args,
01340      *  :catch_table, :bytecode]
01341      */
01342     rb_ary_push(val, rb_str_new2("YARVInstructionSequence/SimpleDataFormat"));
01343     rb_ary_push(val, INT2FIX(ISEQ_MAJOR_VERSION)); /* major */
01344     rb_ary_push(val, INT2FIX(ISEQ_MINOR_VERSION)); /* minor */
01345     rb_ary_push(val, INT2FIX(1));
01346     rb_ary_push(val, misc);
01347     rb_ary_push(val, iseq->name);
01348     rb_ary_push(val, iseq->filename);
01349     rb_ary_push(val, iseq->filepath);
01350     rb_ary_push(val, iseq->line_no);
01351     rb_ary_push(val, type);
01352     rb_ary_push(val, locals);
01353     rb_ary_push(val, args);
01354     rb_ary_push(val, exception);
01355     rb_ary_push(val, body);
01356     return val;
01357 }
01358 
01359 VALUE
01360 rb_iseq_clone(VALUE iseqval, VALUE newcbase)
01361 {
01362     VALUE newiseq = iseq_alloc(rb_cISeq);
01363     rb_iseq_t *iseq0, *iseq1;
01364 
01365     GetISeqPtr(iseqval, iseq0);
01366     GetISeqPtr(newiseq, iseq1);
01367 
01368     *iseq1 = *iseq0;
01369     iseq1->self = newiseq;
01370     if (!iseq1->orig) {
01371         iseq1->orig = iseqval;
01372     }
01373     if (iseq0->local_iseq == iseq0) {
01374         iseq1->local_iseq = iseq1;
01375     }
01376     if (newcbase) {
01377         iseq1->cref_stack = NEW_BLOCK(newcbase);
01378         if (iseq0->cref_stack->nd_next) {
01379             iseq1->cref_stack->nd_next = iseq0->cref_stack->nd_next;
01380         }
01381         iseq1->klass = newcbase;
01382     }
01383 
01384     return newiseq;
01385 }
01386 
01387 VALUE
01388 rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
01389 {
01390     int i, r, s;
01391     VALUE a, args = rb_ary_new2(iseq->arg_size);
01392     ID req, opt, rest, block;
01393 #define PARAM_TYPE(type) rb_ary_push(a = rb_ary_new2(2), ID2SYM(type))
01394 #define PARAM_ID(i) iseq->local_table[(i)]
01395 #define PARAM(i, type) (                      \
01396         PARAM_TYPE(type),                     \
01397         rb_id2name(PARAM_ID(i)) ?             \
01398         rb_ary_push(a, ID2SYM(PARAM_ID(i))) : \
01399         a)
01400 
01401     CONST_ID(req, "req");
01402     CONST_ID(opt, "opt");
01403     if (is_proc) {
01404         for (i = 0; i < iseq->argc; i++) {
01405             PARAM_TYPE(opt);
01406             rb_ary_push(a, rb_id2name(PARAM_ID(i)) ? ID2SYM(PARAM_ID(i)) : Qnil);
01407             rb_ary_push(args, a);
01408         }
01409     }
01410     else {
01411         for (i = 0; i < iseq->argc; i++) {
01412             rb_ary_push(args, PARAM(i, req));
01413         }
01414     }
01415     r = iseq->arg_rest != -1 ? iseq->arg_rest :
01416         iseq->arg_post_len > 0 ? iseq->arg_post_start :
01417         iseq->arg_block != -1 ? iseq->arg_block :
01418         iseq->arg_size;
01419     for (s = i; i < r; i++) {
01420         PARAM_TYPE(opt);
01421         if (rb_id2name(PARAM_ID(i))) {
01422             rb_ary_push(a, ID2SYM(PARAM_ID(i)));
01423         }
01424         rb_ary_push(args, a);
01425     }
01426     if (iseq->arg_rest != -1) {
01427         CONST_ID(rest, "rest");
01428         rb_ary_push(args, PARAM(iseq->arg_rest, rest));
01429     }
01430     r = iseq->arg_post_start + iseq->arg_post_len;
01431     if (is_proc) {
01432         for (i = iseq->arg_post_start; i < r; i++) {
01433             PARAM_TYPE(opt);
01434             rb_ary_push(a, rb_id2name(PARAM_ID(i)) ? ID2SYM(PARAM_ID(i)) : Qnil);
01435             rb_ary_push(args, a);
01436         }
01437     }
01438     else {
01439         for (i = iseq->arg_post_start; i < r; i++) {
01440             rb_ary_push(args, PARAM(i, req));
01441         }
01442     }
01443     if (iseq->arg_block != -1) {
01444         CONST_ID(block, "block");
01445         rb_ary_push(args, PARAM(iseq->arg_block, block));
01446     }
01447     return args;
01448 }
01449 
01450 /* ruby2cext */
01451 
01452 VALUE
01453 rb_iseq_build_for_ruby2cext(
01454     const rb_iseq_t *iseq_template,
01455     const rb_insn_func_t *func,
01456     const struct iseq_insn_info_entry *insn_info_table,
01457     const char **local_table,
01458     const VALUE *arg_opt_table,
01459     const struct iseq_catch_table_entry *catch_table,
01460     const char *name,
01461     const char *filename,
01462     const unsigned short line_no)
01463 {
01464     unsigned long i;
01465     VALUE iseqval = iseq_alloc(rb_cISeq);
01466     rb_iseq_t *iseq;
01467     GetISeqPtr(iseqval, iseq);
01468 
01469     /* copy iseq */
01470     *iseq = *iseq_template;
01471     iseq->name = rb_str_new2(name);
01472     iseq->filename = rb_str_new2(filename);
01473     iseq->line_no = line_no;
01474     iseq->mark_ary = rb_ary_tmp_new(3);
01475     OBJ_UNTRUST(iseq->mark_ary);
01476     iseq->self = iseqval;
01477 
01478     iseq->iseq = ALLOC_N(VALUE, iseq->iseq_size);
01479 
01480     for (i=0; i<iseq->iseq_size; i+=2) {
01481         iseq->iseq[i] = BIN(opt_call_c_function);
01482         iseq->iseq[i+1] = (VALUE)func;
01483     }
01484 
01485     rb_iseq_translate_threaded_code(iseq);
01486 
01487 #define ALLOC_AND_COPY(dst, src, type, size) do { \
01488   if (size) { \
01489       (dst) = ALLOC_N(type, (size)); \
01490       MEMCPY((dst), (src), type, (size)); \
01491   } \
01492 } while (0)
01493 
01494     ALLOC_AND_COPY(iseq->insn_info_table, insn_info_table,
01495                    struct iseq_insn_info_entry, iseq->insn_info_size);
01496 
01497     ALLOC_AND_COPY(iseq->catch_table, catch_table,
01498                    struct iseq_catch_table_entry, iseq->catch_table_size);
01499 
01500     ALLOC_AND_COPY(iseq->arg_opt_table, arg_opt_table,
01501                    VALUE, iseq->arg_opts);
01502 
01503     set_relation(iseq, 0);
01504 
01505     return iseqval;
01506 }
01507 
01508 void
01509 Init_ISeq(void)
01510 {
01511     /* declare ::RubyVM::InstructionSequence */
01512     rb_cISeq = rb_define_class_under(rb_cRubyVM, "InstructionSequence", rb_cObject);
01513     rb_define_alloc_func(rb_cISeq, iseq_alloc);
01514     rb_define_method(rb_cISeq, "inspect", iseq_inspect, 0);
01515     rb_define_method(rb_cISeq, "disasm", rb_iseq_disasm, 0);
01516     rb_define_method(rb_cISeq, "disassemble", rb_iseq_disasm, 0);
01517     rb_define_method(rb_cISeq, "to_a", iseq_to_a, 0);
01518     rb_define_method(rb_cISeq, "eval", iseq_eval, 0);
01519 
01520 #if 0 /* TBD */
01521     rb_define_method(rb_cISeq, "marshal_dump", iseq_marshal_dump, 0);
01522     rb_define_method(rb_cISeq, "marshal_load", iseq_marshal_load, 1);
01523 #endif
01524 
01525     /* disable this feature because there is no verifier. */
01526     /* rb_define_singleton_method(rb_cISeq, "load", iseq_s_load, -1); */
01527     (void)iseq_s_load;
01528 
01529     rb_define_singleton_method(rb_cISeq, "compile", iseq_s_compile, -1);
01530     rb_define_singleton_method(rb_cISeq, "new", iseq_s_compile, -1);
01531     rb_define_singleton_method(rb_cISeq, "compile_file", iseq_s_compile_file, -1);
01532     rb_define_singleton_method(rb_cISeq, "compile_option", iseq_s_compile_option_get, 0);
01533     rb_define_singleton_method(rb_cISeq, "compile_option=", iseq_s_compile_option_set, 1);
01534     rb_define_singleton_method(rb_cISeq, "disasm", iseq_s_disasm, 1);
01535     rb_define_singleton_method(rb_cISeq, "disassemble", iseq_s_disasm, 1);
01536 }
01537 
01538