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