Ruby  1.9.3p448(2013-06-27revision41675)
iseq.c
Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   iseq.c -
00004 
00005   $Author: usa $
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     struct st_table *type_map = 0;
00454     rb_iseq_t *iseq;
00455     rb_compile_option_t option;
00456     int i = 0;
00457 
00458     /* [magic, major_version, minor_version, format_type, misc,
00459      *  name, filename, line_no,
00460      *  type, locals, args, exception_table, body]
00461      */
00462 
00463     data        = CHECK_ARRAY(data);
00464 
00465     magic       = CHECK_STRING(rb_ary_entry(data, i++));
00466     version1    = CHECK_INTEGER(rb_ary_entry(data, i++));
00467     version2    = CHECK_INTEGER(rb_ary_entry(data, i++));
00468     format_type = CHECK_INTEGER(rb_ary_entry(data, i++));
00469     misc        = rb_ary_entry(data, i++); /* TODO */
00470 
00471     name        = CHECK_STRING(rb_ary_entry(data, i++));
00472     filename    = CHECK_STRING(rb_ary_entry(data, i++));
00473     filepath    = rb_ary_entry(data, i++);
00474     filepath    = NIL_P(filepath) ? Qnil : CHECK_STRING(filepath);
00475     line_no     = CHECK_INTEGER(rb_ary_entry(data, i++));
00476 
00477     type        = CHECK_SYMBOL(rb_ary_entry(data, i++));
00478     locals      = CHECK_ARRAY(rb_ary_entry(data, i++));
00479 
00480     args        = rb_ary_entry(data, i++);
00481     if (FIXNUM_P(args) || (args = CHECK_ARRAY(args))) {
00482         /* */
00483     }
00484 
00485     exception   = CHECK_ARRAY(rb_ary_entry(data, i++));
00486     body        = CHECK_ARRAY(rb_ary_entry(data, i++));
00487 
00488     GetISeqPtr(iseqval, iseq);
00489     iseq->self = iseqval;
00490 
00491     if (type_map == 0) {
00492         type_map = st_init_numtable();
00493         st_insert(type_map, ID2SYM(rb_intern("top")), ISEQ_TYPE_TOP);
00494         st_insert(type_map, ID2SYM(rb_intern("method")), ISEQ_TYPE_METHOD);
00495         st_insert(type_map, ID2SYM(rb_intern("block")), ISEQ_TYPE_BLOCK);
00496         st_insert(type_map, ID2SYM(rb_intern("class")), ISEQ_TYPE_CLASS);
00497         st_insert(type_map, ID2SYM(rb_intern("rescue")), ISEQ_TYPE_RESCUE);
00498         st_insert(type_map, ID2SYM(rb_intern("ensure")), ISEQ_TYPE_ENSURE);
00499         st_insert(type_map, ID2SYM(rb_intern("eval")), ISEQ_TYPE_EVAL);
00500         st_insert(type_map, ID2SYM(rb_intern("main")), ISEQ_TYPE_MAIN);
00501         st_insert(type_map, ID2SYM(rb_intern("defined_guard")), ISEQ_TYPE_DEFINED_GUARD);
00502     }
00503 
00504     if (st_lookup(type_map, type, &iseq_type) == 0) {
00505         const char *typename = rb_id2name(type);
00506         if (typename)
00507             rb_raise(rb_eTypeError, "unsupport type: :%s", typename);
00508         else
00509             rb_raise(rb_eTypeError, "unsupport type: %p", (void *)type);
00510     }
00511 
00512     if (parent == Qnil) {
00513         parent = 0;
00514     }
00515 
00516     make_compile_option(&option, opt);
00517     prepare_iseq_build(iseq, name, filename, filepath, line_no,
00518                        parent, (enum iseq_type)iseq_type, 0, &option);
00519 
00520     rb_iseq_build_from_ary(iseq, locals, args, exception, body);
00521 
00522     cleanup_iseq_build(iseq);
00523     return iseqval;
00524 }
00525 
00526 static VALUE
00527 iseq_s_load(int argc, VALUE *argv, VALUE self)
00528 {
00529     VALUE data, opt=Qnil;
00530     rb_scan_args(argc, argv, "11", &data, &opt);
00531 
00532     return iseq_load(self, data, 0, opt);
00533 }
00534 
00535 VALUE
00536 rb_iseq_load(VALUE data, VALUE parent, VALUE opt)
00537 {
00538     return iseq_load(rb_cISeq, data, parent, opt);
00539 }
00540 
00541 static NODE *
00542 parse_string(VALUE str, const char *file, int line)
00543 {
00544     VALUE parser = rb_parser_new();
00545     NODE *node = rb_parser_compile_string(parser, file, str, line);
00546 
00547     if (!node) {
00548         rb_exc_raise(GET_THREAD()->errinfo);    /* TODO: check err */
00549     }
00550     return node;
00551 }
00552 
00553 VALUE
00554 rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE filepath, VALUE line, VALUE opt)
00555 {
00556     rb_compile_option_t option;
00557     const char *fn = StringValueCStr(file);
00558     int ln = NUM2INT(line);
00559     NODE *node = parse_string(StringValue(src), fn, ln);
00560     rb_thread_t *th = GET_THREAD();
00561     make_compile_option(&option, opt);
00562 
00563     if (th->base_block && th->base_block->iseq) {
00564         return rb_iseq_new_with_opt(node, th->base_block->iseq->name,
00565                                     file, filepath, line, th->base_block->iseq->self,
00566                                     ISEQ_TYPE_EVAL, &option);
00567     }
00568     else {
00569         return rb_iseq_new_with_opt(node, rb_str_new2("<compiled>"), file, filepath, line, Qfalse,
00570                                     ISEQ_TYPE_TOP, &option);
00571     }
00572 }
00573 
00574 VALUE
00575 rb_iseq_compile(VALUE src, VALUE file, VALUE line)
00576 {
00577     return rb_iseq_compile_with_option(src, file, Qnil, line, Qnil);
00578 }
00579 
00580 static VALUE
00581 iseq_s_compile(int argc, VALUE *argv, VALUE self)
00582 {
00583     VALUE src, file = Qnil, path = Qnil, line = INT2FIX(1), opt = Qnil;
00584 
00585     rb_secure(1);
00586 
00587     rb_scan_args(argc, argv, "14", &src, &file, &path, &line, &opt);
00588     if (NIL_P(file)) file = rb_str_new2("<compiled>");
00589     if (NIL_P(line)) line = INT2FIX(1);
00590 
00591     return rb_iseq_compile_with_option(src, file, path, line, opt);
00592 }
00593 
00594 static VALUE
00595 iseq_s_compile_file(int argc, VALUE *argv, VALUE self)
00596 {
00597     VALUE file, line = INT2FIX(1), opt = Qnil;
00598     VALUE parser;
00599     VALUE f;
00600     NODE *node;
00601     const char *fname;
00602     rb_compile_option_t option;
00603 
00604     rb_secure(1);
00605     rb_scan_args(argc, argv, "11", &file, &opt);
00606     FilePathValue(file);
00607     fname = StringValueCStr(file);
00608 
00609     f = rb_file_open_str(file, "r");
00610 
00611     parser = rb_parser_new();
00612     node = rb_parser_compile_file(parser, fname, f, NUM2INT(line));
00613     make_compile_option(&option, opt);
00614     return rb_iseq_new_with_opt(node, rb_str_new2("<main>"), file,
00615                                 rb_realpath_internal(Qnil, file, 1), line, Qfalse,
00616                                 ISEQ_TYPE_TOP, &option);
00617 }
00618 
00619 static VALUE
00620 iseq_s_compile_option_set(VALUE self, VALUE opt)
00621 {
00622     rb_compile_option_t option;
00623     rb_secure(1);
00624     make_compile_option(&option, opt);
00625     COMPILE_OPTION_DEFAULT = option;
00626     return opt;
00627 }
00628 
00629 static VALUE
00630 iseq_s_compile_option_get(VALUE self)
00631 {
00632     return make_compile_option_value(&COMPILE_OPTION_DEFAULT);
00633 }
00634 
00635 static rb_iseq_t *
00636 iseq_check(VALUE val)
00637 {
00638     rb_iseq_t *iseq;
00639     GetISeqPtr(val, iseq);
00640     if (!iseq->name) {
00641         rb_raise(rb_eTypeError, "uninitialized InstructionSequence");
00642     }
00643     return iseq;
00644 }
00645 
00646 static VALUE
00647 iseq_eval(VALUE self)
00648 {
00649     rb_secure(1);
00650     return rb_iseq_eval(self);
00651 }
00652 
00653 static VALUE
00654 iseq_inspect(VALUE self)
00655 {
00656     rb_iseq_t *iseq;
00657     GetISeqPtr(self, iseq);
00658     if (!iseq->name) {
00659         return rb_sprintf("#<%s: uninitialized>", rb_obj_classname(self));
00660     }
00661 
00662     return rb_sprintf("<%s:%s@%s>",
00663                       rb_obj_classname(self),
00664                       RSTRING_PTR(iseq->name), RSTRING_PTR(iseq->filename));
00665 }
00666 
00667 static
00668 VALUE iseq_data_to_ary(rb_iseq_t *iseq);
00669 
00670 static VALUE
00671 iseq_to_a(VALUE self)
00672 {
00673     rb_iseq_t *iseq = iseq_check(self);
00674     rb_secure(1);
00675     return iseq_data_to_ary(iseq);
00676 }
00677 
00678 int
00679 rb_iseq_first_lineno(rb_iseq_t *iseq)
00680 {
00681     return FIX2INT(iseq->line_no);
00682 }
00683 
00684 /* TODO: search algorithm is brute force.
00685          this should be binary search or so. */
00686 
00687 static struct iseq_insn_info_entry *
00688 get_insn_info(const rb_iseq_t *iseq, const unsigned long pos)
00689 {
00690     unsigned long i, size = iseq->insn_info_size;
00691     struct iseq_insn_info_entry *table = iseq->insn_info_table;
00692 
00693     for (i = 0; i < size; i++) {
00694         if (table[i].position == pos) {
00695             return &table[i];
00696         }
00697     }
00698 
00699     return 0;
00700 }
00701 
00702 static unsigned short
00703 find_line_no(rb_iseq_t *iseq, unsigned long pos)
00704 {
00705     struct iseq_insn_info_entry *entry = get_insn_info(iseq, pos);
00706     if (entry) {
00707         return entry->line_no;
00708     }
00709     else {
00710         return 0;
00711     }
00712 }
00713 
00714 static unsigned short
00715 find_prev_line_no(rb_iseq_t *iseqdat, unsigned long pos)
00716 {
00717     unsigned long i, size = iseqdat->insn_info_size;
00718     struct iseq_insn_info_entry *iiary = iseqdat->insn_info_table;
00719 
00720     for (i = 0; i < size; i++) {
00721         if (iiary[i].position == pos) {
00722             if (i > 0) {
00723                 return iiary[i - 1].line_no;
00724             }
00725             else {
00726                 return 0;
00727             }
00728         }
00729     }
00730 
00731     return 0;
00732 }
00733 
00734 static VALUE
00735 insn_operand_intern(rb_iseq_t *iseq,
00736                     VALUE insn, int op_no, VALUE op,
00737                     int len, size_t pos, VALUE *pnop, VALUE child)
00738 {
00739     const char *types = insn_op_types(insn);
00740     char type = types[op_no];
00741     VALUE ret;
00742 
00743     switch (type) {
00744       case TS_OFFSET:           /* LONG */
00745         ret = rb_sprintf("%"PRIdVALUE, (VALUE)(pos + len + op));
00746         break;
00747 
00748       case TS_NUM:              /* ULONG */
00749         ret = rb_sprintf("%"PRIuVALUE, op);
00750         break;
00751 
00752       case TS_LINDEX:
00753         {
00754             rb_iseq_t *liseq = iseq->local_iseq;
00755             int lidx = liseq->local_size - (int)op;
00756             const char *name = rb_id2name(liseq->local_table[lidx]);
00757 
00758             if (name) {
00759                 ret = rb_str_new2(name);
00760             }
00761             else {
00762                 ret = rb_str_new2("*");
00763             }
00764             break;
00765         }
00766       case TS_DINDEX:{
00767         if (insn == BIN(getdynamic) || insn == BIN(setdynamic)) {
00768             rb_iseq_t *diseq = iseq;
00769             VALUE level = *pnop, i;
00770             const char *name;
00771             for (i = 0; i < level; i++) {
00772                 diseq = diseq->parent_iseq;
00773             }
00774             name = rb_id2name(diseq->local_table[diseq->local_size - op]);
00775 
00776             if (!name) {
00777                 name = "*";
00778             }
00779             ret = rb_str_new2(name);
00780         }
00781         else {
00782             ret = rb_inspect(INT2FIX(op));
00783         }
00784         break;
00785       }
00786       case TS_ID:               /* ID (symbol) */
00787         op = ID2SYM(op);
00788 
00789       case TS_VALUE:            /* VALUE */
00790         op = obj_resurrect(op);
00791         ret = rb_inspect(op);
00792         if (CLASS_OF(op) == rb_cISeq) {
00793             rb_ary_push(child, op);
00794         }
00795         break;
00796 
00797       case TS_ISEQ:             /* iseq */
00798         {
00799             rb_iseq_t *iseq = (rb_iseq_t *)op;
00800             if (iseq) {
00801                 ret = iseq->name;
00802                 if (child) {
00803                     rb_ary_push(child, iseq->self);
00804                 }
00805             }
00806             else {
00807                 ret = rb_str_new2("nil");
00808             }
00809             break;
00810         }
00811       case TS_GENTRY:
00812         {
00813             struct rb_global_entry *entry = (struct rb_global_entry *)op;
00814             ret = rb_str_dup(rb_id2str(entry->id));
00815         }
00816         break;
00817 
00818       case TS_IC:
00819         ret = rb_sprintf("<ic:%"PRIdPTRDIFF">", (struct iseq_inline_cache_entry *)op - iseq->ic_entries);
00820         break;
00821 
00822       case TS_CDHASH:
00823         ret = rb_str_new2("<cdhash>");
00824         break;
00825 
00826       case TS_FUNCPTR:
00827         ret = rb_str_new2("<funcptr>");
00828         break;
00829 
00830       default:
00831         rb_bug("rb_iseq_disasm: unknown operand type: %c", type);
00832     }
00833     return ret;
00834 }
00835 
00840 int
00841 rb_iseq_disasm_insn(VALUE ret, VALUE *iseq, size_t pos,
00842                     rb_iseq_t *iseqdat, VALUE child)
00843 {
00844     VALUE insn = iseq[pos];
00845     int len = insn_len(insn);
00846     int j;
00847     const char *types = insn_op_types(insn);
00848     VALUE str = rb_str_new(0, 0);
00849     const char *insn_name_buff;
00850 
00851     insn_name_buff = insn_name(insn);
00852     if (1) {
00853         rb_str_catf(str, "%04"PRIdSIZE" %-16s ", pos, insn_name_buff);
00854     }
00855     else {
00856         rb_str_catf(str, "%04"PRIdSIZE" %-16.*s ", pos,
00857                     (int)strcspn(insn_name_buff, "_"), insn_name_buff);
00858     }
00859 
00860     for (j = 0; types[j]; j++) {
00861         const char *types = insn_op_types(insn);
00862         VALUE opstr = insn_operand_intern(iseqdat, insn, j, iseq[pos + j + 1],
00863                                           len, pos, &iseq[pos + j + 2],
00864                                           child);
00865         rb_str_concat(str, opstr);
00866 
00867         if (types[j + 1]) {
00868             rb_str_cat2(str, ", ");
00869         }
00870     }
00871 
00872     if (1) {
00873         int line_no = find_line_no(iseqdat, pos);
00874         int prev = find_prev_line_no(iseqdat, pos);
00875         if (line_no && line_no != prev) {
00876             long slen = RSTRING_LEN(str);
00877             slen = (slen > 70) ? 0 : (70 - slen);
00878             str = rb_str_catf(str, "%*s(%4d)", (int)slen, "", line_no);
00879         }
00880     }
00881     else {
00882         /* for debug */
00883         struct iseq_insn_info_entry *entry = get_insn_info(iseqdat, pos);
00884         long slen = RSTRING_LEN(str);
00885         slen = (slen > 60) ? 0 : (60 - slen);
00886         str = rb_str_catf(str, "%*s(line: %d, sp: %d)",
00887                           (int)slen, "", entry->line_no, entry->sp);
00888     }
00889 
00890     if (ret) {
00891         rb_str_cat2(str, "\n");
00892         rb_str_concat(ret, str);
00893     }
00894     else {
00895         printf("%s\n", RSTRING_PTR(str));
00896     }
00897     return len;
00898 }
00899 
00900 static const char *
00901 catch_type(int type)
00902 {
00903     switch (type) {
00904       case CATCH_TYPE_RESCUE:
00905         return "rescue";
00906       case CATCH_TYPE_ENSURE:
00907         return "ensure";
00908       case CATCH_TYPE_RETRY:
00909         return "retry";
00910       case CATCH_TYPE_BREAK:
00911         return "break";
00912       case CATCH_TYPE_REDO:
00913         return "redo";
00914       case CATCH_TYPE_NEXT:
00915         return "next";
00916       default:
00917         rb_bug("unknown catch type (%d)", type);
00918         return 0;
00919     }
00920 }
00921 
00922 VALUE
00923 rb_iseq_disasm(VALUE self)
00924 {
00925     rb_iseq_t *iseqdat = iseq_check(self);
00926     VALUE *iseq;
00927     VALUE str = rb_str_new(0, 0);
00928     VALUE child = rb_ary_new();
00929     unsigned long size;
00930     int i;
00931     long l;
00932     ID *tbl;
00933     size_t n;
00934     enum {header_minlen = 72};
00935 
00936     rb_secure(1);
00937 
00938     iseq = iseqdat->iseq;
00939     size = iseqdat->iseq_size;
00940 
00941     rb_str_cat2(str, "== disasm: ");
00942 
00943     rb_str_concat(str, iseq_inspect(iseqdat->self));
00944     if ((l = RSTRING_LEN(str)) < header_minlen) {
00945         rb_str_resize(str, header_minlen);
00946         memset(RSTRING_PTR(str) + l, '=', header_minlen - l);
00947     }
00948     rb_str_cat2(str, "\n");
00949 
00950     /* show catch table information */
00951     if (iseqdat->catch_table_size != 0) {
00952         rb_str_cat2(str, "== catch table\n");
00953     }
00954     for (i = 0; i < iseqdat->catch_table_size; i++) {
00955         struct iseq_catch_table_entry *entry = &iseqdat->catch_table[i];
00956         rb_str_catf(str,
00957                     "| catch type: %-6s st: %04d ed: %04d sp: %04d cont: %04d\n",
00958                     catch_type((int)entry->type), (int)entry->start,
00959                     (int)entry->end, (int)entry->sp, (int)entry->cont);
00960         if (entry->iseq) {
00961             rb_str_concat(str, rb_iseq_disasm(entry->iseq));
00962         }
00963     }
00964     if (iseqdat->catch_table_size != 0) {
00965         rb_str_cat2(str, "|-------------------------------------"
00966                     "-----------------------------------\n");
00967     }
00968 
00969     /* show local table information */
00970     tbl = iseqdat->local_table;
00971 
00972     if (tbl) {
00973         rb_str_catf(str,
00974                     "local table (size: %d, argc: %d "
00975                     "[opts: %d, rest: %d, post: %d, block: %d] s%d)\n",
00976                     iseqdat->local_size, iseqdat->argc,
00977                     iseqdat->arg_opts, iseqdat->arg_rest,
00978                     iseqdat->arg_post_len, iseqdat->arg_block,
00979                     iseqdat->arg_simple);
00980 
00981         for (i = 0; i < iseqdat->local_table_size; i++) {
00982             const char *name = rb_id2name(tbl[i]);
00983             char info[0x100];
00984             char argi[0x100] = "";
00985             char opti[0x100] = "";
00986 
00987             if (iseqdat->arg_opts) {
00988                 int argc = iseqdat->argc;
00989                 int opts = iseqdat->arg_opts;
00990                 if (i >= argc && i < argc + opts - 1) {
00991                     snprintf(opti, sizeof(opti), "Opt=%"PRIdVALUE,
00992                              iseqdat->arg_opt_table[i - argc]);
00993                 }
00994             }
00995 
00996             snprintf(argi, sizeof(argi), "%s%s%s%s%s",  /* arg, opts, rest, post  block */
00997                      iseqdat->argc > i ? "Arg" : "",
00998                      opti,
00999                      iseqdat->arg_rest == i ? "Rest" : "",
01000                      (iseqdat->arg_post_start <= i &&
01001                       i < iseqdat->arg_post_start + iseqdat->arg_post_len) ? "Post" : "",
01002                      iseqdat->arg_block == i ? "Block" : "");
01003 
01004             snprintf(info, sizeof(info), "%s%s%s%s", name ? name : "?",
01005                      *argi ? "<" : "", argi, *argi ? ">" : "");
01006 
01007             rb_str_catf(str, "[%2d] %-11s", iseqdat->local_size - i, info);
01008         }
01009         rb_str_cat2(str, "\n");
01010     }
01011 
01012     /* show each line */
01013     for (n = 0; n < size;) {
01014         n += rb_iseq_disasm_insn(str, iseq, n, iseqdat, child);
01015     }
01016 
01017     for (i = 0; i < RARRAY_LEN(child); i++) {
01018         VALUE isv = rb_ary_entry(child, i);
01019         rb_str_concat(str, rb_iseq_disasm(isv));
01020     }
01021 
01022     return str;
01023 }
01024 
01025 static VALUE
01026 iseq_s_disasm(VALUE klass, VALUE body)
01027 {
01028     VALUE ret = Qnil;
01029     rb_iseq_t *iseq;
01030 
01031     rb_secure(1);
01032 
01033     if (rb_obj_is_proc(body)) {
01034         rb_proc_t *proc;
01035         GetProcPtr(body, proc);
01036         iseq = proc->block.iseq;
01037         if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
01038             ret = rb_iseq_disasm(iseq->self);
01039         }
01040     }
01041     else if ((iseq = rb_method_get_iseq(body)) != 0) {
01042         ret = rb_iseq_disasm(iseq->self);
01043     }
01044 
01045     return ret;
01046 }
01047 
01048 const char *
01049 ruby_node_name(int node)
01050 {
01051     switch (node) {
01052 #include "node_name.inc"
01053       default:
01054         rb_bug("unknown node (%d)", node);
01055         return 0;
01056     }
01057 }
01058 
01059 #define DECL_SYMBOL(name) \
01060   static VALUE sym_##name
01061 
01062 #define INIT_SYMBOL(name) \
01063   sym_##name = ID2SYM(rb_intern(#name))
01064 
01065 static VALUE
01066 register_label(struct st_table *table, unsigned long idx)
01067 {
01068     VALUE sym;
01069     char buff[8 + (sizeof(idx) * CHAR_BIT * 32 / 100)];
01070 
01071     snprintf(buff, sizeof(buff), "label_%lu", idx);
01072     sym = ID2SYM(rb_intern(buff));
01073     st_insert(table, idx, sym);
01074     return sym;
01075 }
01076 
01077 static VALUE
01078 exception_type2symbol(VALUE type)
01079 {
01080     ID id;
01081     switch(type) {
01082       case CATCH_TYPE_RESCUE: CONST_ID(id, "rescue"); break;
01083       case CATCH_TYPE_ENSURE: CONST_ID(id, "ensure"); break;
01084       case CATCH_TYPE_RETRY:  CONST_ID(id, "retry");  break;
01085       case CATCH_TYPE_BREAK:  CONST_ID(id, "break");  break;
01086       case CATCH_TYPE_REDO:   CONST_ID(id, "redo");   break;
01087       case CATCH_TYPE_NEXT:   CONST_ID(id, "next");   break;
01088       default:
01089         rb_bug("...");
01090     }
01091     return ID2SYM(id);
01092 }
01093 
01094 static int
01095 cdhash_each(VALUE key, VALUE value, VALUE ary)
01096 {
01097     rb_ary_push(ary, obj_resurrect(key));
01098     rb_ary_push(ary, value);
01099     return ST_CONTINUE;
01100 }
01101 
01102 static VALUE
01103 iseq_data_to_ary(rb_iseq_t *iseq)
01104 {
01105     long i, pos;
01106     int line = 0;
01107     VALUE *seq;
01108 
01109     VALUE val = rb_ary_new();
01110     VALUE type; /* Symbol */
01111     VALUE locals = rb_ary_new();
01112     VALUE args = rb_ary_new();
01113     VALUE body = rb_ary_new(); /* [[:insn1, ...], ...] */
01114     VALUE nbody;
01115     VALUE exception = rb_ary_new(); /* [[....]] */
01116     VALUE misc = rb_hash_new();
01117 
01118     static VALUE insn_syms[VM_INSTRUCTION_SIZE];
01119     struct st_table *labels_table = st_init_numtable();
01120 
01121     DECL_SYMBOL(top);
01122     DECL_SYMBOL(method);
01123     DECL_SYMBOL(block);
01124     DECL_SYMBOL(class);
01125     DECL_SYMBOL(rescue);
01126     DECL_SYMBOL(ensure);
01127     DECL_SYMBOL(eval);
01128     DECL_SYMBOL(main);
01129     DECL_SYMBOL(defined_guard);
01130 
01131     if (sym_top == 0) {
01132         int i;
01133         for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
01134             insn_syms[i] = ID2SYM(rb_intern(insn_name(i)));
01135         }
01136         INIT_SYMBOL(top);
01137         INIT_SYMBOL(method);
01138         INIT_SYMBOL(block);
01139         INIT_SYMBOL(class);
01140         INIT_SYMBOL(rescue);
01141         INIT_SYMBOL(ensure);
01142         INIT_SYMBOL(eval);
01143         INIT_SYMBOL(main);
01144         INIT_SYMBOL(defined_guard);
01145     }
01146 
01147     /* type */
01148     switch(iseq->type) {
01149       case ISEQ_TYPE_TOP:    type = sym_top;    break;
01150       case ISEQ_TYPE_METHOD: type = sym_method; break;
01151       case ISEQ_TYPE_BLOCK:  type = sym_block;  break;
01152       case ISEQ_TYPE_CLASS:  type = sym_class;  break;
01153       case ISEQ_TYPE_RESCUE: type = sym_rescue; break;
01154       case ISEQ_TYPE_ENSURE: type = sym_ensure; break;
01155       case ISEQ_TYPE_EVAL:   type = sym_eval;   break;
01156       case ISEQ_TYPE_MAIN:   type = sym_main;   break;
01157       case ISEQ_TYPE_DEFINED_GUARD: type = sym_defined_guard; break;
01158       default: rb_bug("unsupported iseq type");
01159     };
01160 
01161     /* locals */
01162     for (i=0; i<iseq->local_table_size; i++) {
01163         ID lid = iseq->local_table[i];
01164         if (lid) {
01165             if (rb_id2str(lid)) rb_ary_push(locals, ID2SYM(lid));
01166         }
01167         else {
01168             rb_ary_push(locals, ID2SYM(rb_intern("#arg_rest")));
01169         }
01170     }
01171 
01172     /* args */
01173     {
01174         /*
01175          * [argc,                 # argc
01176          *  [label1, label2, ...] # opts
01177          *  rest index,
01178          *  post_len
01179          *  post_start
01180          *  block index,
01181          *  simple,
01182          * ]
01183          */
01184         VALUE arg_opt_labels = rb_ary_new();
01185         int j;
01186 
01187         for (j=0; j<iseq->arg_opts; j++) {
01188             rb_ary_push(arg_opt_labels,
01189                         register_label(labels_table, iseq->arg_opt_table[j]));
01190         }
01191 
01192         /* commit */
01193         if (iseq->arg_simple == 1) {
01194             args = INT2FIX(iseq->argc);
01195         }
01196         else {
01197             rb_ary_push(args, INT2FIX(iseq->argc));
01198             rb_ary_push(args, arg_opt_labels);
01199             rb_ary_push(args, INT2FIX(iseq->arg_post_len));
01200             rb_ary_push(args, INT2FIX(iseq->arg_post_start));
01201             rb_ary_push(args, INT2FIX(iseq->arg_rest));
01202             rb_ary_push(args, INT2FIX(iseq->arg_block));
01203             rb_ary_push(args, INT2FIX(iseq->arg_simple));
01204         }
01205     }
01206 
01207     /* body */
01208     for (seq = iseq->iseq; seq < iseq->iseq + iseq->iseq_size; ) {
01209         VALUE insn = *seq++;
01210         int j, len = insn_len(insn);
01211         VALUE *nseq = seq + len - 1;
01212         VALUE ary = rb_ary_new2(len);
01213 
01214         rb_ary_push(ary, insn_syms[insn]);
01215         for (j=0; j<len-1; j++, seq++) {
01216             switch (insn_op_type(insn, j)) {
01217               case TS_OFFSET: {
01218                 unsigned long idx = nseq - iseq->iseq + *seq;
01219                 rb_ary_push(ary, register_label(labels_table, idx));
01220                 break;
01221               }
01222               case TS_LINDEX:
01223               case TS_DINDEX:
01224               case TS_NUM:
01225                 rb_ary_push(ary, INT2FIX(*seq));
01226                 break;
01227               case TS_VALUE:
01228                 rb_ary_push(ary, obj_resurrect(*seq));
01229                 break;
01230               case TS_ISEQ:
01231                 {
01232                     rb_iseq_t *iseq = (rb_iseq_t *)*seq;
01233                     if (iseq) {
01234                         VALUE val = iseq_data_to_ary(iseq);
01235                         rb_ary_push(ary, val);
01236                     }
01237                     else {
01238                         rb_ary_push(ary, Qnil);
01239                     }
01240                 }
01241                 break;
01242               case TS_GENTRY:
01243                 {
01244                     struct rb_global_entry *entry = (struct rb_global_entry *)*seq;
01245                     rb_ary_push(ary, ID2SYM(entry->id));
01246                 }
01247                 break;
01248               case TS_IC: {
01249                   struct iseq_inline_cache_entry *ic = (struct iseq_inline_cache_entry *)*seq;
01250                     rb_ary_push(ary, INT2FIX(ic - iseq->ic_entries));
01251                 }
01252                 break;
01253               case TS_ID:
01254                 rb_ary_push(ary, ID2SYM(*seq));
01255                 break;
01256               case TS_CDHASH:
01257                 {
01258                     VALUE hash = *seq;
01259                     VALUE val = rb_ary_new();
01260                     int i;
01261 
01262                     rb_hash_foreach(hash, cdhash_each, val);
01263 
01264                     for (i=0; i<RARRAY_LEN(val); i+=2) {
01265                         VALUE pos = FIX2INT(rb_ary_entry(val, i+1));
01266                         unsigned long idx = nseq - iseq->iseq + pos;
01267 
01268                         rb_ary_store(val, i+1,
01269                                      register_label(labels_table, idx));
01270                     }
01271                     rb_ary_push(ary, val);
01272                 }
01273                 break;
01274               default:
01275                 rb_bug("unknown operand: %c", insn_op_type(insn, j));
01276             }
01277         }
01278         rb_ary_push(body, ary);
01279     }
01280 
01281     nbody = body;
01282 
01283     /* exception */
01284     for (i=0; i<iseq->catch_table_size; i++) {
01285         VALUE ary = rb_ary_new();
01286         struct iseq_catch_table_entry *entry = &iseq->catch_table[i];
01287         rb_ary_push(ary, exception_type2symbol(entry->type));
01288         if (entry->iseq) {
01289             rb_iseq_t *eiseq;
01290             GetISeqPtr(entry->iseq, eiseq);
01291             rb_ary_push(ary, iseq_data_to_ary(eiseq));
01292         }
01293         else {
01294             rb_ary_push(ary, Qnil);
01295         }
01296         rb_ary_push(ary, register_label(labels_table, entry->start));
01297         rb_ary_push(ary, register_label(labels_table, entry->end));
01298         rb_ary_push(ary, register_label(labels_table, entry->cont));
01299         rb_ary_push(ary, INT2FIX(entry->sp));
01300         rb_ary_push(exception, ary);
01301     }
01302 
01303     /* make body with labels and insert line number */
01304     body = rb_ary_new();
01305 
01306     for (i=0, pos=0; i<RARRAY_LEN(nbody); i++) {
01307         VALUE ary = RARRAY_PTR(nbody)[i];
01308         st_data_t label;
01309 
01310         if (st_lookup(labels_table, pos, &label)) {
01311             rb_ary_push(body, (VALUE)label);
01312         }
01313 
01314         if (iseq->insn_info_table[i].line_no != line) {
01315             line = iseq->insn_info_table[i].line_no;
01316             rb_ary_push(body, INT2FIX(line));
01317         }
01318 
01319         rb_ary_push(body, ary);
01320         pos += RARRAY_LENINT(ary); /* reject too huge data */
01321     }
01322 
01323     st_free_table(labels_table);
01324 
01325     rb_hash_aset(misc, ID2SYM(rb_intern("arg_size")), INT2FIX(iseq->arg_size));
01326     rb_hash_aset(misc, ID2SYM(rb_intern("local_size")), INT2FIX(iseq->local_size));
01327     rb_hash_aset(misc, ID2SYM(rb_intern("stack_max")), INT2FIX(iseq->stack_max));
01328 
01329     /*
01330      * [:magic, :major_version, :minor_version, :format_type, :misc,
01331      *  :name, :filename, :filepath, :line_no, :type, :locals, :args,
01332      *  :catch_table, :bytecode]
01333      */
01334     rb_ary_push(val, rb_str_new2("YARVInstructionSequence/SimpleDataFormat"));
01335     rb_ary_push(val, INT2FIX(ISEQ_MAJOR_VERSION)); /* major */
01336     rb_ary_push(val, INT2FIX(ISEQ_MINOR_VERSION)); /* minor */
01337     rb_ary_push(val, INT2FIX(1));
01338     rb_ary_push(val, misc);
01339     rb_ary_push(val, iseq->name);
01340     rb_ary_push(val, iseq->filename);
01341     rb_ary_push(val, iseq->filepath);
01342     rb_ary_push(val, iseq->line_no);
01343     rb_ary_push(val, type);
01344     rb_ary_push(val, locals);
01345     rb_ary_push(val, args);
01346     rb_ary_push(val, exception);
01347     rb_ary_push(val, body);
01348     return val;
01349 }
01350 
01351 VALUE
01352 rb_iseq_clone(VALUE iseqval, VALUE newcbase)
01353 {
01354     VALUE newiseq = iseq_alloc(rb_cISeq);
01355     rb_iseq_t *iseq0, *iseq1;
01356 
01357     GetISeqPtr(iseqval, iseq0);
01358     GetISeqPtr(newiseq, iseq1);
01359 
01360     *iseq1 = *iseq0;
01361     iseq1->self = newiseq;
01362     if (!iseq1->orig) {
01363         iseq1->orig = iseqval;
01364     }
01365     if (iseq0->local_iseq == iseq0) {
01366         iseq1->local_iseq = iseq1;
01367     }
01368     if (newcbase) {
01369         iseq1->cref_stack = NEW_BLOCK(newcbase);
01370         if (iseq0->cref_stack->nd_next) {
01371             iseq1->cref_stack->nd_next = iseq0->cref_stack->nd_next;
01372         }
01373         iseq1->klass = newcbase;
01374     }
01375 
01376     return newiseq;
01377 }
01378 
01379 VALUE
01380 rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
01381 {
01382     int i, r, s;
01383     VALUE a, args = rb_ary_new2(iseq->arg_size);
01384     ID req, opt, rest, block;
01385 #define PARAM_TYPE(type) rb_ary_push(a = rb_ary_new2(2), ID2SYM(type))
01386 #define PARAM_ID(i) iseq->local_table[(i)]
01387 #define PARAM(i, type) (                      \
01388         PARAM_TYPE(type),                     \
01389         rb_id2name(PARAM_ID(i)) ?             \
01390         rb_ary_push(a, ID2SYM(PARAM_ID(i))) : \
01391         a)
01392 
01393     CONST_ID(req, "req");
01394     CONST_ID(opt, "opt");
01395     if (is_proc) {
01396         for (i = 0; i < iseq->argc; i++) {
01397             PARAM_TYPE(opt);
01398             rb_ary_push(a, rb_id2name(PARAM_ID(i)) ? ID2SYM(PARAM_ID(i)) : Qnil);
01399             rb_ary_push(args, a);
01400         }
01401     }
01402     else {
01403         for (i = 0; i < iseq->argc; i++) {
01404             rb_ary_push(args, PARAM(i, req));
01405         }
01406     }
01407     r = iseq->arg_rest != -1 ? iseq->arg_rest :
01408         iseq->arg_post_len > 0 ? iseq->arg_post_start :
01409         iseq->arg_block != -1 ? iseq->arg_block :
01410         iseq->arg_size;
01411     for (s = i; i < r; i++) {
01412         PARAM_TYPE(opt);
01413         if (rb_id2name(PARAM_ID(i))) {
01414             rb_ary_push(a, ID2SYM(PARAM_ID(i)));
01415         }
01416         rb_ary_push(args, a);
01417     }
01418     if (iseq->arg_rest != -1) {
01419         CONST_ID(rest, "rest");
01420         rb_ary_push(args, PARAM(iseq->arg_rest, rest));
01421     }
01422     r = iseq->arg_post_start + iseq->arg_post_len;
01423     if (is_proc) {
01424         for (i = iseq->arg_post_start; i < r; i++) {
01425             PARAM_TYPE(opt);
01426             rb_ary_push(a, rb_id2name(PARAM_ID(i)) ? ID2SYM(PARAM_ID(i)) : Qnil);
01427             rb_ary_push(args, a);
01428         }
01429     }
01430     else {
01431         for (i = iseq->arg_post_start; i < r; i++) {
01432             rb_ary_push(args, PARAM(i, req));
01433         }
01434     }
01435     if (iseq->arg_block != -1) {
01436         CONST_ID(block, "block");
01437         rb_ary_push(args, PARAM(iseq->arg_block, block));
01438     }
01439     return args;
01440 }
01441 
01442 /* ruby2cext */
01443 
01444 VALUE
01445 rb_iseq_build_for_ruby2cext(
01446     const rb_iseq_t *iseq_template,
01447     const rb_insn_func_t *func,
01448     const struct iseq_insn_info_entry *insn_info_table,
01449     const char **local_table,
01450     const VALUE *arg_opt_table,
01451     const struct iseq_catch_table_entry *catch_table,
01452     const char *name,
01453     const char *filename,
01454     const unsigned short line_no)
01455 {
01456     unsigned long i;
01457     VALUE iseqval = iseq_alloc(rb_cISeq);
01458     rb_iseq_t *iseq;
01459     GetISeqPtr(iseqval, iseq);
01460 
01461     /* copy iseq */
01462     *iseq = *iseq_template;
01463     iseq->name = rb_str_new2(name);
01464     iseq->filename = rb_str_new2(filename);
01465     iseq->line_no = line_no;
01466     iseq->mark_ary = rb_ary_tmp_new(3);
01467     OBJ_UNTRUST(iseq->mark_ary);
01468     iseq->self = iseqval;
01469 
01470     iseq->iseq = ALLOC_N(VALUE, iseq->iseq_size);
01471 
01472     for (i=0; i<iseq->iseq_size; i+=2) {
01473         iseq->iseq[i] = BIN(opt_call_c_function);
01474         iseq->iseq[i+1] = (VALUE)func;
01475     }
01476 
01477     rb_iseq_translate_threaded_code(iseq);
01478 
01479 #define ALLOC_AND_COPY(dst, src, type, size) do { \
01480   if (size) { \
01481       (dst) = ALLOC_N(type, (size)); \
01482       MEMCPY((dst), (src), type, (size)); \
01483   } \
01484 } while (0)
01485 
01486     ALLOC_AND_COPY(iseq->insn_info_table, insn_info_table,
01487                    struct iseq_insn_info_entry, iseq->insn_info_size);
01488 
01489     ALLOC_AND_COPY(iseq->catch_table, catch_table,
01490                    struct iseq_catch_table_entry, iseq->catch_table_size);
01491 
01492     ALLOC_AND_COPY(iseq->arg_opt_table, arg_opt_table,
01493                    VALUE, iseq->arg_opts);
01494 
01495     set_relation(iseq, 0);
01496 
01497     return iseqval;
01498 }
01499 
01500 void
01501 Init_ISeq(void)
01502 {
01503     /* declare ::RubyVM::InstructionSequence */
01504     rb_cISeq = rb_define_class_under(rb_cRubyVM, "InstructionSequence", rb_cObject);
01505     rb_define_alloc_func(rb_cISeq, iseq_alloc);
01506     rb_define_method(rb_cISeq, "inspect", iseq_inspect, 0);
01507     rb_define_method(rb_cISeq, "disasm", rb_iseq_disasm, 0);
01508     rb_define_method(rb_cISeq, "disassemble", rb_iseq_disasm, 0);
01509     rb_define_method(rb_cISeq, "to_a", iseq_to_a, 0);
01510     rb_define_method(rb_cISeq, "eval", iseq_eval, 0);
01511 
01512 #if 0 /* TBD */
01513     rb_define_method(rb_cISeq, "marshal_dump", iseq_marshal_dump, 0);
01514     rb_define_method(rb_cISeq, "marshal_load", iseq_marshal_load, 1);
01515 #endif
01516 
01517     /* disable this feature because there is no verifier. */
01518     /* rb_define_singleton_method(rb_cISeq, "load", iseq_s_load, -1); */
01519     (void)iseq_s_load;
01520 
01521     rb_define_singleton_method(rb_cISeq, "compile", iseq_s_compile, -1);
01522     rb_define_singleton_method(rb_cISeq, "new", iseq_s_compile, -1);
01523     rb_define_singleton_method(rb_cISeq, "compile_file", iseq_s_compile_file, -1);
01524     rb_define_singleton_method(rb_cISeq, "compile_option", iseq_s_compile_option_get, 0);
01525     rb_define_singleton_method(rb_cISeq, "compile_option=", iseq_s_compile_option_set, 1);
01526     rb_define_singleton_method(rb_cISeq, "disasm", iseq_s_disasm, 1);
01527     rb_define_singleton_method(rb_cISeq, "disassemble", iseq_s_disasm, 1);
01528 }
01529 
01530