iseq.c

Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   iseq.c -
00004 
00005   $Author: yugui $
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 
00014 /* #define RUBY_MARK_FREE_DEBUG 1 */
00015 #include "gc.h"
00016 #include "vm_core.h"
00017 #include "iseq.h"
00018 
00019 #include "insns.inc"
00020 #include "insns_info.inc"
00021 
00022 VALUE rb_cISeq;
00023 
00024 #define hidden_obj_p(obj) (!SPECIAL_CONST_P(obj) && !RBASIC(obj)->klass)
00025 
00026 static inline VALUE
00027 obj_resurrect(VALUE obj)
00028 {
00029     if (hidden_obj_p(obj)) {
00030         switch (BUILTIN_TYPE(obj)) {
00031           case T_STRING:
00032             obj = rb_str_resurrect(obj);
00033             break;
00034           case T_ARRAY:
00035             obj = rb_ary_resurrect(obj);
00036             break;
00037         }
00038     }
00039     return obj;
00040 }
00041 
00042 static void
00043 compile_data_free(struct iseq_compile_data *compile_data)
00044 {
00045     if (compile_data) {
00046         struct iseq_compile_data_storage *cur, *next;
00047         cur = compile_data->storage_head;
00048         while (cur) {
00049             next = cur->next;
00050             ruby_xfree(cur);
00051             cur = next;
00052         }
00053         ruby_xfree(compile_data);
00054     }
00055 }
00056 
00057 static void
00058 iseq_free(void *ptr)
00059 {
00060     rb_iseq_t *iseq;
00061     RUBY_FREE_ENTER("iseq");
00062 
00063     if (ptr) {
00064         iseq = ptr;
00065         if (!iseq->orig) {
00066             /* It's possible that strings are freed */
00067             if (0) {
00068                 RUBY_GC_INFO("%s @ %s\n", RSTRING_PTR(iseq->name),
00069                                           RSTRING_PTR(iseq->filename));
00070             }
00071 
00072             if (iseq->iseq != iseq->iseq_encoded) {
00073                 RUBY_FREE_UNLESS_NULL(iseq->iseq_encoded);
00074             }
00075 
00076             RUBY_FREE_UNLESS_NULL(iseq->iseq);
00077             RUBY_FREE_UNLESS_NULL(iseq->insn_info_table);
00078             RUBY_FREE_UNLESS_NULL(iseq->local_table);
00079             RUBY_FREE_UNLESS_NULL(iseq->ic_entries);
00080             RUBY_FREE_UNLESS_NULL(iseq->catch_table);
00081             RUBY_FREE_UNLESS_NULL(iseq->arg_opt_table);
00082             compile_data_free(iseq->compile_data);
00083         }
00084         ruby_xfree(ptr);
00085     }
00086     RUBY_FREE_LEAVE("iseq");
00087 }
00088 
00089 static void
00090 iseq_mark(void *ptr)
00091 {
00092     RUBY_MARK_ENTER("iseq");
00093 
00094     if (ptr) {
00095         rb_iseq_t *iseq = ptr;
00096 
00097         RUBY_GC_INFO("%s @ %s\n", RSTRING_PTR(iseq->name), RSTRING_PTR(iseq->filename));
00098         RUBY_MARK_UNLESS_NULL(iseq->mark_ary);
00099         RUBY_MARK_UNLESS_NULL(iseq->name);
00100         RUBY_MARK_UNLESS_NULL(iseq->filename);
00101         RUBY_MARK_UNLESS_NULL(iseq->filepath);
00102         RUBY_MARK_UNLESS_NULL((VALUE)iseq->cref_stack);
00103         RUBY_MARK_UNLESS_NULL(iseq->klass);
00104         RUBY_MARK_UNLESS_NULL(iseq->coverage);
00105 #if 0
00106         RUBY_MARK_UNLESS_NULL((VALUE)iseq->node);
00107         RUBY_MARK_UNLESS_NULL(iseq->cached_special_block);
00108 #endif
00109         RUBY_MARK_UNLESS_NULL(iseq->orig);
00110 
00111         if (iseq->compile_data != 0) {
00112             struct iseq_compile_data *const compile_data = iseq->compile_data;
00113             RUBY_MARK_UNLESS_NULL(compile_data->mark_ary);
00114             RUBY_MARK_UNLESS_NULL(compile_data->err_info);
00115             RUBY_MARK_UNLESS_NULL(compile_data->catch_table_ary);
00116         }
00117     }
00118     RUBY_MARK_LEAVE("iseq");
00119 }
00120 
00121 static size_t
00122 iseq_memsize(const void *ptr)
00123 {
00124     size_t size = sizeof(rb_iseq_t);
00125     const rb_iseq_t *iseq;
00126 
00127     if (ptr) {
00128         iseq = ptr;
00129         if (!iseq->orig) {
00130             if (iseq->iseq != iseq->iseq_encoded) {
00131                 size += iseq->iseq_size * sizeof(VALUE);
00132             }
00133 
00134             size += iseq->iseq_size * sizeof(VALUE);
00135             size += iseq->insn_info_size * sizeof(struct iseq_insn_info_entry);
00136             size += iseq->local_table_size * sizeof(ID);
00137             size += iseq->catch_table_size * sizeof(struct iseq_catch_table_entry);
00138             size += iseq->arg_opts * sizeof(VALUE);
00139             size += iseq->ic_size * sizeof(struct iseq_inline_cache_entry);
00140 
00141             if (iseq->compile_data) {
00142                 struct iseq_compile_data_storage *cur;
00143 
00144                 cur = iseq->compile_data->storage_head;
00145                 while (cur) {
00146                     size += cur->size + sizeof(struct iseq_compile_data_storage);
00147                     cur = cur->next;
00148                 }
00149                 size += sizeof(struct iseq_compile_data);
00150             }
00151         }
00152     }
00153 
00154     return size;
00155 }
00156 
00157 static const rb_data_type_t iseq_data_type = {
00158     "iseq",
00159     iseq_mark,
00160     iseq_free,
00161     iseq_memsize,
00162 };
00163 
00164 static VALUE
00165 iseq_alloc(VALUE klass)
00166 {
00167     rb_iseq_t *iseq;
00168     return TypedData_Make_Struct(klass, rb_iseq_t, &iseq_data_type, iseq);
00169 }
00170 
00171 static void
00172 set_relation(rb_iseq_t *iseq, const VALUE parent)
00173 {
00174     const VALUE type = iseq->type;
00175     rb_thread_t *th = GET_THREAD();
00176 
00177     /* set class nest stack */
00178     if (type == ISEQ_TYPE_TOP) {
00179         /* toplevel is private */
00180         iseq->cref_stack = NEW_BLOCK(rb_cObject);
00181         iseq->cref_stack->nd_file = 0;
00182         iseq->cref_stack->nd_visi = NOEX_PRIVATE;
00183         if (th->top_wrapper) {
00184             NODE *cref = NEW_BLOCK(th->top_wrapper);
00185             cref->nd_file = 0;
00186             cref->nd_visi = NOEX_PRIVATE;
00187             cref->nd_next = iseq->cref_stack;
00188             iseq->cref_stack = cref;
00189         }
00190     }
00191     else if (type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) {
00192         iseq->cref_stack = NEW_BLOCK(0); /* place holder */
00193         iseq->cref_stack->nd_file = 0;
00194     }
00195     else if (RTEST(parent)) {
00196         rb_iseq_t *piseq;
00197         GetISeqPtr(parent, piseq);
00198         iseq->cref_stack = piseq->cref_stack;
00199     }
00200 
00201     if (type == ISEQ_TYPE_TOP ||
00202         type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) {
00203         iseq->local_iseq = iseq;
00204     }
00205     else if (RTEST(parent)) {
00206         rb_iseq_t *piseq;
00207         GetISeqPtr(parent, piseq);
00208         iseq->local_iseq = piseq->local_iseq;
00209     }
00210 
00211     if (RTEST(parent)) {
00212         rb_iseq_t *piseq;
00213         GetISeqPtr(parent, piseq);
00214         iseq->parent_iseq = piseq;
00215     }
00216 }
00217 
00218 VALUE rb_realpath_internal(VALUE basedir, VALUE path, int strict);
00219 
00220 static VALUE
00221 prepare_iseq_build(rb_iseq_t *iseq,
00222                    VALUE name, VALUE filename, VALUE filepath, VALUE line_no,
00223                    VALUE parent, VALUE type, VALUE block_opt,
00224                    const rb_compile_option_t *option)
00225 {
00226     OBJ_FREEZE(name);
00227     OBJ_FREEZE(filename);
00228 
00229     iseq->name = name;
00230     iseq->filename = filename;
00231     iseq->filepath = filepath == Qnil ? Qnil : rb_realpath_internal(Qnil, filepath, 1);
00232     iseq->line_no = line_no;
00233     iseq->defined_method_id = 0;
00234     iseq->mark_ary = rb_ary_tmp_new(3);
00235     OBJ_UNTRUST(iseq->mark_ary);
00236     RBASIC(iseq->mark_ary)->klass = 0;
00237 
00238     iseq->type = type;
00239     iseq->arg_rest = -1;
00240     iseq->arg_block = -1;
00241     iseq->klass = 0;
00242 
00243     /*
00244      * iseq->special_block_builder = GC_GUARDED_PTR_REF(block_opt);
00245      * iseq->cached_special_block_builder = 0;
00246      * iseq->cached_special_block = 0;
00247      */
00248 
00249     iseq->compile_data = ALLOC(struct iseq_compile_data);
00250     MEMZERO(iseq->compile_data, struct iseq_compile_data, 1);
00251     iseq->compile_data->mark_ary = rb_ary_tmp_new(3);
00252 
00253     iseq->compile_data->storage_head = iseq->compile_data->storage_current =
00254       (struct iseq_compile_data_storage *)
00255         ALLOC_N(char, INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE +
00256                 sizeof(struct iseq_compile_data_storage));
00257 
00258     iseq->compile_data->catch_table_ary = rb_ary_new();
00259     iseq->compile_data->storage_head->pos = 0;
00260     iseq->compile_data->storage_head->next = 0;
00261     iseq->compile_data->storage_head->size =
00262       INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE;
00263     iseq->compile_data->storage_head->buff =
00264       (char *)(&iseq->compile_data->storage_head->buff + 1);
00265     iseq->compile_data->option = option;
00266     iseq->compile_data->last_coverable_line = -1;
00267 
00268     set_relation(iseq, parent);
00269 
00270     iseq->coverage = Qfalse;
00271     if (!GET_THREAD()->parse_in_eval) {
00272         extern VALUE rb_get_coverages(void);
00273         VALUE coverages = rb_get_coverages();
00274         if (RTEST(coverages)) {
00275             iseq->coverage = rb_hash_lookup(coverages, filename);
00276             if (NIL_P(iseq->coverage)) iseq->coverage = Qfalse;
00277         }
00278     }
00279 
00280     return Qtrue;
00281 }
00282 
00283 static VALUE
00284 cleanup_iseq_build(rb_iseq_t *iseq)
00285 {
00286     struct iseq_compile_data *data = iseq->compile_data;
00287     VALUE err = data->err_info;
00288     iseq->compile_data = 0;
00289     compile_data_free(data);
00290 
00291     if (RTEST(err)) {
00292         rb_funcall2(err, rb_intern("set_backtrace"), 1, &iseq->filename);
00293         rb_exc_raise(err);
00294     }
00295     return Qtrue;
00296 }
00297 
00298 static rb_compile_option_t COMPILE_OPTION_DEFAULT = {
00299     OPT_INLINE_CONST_CACHE, /* int inline_const_cache; */
00300     OPT_PEEPHOLE_OPTIMIZATION, /* int peephole_optimization; */
00301     OPT_TAILCALL_OPTIMIZATION, /* int tailcall_optimization */
00302     OPT_SPECIALISED_INSTRUCTION, /* int specialized_instruction; */
00303     OPT_OPERANDS_UNIFICATION, /* int operands_unification; */
00304     OPT_INSTRUCTIONS_UNIFICATION, /* int instructions_unification; */
00305     OPT_STACK_CACHING, /* int stack_caching; */
00306     OPT_TRACE_INSTRUCTION, /* int trace_instruction */
00307 };
00308 static const rb_compile_option_t COMPILE_OPTION_FALSE = {0};
00309 
00310 static void
00311 make_compile_option(rb_compile_option_t *option, VALUE opt)
00312 {
00313     if (opt == Qnil) {
00314         *option = COMPILE_OPTION_DEFAULT;
00315     }
00316     else if (opt == Qfalse) {
00317         *option = COMPILE_OPTION_FALSE;
00318     }
00319     else if (opt == Qtrue) {
00320         memset(option, 1, sizeof(rb_compile_option_t));
00321     }
00322     else if (CLASS_OF(opt) == rb_cHash) {
00323         *option = COMPILE_OPTION_DEFAULT;
00324 
00325 #define SET_COMPILE_OPTION(o, h, mem) \
00326   { VALUE flag = rb_hash_aref(h, ID2SYM(rb_intern(#mem))); \
00327       if (flag == Qtrue)  { o->mem = 1; } \
00328       else if (flag == Qfalse)  { o->mem = 0; } \
00329   }
00330 #define SET_COMPILE_OPTION_NUM(o, h, mem) \
00331   { VALUE num = rb_hash_aref(opt, ID2SYM(rb_intern(#mem))); \
00332       if (!NIL_P(num)) o->mem = NUM2INT(num); \
00333   }
00334         SET_COMPILE_OPTION(option, opt, inline_const_cache);
00335         SET_COMPILE_OPTION(option, opt, peephole_optimization);
00336         SET_COMPILE_OPTION(option, opt, tailcall_optimization);
00337         SET_COMPILE_OPTION(option, opt, specialized_instruction);
00338         SET_COMPILE_OPTION(option, opt, operands_unification);
00339         SET_COMPILE_OPTION(option, opt, instructions_unification);
00340         SET_COMPILE_OPTION(option, opt, stack_caching);
00341         SET_COMPILE_OPTION(option, opt, trace_instruction);
00342         SET_COMPILE_OPTION_NUM(option, opt, debug_level);
00343 #undef SET_COMPILE_OPTION
00344 #undef SET_COMPILE_OPTION_NUM
00345     }
00346     else {
00347         rb_raise(rb_eTypeError, "Compile option must be Hash/true/false/nil");
00348     }
00349 }
00350 
00351 static VALUE
00352 make_compile_option_value(rb_compile_option_t *option)
00353 {
00354     VALUE opt = rb_hash_new();
00355 #define SET_COMPILE_OPTION(o, h, mem) \
00356   rb_hash_aset(h, ID2SYM(rb_intern(#mem)), o->mem ? Qtrue : Qfalse)
00357 #define SET_COMPILE_OPTION_NUM(o, h, mem) \
00358   rb_hash_aset(h, ID2SYM(rb_intern(#mem)), INT2NUM(o->mem))
00359     {
00360         SET_COMPILE_OPTION(option, opt, inline_const_cache);
00361         SET_COMPILE_OPTION(option, opt, peephole_optimization);
00362         SET_COMPILE_OPTION(option, opt, tailcall_optimization);
00363         SET_COMPILE_OPTION(option, opt, specialized_instruction);
00364         SET_COMPILE_OPTION(option, opt, operands_unification);
00365         SET_COMPILE_OPTION(option, opt, instructions_unification);
00366         SET_COMPILE_OPTION(option, opt, stack_caching);
00367         SET_COMPILE_OPTION_NUM(option, opt, debug_level);
00368     }
00369 #undef SET_COMPILE_OPTION
00370 #undef SET_COMPILE_OPTION_NUM
00371     return opt;
00372 }
00373 
00374 VALUE
00375 rb_iseq_new(NODE *node, VALUE name, VALUE filename, VALUE filepath,
00376               VALUE parent, VALUE type)
00377 {
00378     return rb_iseq_new_with_opt(node, name, filename, filepath, INT2FIX(0), parent, type,
00379                                 &COMPILE_OPTION_DEFAULT);
00380 }
00381 
00382 VALUE
00383 rb_iseq_new_top(NODE *node, VALUE name, VALUE filename, VALUE filepath, VALUE parent)
00384 {
00385     return rb_iseq_new_with_opt(node, name, filename, filepath, INT2FIX(0), parent, ISEQ_TYPE_TOP,
00386                                 &COMPILE_OPTION_DEFAULT);
00387 }
00388 
00389 VALUE
00390 rb_iseq_new_main(NODE *node, VALUE filename, VALUE filepath)
00391 {
00392     rb_thread_t *th = GET_THREAD();
00393     VALUE parent = th->base_block->iseq->self;
00394     return rb_iseq_new_with_opt(node, rb_str_new2("<main>"), filename, filepath, INT2FIX(0),
00395                                 parent, ISEQ_TYPE_MAIN, &COMPILE_OPTION_DEFAULT);
00396 }
00397 
00398 static VALUE
00399 rb_iseq_new_with_bopt_and_opt(NODE *node, VALUE name, VALUE filename, VALUE filepath, VALUE line_no,
00400                                 VALUE parent, VALUE type, VALUE bopt,
00401                                 const rb_compile_option_t *option)
00402 {
00403     rb_iseq_t *iseq;
00404     VALUE self = iseq_alloc(rb_cISeq);
00405 
00406     GetISeqPtr(self, iseq);
00407     iseq->self = self;
00408 
00409     prepare_iseq_build(iseq, name, filename, filepath, line_no, parent, type, bopt, option);
00410     rb_iseq_compile_node(self, node);
00411     cleanup_iseq_build(iseq);
00412     return self;
00413 }
00414 
00415 VALUE
00416 rb_iseq_new_with_opt(NODE *node, VALUE name, VALUE filename, VALUE filepath, VALUE line_no,
00417                      VALUE parent, VALUE type,
00418                      const rb_compile_option_t *option)
00419 {
00420     /* TODO: argument check */
00421     return rb_iseq_new_with_bopt_and_opt(node, name, filename, filepath, line_no, parent, type,
00422                                            Qfalse, option);
00423 }
00424 
00425 VALUE
00426 rb_iseq_new_with_bopt(NODE *node, VALUE name, VALUE filename, VALUE filepath, VALUE line_no,
00427                        VALUE parent, VALUE type, VALUE bopt)
00428 {
00429     /* TODO: argument check */
00430     return rb_iseq_new_with_bopt_and_opt(node, name, filename, filepath, line_no, parent, type,
00431                                            bopt, &COMPILE_OPTION_DEFAULT);
00432 }
00433 
00434 #define CHECK_ARRAY(v)   rb_convert_type(v, T_ARRAY, "Array", "to_ary")
00435 #define CHECK_STRING(v)  rb_convert_type(v, T_STRING, "String", "to_str")
00436 #define CHECK_SYMBOL(v)  rb_convert_type(v, T_SYMBOL, "Symbol", "to_sym")
00437 static inline VALUE CHECK_INTEGER(VALUE v) {NUM2LONG(v); return v;}
00438 static VALUE
00439 iseq_load(VALUE self, VALUE data, VALUE parent, VALUE opt)
00440 {
00441     VALUE iseqval = iseq_alloc(self);
00442 
00443     VALUE magic, version1, version2, format_type, misc;
00444     VALUE name, filename, filepath, line_no;
00445     VALUE type, body, locals, args, exception;
00446 
00447     VALUE iseq_type;
00448     struct st_table *type_map = 0;
00449     rb_iseq_t *iseq;
00450     rb_compile_option_t option;
00451     int i = 0;
00452 
00453     /* [magic, major_version, minor_version, format_type, misc,
00454      *  name, filename, line_no,
00455      *  type, locals, args, exception_table, body]
00456      */
00457 
00458     data        = CHECK_ARRAY(data);
00459 
00460     magic       = CHECK_STRING(rb_ary_entry(data, i++));
00461     version1    = CHECK_INTEGER(rb_ary_entry(data, i++));
00462     version2    = CHECK_INTEGER(rb_ary_entry(data, i++));
00463     format_type = CHECK_INTEGER(rb_ary_entry(data, i++));
00464     misc        = rb_ary_entry(data, i++); /* TODO */
00465 
00466     name        = CHECK_STRING(rb_ary_entry(data, i++));
00467     filename    = CHECK_STRING(rb_ary_entry(data, i++));
00468     filepath    = rb_ary_entry(data, i++);
00469     filepath    = NIL_P(filepath) ? Qnil : CHECK_STRING(filepath);
00470     line_no     = CHECK_INTEGER(rb_ary_entry(data, i++));
00471 
00472     type        = CHECK_SYMBOL(rb_ary_entry(data, i++));
00473     locals      = CHECK_ARRAY(rb_ary_entry(data, i++));
00474 
00475     args        = rb_ary_entry(data, i++);
00476     if (FIXNUM_P(args) || (args = CHECK_ARRAY(args))) {
00477         /* */
00478     }
00479 
00480     exception   = CHECK_ARRAY(rb_ary_entry(data, i++));
00481     body        = CHECK_ARRAY(rb_ary_entry(data, i++));
00482 
00483     GetISeqPtr(iseqval, iseq);
00484     iseq->self = iseqval;
00485 
00486     if (type_map == 0) {
00487         type_map = st_init_numtable();
00488         st_insert(type_map, ID2SYM(rb_intern("top")), ISEQ_TYPE_TOP);
00489         st_insert(type_map, ID2SYM(rb_intern("method")), ISEQ_TYPE_METHOD);
00490         st_insert(type_map, ID2SYM(rb_intern("block")), ISEQ_TYPE_BLOCK);
00491         st_insert(type_map, ID2SYM(rb_intern("class")), ISEQ_TYPE_CLASS);
00492         st_insert(type_map, ID2SYM(rb_intern("rescue")), ISEQ_TYPE_RESCUE);
00493         st_insert(type_map, ID2SYM(rb_intern("ensure")), ISEQ_TYPE_ENSURE);
00494         st_insert(type_map, ID2SYM(rb_intern("eval")), ISEQ_TYPE_EVAL);
00495         st_insert(type_map, ID2SYM(rb_intern("main")), ISEQ_TYPE_MAIN);
00496         st_insert(type_map, ID2SYM(rb_intern("defined_guard")), ISEQ_TYPE_DEFINED_GUARD);
00497     }
00498 
00499     if (st_lookup(type_map, type, &iseq_type) == 0) {
00500         const char *typename = rb_id2name(type);
00501         if (typename)
00502             rb_raise(rb_eTypeError, "unsupport type: :%s", typename);
00503         else
00504             rb_raise(rb_eTypeError, "unsupport type: %p", (void *)type);
00505     }
00506 
00507     if (parent == Qnil) {
00508         parent = 0;
00509     }
00510 
00511     make_compile_option(&option, opt);
00512     prepare_iseq_build(iseq, name, filename, filepath, line_no,
00513                        parent, iseq_type, 0, &option);
00514 
00515     rb_iseq_build_from_ary(iseq, locals, args, exception, body);
00516 
00517     cleanup_iseq_build(iseq);
00518     return iseqval;
00519 }
00520 
00521 static VALUE
00522 iseq_s_load(int argc, VALUE *argv, VALUE self)
00523 {
00524     VALUE data, opt=Qnil;
00525     rb_scan_args(argc, argv, "11", &data, &opt);
00526 
00527     return iseq_load(self, data, 0, opt);
00528 }
00529 
00530 VALUE
00531 rb_iseq_load(VALUE data, VALUE parent, VALUE opt)
00532 {
00533     return iseq_load(rb_cISeq, data, parent, opt);
00534 }
00535 
00536 static NODE *
00537 parse_string(VALUE str, const char *file, int line)
00538 {
00539     VALUE parser = rb_parser_new();
00540     NODE *node = rb_parser_compile_string(parser, file, str, line);
00541 
00542     if (!node) {
00543         rb_exc_raise(GET_THREAD()->errinfo);    /* TODO: check err */
00544     }
00545     return node;
00546 }
00547 
00548 VALUE
00549 rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE filepath, VALUE line, VALUE opt)
00550 {
00551     rb_compile_option_t option;
00552     const char *fn = StringValueCStr(file);
00553     int ln = NUM2INT(line);
00554     NODE *node = parse_string(StringValue(src), fn, ln);
00555     rb_thread_t *th = GET_THREAD();
00556     make_compile_option(&option, opt);
00557 
00558     if (th->base_block && th->base_block->iseq) {
00559         return rb_iseq_new_with_opt(node, th->base_block->iseq->name,
00560                                     file, filepath, line, th->base_block->iseq->self,
00561                                     ISEQ_TYPE_EVAL, &option);
00562     }
00563     else {
00564         return rb_iseq_new_with_opt(node, rb_str_new2("<compiled>"), file, filepath, line, Qfalse,
00565                                     ISEQ_TYPE_TOP, &option);
00566     }
00567 }
00568 
00569 VALUE
00570 rb_iseq_compile(VALUE src, VALUE file, VALUE line)
00571 {
00572     return rb_iseq_compile_with_option(src, file, Qnil, line, Qnil);
00573 }
00574 
00575 static VALUE
00576 iseq_s_compile(int argc, VALUE *argv, VALUE self)
00577 {
00578     VALUE src, file = Qnil, path = Qnil, line = INT2FIX(1), opt = Qnil;
00579 
00580     rb_secure(1);
00581 
00582     rb_scan_args(argc, argv, "14", &src, &file, &path, &line, &opt);
00583     if (NIL_P(file)) file = rb_str_new2("<compiled>");
00584     if (NIL_P(line)) line = INT2FIX(1);
00585 
00586     return rb_iseq_compile_with_option(src, file, path, line, opt);
00587 }
00588 
00589 static VALUE
00590 iseq_s_compile_file(int argc, VALUE *argv, VALUE self)
00591 {
00592     VALUE file, line = INT2FIX(1), opt = Qnil;
00593     VALUE parser;
00594     VALUE f;
00595     NODE *node;
00596     const char *fname;
00597     rb_compile_option_t option;
00598 
00599     rb_secure(1);
00600     rb_scan_args(argc, argv, "11", &file, &opt);
00601     FilePathValue(file);
00602     fname = StringValueCStr(file);
00603 
00604     f = rb_file_open_str(file, "r");
00605 
00606     parser = rb_parser_new();
00607     node = rb_parser_compile_file(parser, fname, f, NUM2INT(line));
00608     make_compile_option(&option, opt);
00609     return rb_iseq_new_with_opt(node, rb_str_new2("<main>"), file, file, line, Qfalse,
00610                                 ISEQ_TYPE_TOP, &option);
00611 }
00612 
00613 static VALUE
00614 iseq_s_compile_option_set(VALUE self, VALUE opt)
00615 {
00616     rb_compile_option_t option;
00617     rb_secure(1);
00618     make_compile_option(&option, opt);
00619     COMPILE_OPTION_DEFAULT = option;
00620     return opt;
00621 }
00622 
00623 static VALUE
00624 iseq_s_compile_option_get(VALUE self)
00625 {
00626     return make_compile_option_value(&COMPILE_OPTION_DEFAULT);
00627 }
00628 
00629 static rb_iseq_t *
00630 iseq_check(VALUE val)
00631 {
00632     rb_iseq_t *iseq;
00633     GetISeqPtr(val, iseq);
00634     if (!iseq->name) {
00635         rb_raise(rb_eTypeError, "uninitialized InstructionSequence");
00636     }
00637     return iseq;
00638 }
00639 
00640 static VALUE
00641 iseq_eval(VALUE self)
00642 {
00643     rb_secure(1);
00644     return rb_iseq_eval(self);
00645 }
00646 
00647 static VALUE
00648 iseq_inspect(VALUE self)
00649 {
00650     rb_iseq_t *iseq;
00651     GetISeqPtr(self, iseq);
00652     if (!iseq->name) {
00653         return rb_sprintf("#<%s: uninitialized>", rb_obj_classname(self));
00654     }
00655 
00656     return rb_sprintf("<%s:%s@%s>",
00657                       rb_obj_classname(self),
00658                       RSTRING_PTR(iseq->name), RSTRING_PTR(iseq->filename));
00659 }
00660 
00661 static
00662 VALUE iseq_data_to_ary(rb_iseq_t *iseq);
00663 
00664 static VALUE
00665 iseq_to_a(VALUE self)
00666 {
00667     rb_iseq_t *iseq = iseq_check(self);
00668     rb_secure(1);
00669     return iseq_data_to_ary(iseq);
00670 }
00671 
00672 int
00673 rb_iseq_first_lineno(rb_iseq_t *iseq)
00674 {
00675     return FIX2INT(iseq->line_no);
00676 }
00677 
00678 /* TODO: search algorithm is brute force.
00679          this should be binary search or so. */
00680 
00681 static struct iseq_insn_info_entry *
00682 get_insn_info(const rb_iseq_t *iseq, const unsigned long pos)
00683 {
00684     unsigned long i, size = iseq->insn_info_size;
00685     struct iseq_insn_info_entry *table = iseq->insn_info_table;
00686 
00687     for (i = 0; i < size; i++) {
00688         if (table[i].position == pos) {
00689             return &table[i];
00690         }
00691     }
00692 
00693     return 0;
00694 }
00695 
00696 static unsigned short
00697 find_line_no(rb_iseq_t *iseq, unsigned long pos)
00698 {
00699     struct iseq_insn_info_entry *entry = get_insn_info(iseq, pos);
00700     if (entry) {
00701         return entry->line_no;
00702     }
00703     else {
00704         return 0;
00705     }
00706 }
00707 
00708 static unsigned short
00709 find_prev_line_no(rb_iseq_t *iseqdat, unsigned long pos)
00710 {
00711     unsigned long i, size = iseqdat->insn_info_size;
00712     struct iseq_insn_info_entry *iiary = iseqdat->insn_info_table;
00713 
00714     for (i = 0; i < size; i++) {
00715         if (iiary[i].position == pos) {
00716             if (i > 0) {
00717                 return iiary[i - 1].line_no;
00718             }
00719             else {
00720                 return 0;
00721             }
00722         }
00723     }
00724 
00725     return 0;
00726 }
00727 
00728 static VALUE
00729 insn_operand_intern(rb_iseq_t *iseq,
00730                     VALUE insn, int op_no, VALUE op,
00731                     int len, size_t pos, VALUE *pnop, VALUE child)
00732 {
00733     const char *types = insn_op_types(insn);
00734     char type = types[op_no];
00735     VALUE ret;
00736 
00737     switch (type) {
00738       case TS_OFFSET:           /* LONG */
00739         ret = rb_sprintf("%ld", pos + len + op);
00740         break;
00741 
00742       case TS_NUM:              /* ULONG */
00743         ret = rb_sprintf("%lu", op);
00744         break;
00745 
00746       case TS_LINDEX:
00747         {
00748             rb_iseq_t *ip = iseq->local_iseq;
00749             int lidx = ip->local_size - (int)op;
00750             const char *name = rb_id2name(ip->local_table[lidx]);
00751 
00752             if (name) {
00753                 ret = rb_str_new2(name);
00754             }
00755             else {
00756                 ret = rb_str_new2("*");
00757             }
00758             break;
00759         }
00760       case TS_DINDEX:{
00761         if (insn == BIN(getdynamic) || insn == BIN(setdynamic)) {
00762             rb_iseq_t *ip = iseq;
00763             VALUE level = *pnop, i;
00764             const char *name;
00765             for (i = 0; i < level; i++) {
00766                 ip = ip->parent_iseq;
00767             }
00768             name = rb_id2name(ip->local_table[ip->local_size - op]);
00769 
00770             if (!name) {
00771                 name = "*";
00772             }
00773             ret = rb_str_new2(name);
00774         }
00775         else {
00776             ret = rb_inspect(INT2FIX(op));
00777         }
00778         break;
00779       }
00780       case TS_ID:               /* ID (symbol) */
00781         op = ID2SYM(op);
00782 
00783       case TS_VALUE:            /* VALUE */
00784         op = obj_resurrect(op);
00785         ret = rb_inspect(op);
00786         if (CLASS_OF(op) == rb_cISeq) {
00787             rb_ary_push(child, op);
00788         }
00789         break;
00790 
00791       case TS_ISEQ:             /* iseq */
00792         {
00793             rb_iseq_t *iseq = (rb_iseq_t *)op;
00794             if (iseq) {
00795                 ret = iseq->name;
00796                 if (child) {
00797                     rb_ary_push(child, iseq->self);
00798                 }
00799             }
00800             else {
00801                 ret = rb_str_new2("nil");
00802             }
00803             break;
00804         }
00805       case TS_GENTRY:
00806         {
00807             struct rb_global_entry *entry = (struct rb_global_entry *)op;
00808             ret = rb_str_dup(rb_id2str(entry->id));
00809         }
00810         break;
00811 
00812       case TS_IC:
00813         ret = rb_sprintf("<ic:%"PRIdPTRDIFF">", (struct iseq_inline_cache_entry *)op - iseq->ic_entries);
00814         break;
00815 
00816       case TS_CDHASH:
00817         ret = rb_str_new2("<cdhash>");
00818         break;
00819 
00820       case TS_FUNCPTR:
00821         ret = rb_str_new2("<funcptr>");
00822         break;
00823 
00824       default:
00825         rb_bug("rb_iseq_disasm: unknown operand type: %c", type);
00826     }
00827     return ret;
00828 }
00829 
00834 int
00835 rb_iseq_disasm_insn(VALUE ret, VALUE *iseq, size_t pos,
00836                     rb_iseq_t *iseqdat, VALUE child)
00837 {
00838     VALUE insn = iseq[pos];
00839     int len = insn_len(insn);
00840     int j;
00841     const char *types = insn_op_types(insn);
00842     VALUE str = rb_str_new(0, 0);
00843     const char *insn_name_buff;
00844 
00845     insn_name_buff = insn_name(insn);
00846     if (1) {
00847         rb_str_catf(str, "%04"PRIdSIZE" %-16s ", pos, insn_name_buff);
00848     }
00849     else {
00850         rb_str_catf(str, "%04"PRIdSIZE" %-16.*s ", pos,
00851                     (int)strcspn(insn_name_buff, "_"), insn_name_buff);
00852     }
00853 
00854     for (j = 0; types[j]; j++) {
00855         const char *types = insn_op_types(insn);
00856         VALUE opstr = insn_operand_intern(iseqdat, insn, j, iseq[pos + j + 1],
00857                                           len, pos, &iseq[pos + j + 2],
00858                                           child);
00859         rb_str_concat(str, opstr);
00860 
00861         if (types[j + 1]) {
00862             rb_str_cat2(str, ", ");
00863         }
00864     }
00865 
00866     if (1) {
00867         int line_no = find_line_no(iseqdat, pos);
00868         int prev = find_prev_line_no(iseqdat, pos);
00869         if (line_no && line_no != prev) {
00870             long slen = RSTRING_LEN(str);
00871             slen = (slen > 70) ? 0 : (70 - slen);
00872             str = rb_str_catf(str, "%*s(%4d)", (int)slen, "", line_no);
00873         }
00874     }
00875     else {
00876         /* for debug */
00877         struct iseq_insn_info_entry *entry = get_insn_info(iseqdat, pos);
00878         long slen = RSTRING_LEN(str);
00879         slen = (slen > 60) ? 0 : (60 - slen);
00880         str = rb_str_catf(str, "%*s(line: %d, sp: %d)",
00881                           (int)slen, "", entry->line_no, entry->sp);
00882     }
00883 
00884     if (ret) {
00885         rb_str_cat2(str, "\n");
00886         rb_str_concat(ret, str);
00887     }
00888     else {
00889         printf("%s\n", RSTRING_PTR(str));
00890     }
00891     return len;
00892 }
00893 
00894 static const char *
00895 catch_type(int type)
00896 {
00897     switch (type) {
00898       case CATCH_TYPE_RESCUE:
00899         return "rescue";
00900       case CATCH_TYPE_ENSURE:
00901         return "ensure";
00902       case CATCH_TYPE_RETRY:
00903         return "retry";
00904       case CATCH_TYPE_BREAK:
00905         return "break";
00906       case CATCH_TYPE_REDO:
00907         return "redo";
00908       case CATCH_TYPE_NEXT:
00909         return "next";
00910       default:
00911         rb_bug("unknown catch type (%d)", type);
00912         return 0;
00913     }
00914 }
00915 
00916 VALUE
00917 rb_iseq_disasm(VALUE self)
00918 {
00919     rb_iseq_t *iseqdat = iseq_check(self);
00920     VALUE *iseq;
00921     VALUE str = rb_str_new(0, 0);
00922     VALUE child = rb_ary_new();
00923     unsigned long size;
00924     int i;
00925     long l;
00926     ID *tbl;
00927     size_t n;
00928     enum {header_minlen = 72};
00929 
00930     rb_secure(1);
00931 
00932     iseq = iseqdat->iseq;
00933     size = iseqdat->iseq_size;
00934 
00935     rb_str_cat2(str, "== disasm: ");
00936 
00937     rb_str_concat(str, iseq_inspect(iseqdat->self));
00938     if ((l = RSTRING_LEN(str)) < header_minlen) {
00939         rb_str_resize(str, header_minlen);
00940         memset(RSTRING_PTR(str) + l, '=', header_minlen - l);
00941     }
00942     rb_str_cat2(str, "\n");
00943 
00944     /* show catch table information */
00945     if (iseqdat->catch_table_size != 0) {
00946         rb_str_cat2(str, "== catch table\n");
00947     }
00948     for (i = 0; i < iseqdat->catch_table_size; i++) {
00949         struct iseq_catch_table_entry *entry = &iseqdat->catch_table[i];
00950         rb_str_catf(str,
00951                     "| catch type: %-6s st: %04d ed: %04d sp: %04d cont: %04d\n",
00952                     catch_type((int)entry->type), (int)entry->start,
00953                     (int)entry->end, (int)entry->sp, (int)entry->cont);
00954         if (entry->iseq) {
00955             rb_str_concat(str, rb_iseq_disasm(entry->iseq));
00956         }
00957     }
00958     if (iseqdat->catch_table_size != 0) {
00959         rb_str_cat2(str, "|-------------------------------------"
00960                     "-----------------------------------\n");
00961     }
00962 
00963     /* show local table information */
00964     tbl = iseqdat->local_table;
00965 
00966     if (tbl) {
00967         rb_str_catf(str,
00968                     "local table (size: %d, argc: %d "
00969                     "[opts: %d, rest: %d, post: %d, block: %d] s%d)\n",
00970                     iseqdat->local_size, iseqdat->argc,
00971                     iseqdat->arg_opts, iseqdat->arg_rest,
00972                     iseqdat->arg_post_len, iseqdat->arg_block,
00973                     iseqdat->arg_simple);
00974 
00975         for (i = 0; i < iseqdat->local_table_size; i++) {
00976             const char *name = rb_id2name(tbl[i]);
00977             char info[0x100];
00978             char argi[0x100] = "";
00979             char opti[0x100] = "";
00980 
00981             if (iseqdat->arg_opts) {
00982                 int argc = iseqdat->argc;
00983                 int opts = iseqdat->arg_opts;
00984                 if (i >= argc && i < argc + opts - 1) {
00985                     snprintf(opti, sizeof(opti), "Opt=%ld",
00986                              iseqdat->arg_opt_table[i - argc]);
00987                 }
00988             }
00989 
00990             snprintf(argi, sizeof(argi), "%s%s%s%s%s",  /* arg, opts, rest, post  block */
00991                      iseqdat->argc > i ? "Arg" : "",
00992                      opti,
00993                      iseqdat->arg_rest == i ? "Rest" : "",
00994                      (iseqdat->arg_post_start <= i &&
00995                       i < iseqdat->arg_post_start + iseqdat->arg_post_len) ? "Post" : "",
00996                      iseqdat->arg_block == i ? "Block" : "");
00997 
00998             snprintf(info, sizeof(info), "%s%s%s%s", name ? name : "?",
00999                      *argi ? "<" : "", argi, *argi ? ">" : "");
01000 
01001             rb_str_catf(str, "[%2d] %-11s", iseqdat->local_size - i, info);
01002         }
01003         rb_str_cat2(str, "\n");
01004     }
01005 
01006     /* show each line */
01007     for (n = 0; n < size;) {
01008         n += rb_iseq_disasm_insn(str, iseq, n, iseqdat, child);
01009     }
01010 
01011     for (i = 0; i < RARRAY_LEN(child); i++) {
01012         VALUE isv = rb_ary_entry(child, i);
01013         rb_str_concat(str, rb_iseq_disasm(isv));
01014     }
01015 
01016     return str;
01017 }
01018 
01019 static VALUE
01020 iseq_s_disasm(VALUE klass, VALUE body)
01021 {
01022     VALUE ret = Qnil;
01023     rb_iseq_t *iseq;
01024     extern rb_iseq_t *rb_method_get_iseq(VALUE body);
01025 
01026     rb_secure(1);
01027 
01028     if (rb_obj_is_proc(body)) {
01029         rb_proc_t *proc;
01030         VALUE iseqval;
01031         GetProcPtr(body, proc);
01032         iseqval = proc->block.iseq->self;
01033         if (RUBY_VM_NORMAL_ISEQ_P(iseqval)) {
01034             ret = rb_iseq_disasm(iseqval);
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         VALUE label;
01305 
01306         if (st_lookup(labels_table, pos, &label)) {
01307             rb_ary_push(body, 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_LEN(ary);
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(1)); /* major */
01332     rb_ary_push(val, INT2FIX(2)); /* 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 ::VM::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     /* disable this feature because there is no verifier. */
01509     /* rb_define_singleton_method(rb_cISeq, "load", iseq_s_load, -1); */
01510     (void)iseq_s_load;
01511 
01512     rb_define_singleton_method(rb_cISeq, "compile", iseq_s_compile, -1);
01513     rb_define_singleton_method(rb_cISeq, "new", iseq_s_compile, -1);
01514     rb_define_singleton_method(rb_cISeq, "compile_file", iseq_s_compile_file, -1);
01515     rb_define_singleton_method(rb_cISeq, "compile_option", iseq_s_compile_option_get, 0);
01516     rb_define_singleton_method(rb_cISeq, "compile_option=", iseq_s_compile_option_set, 1);
01517     rb_define_singleton_method(rb_cISeq, "disasm", iseq_s_disasm, 1);
01518     rb_define_singleton_method(rb_cISeq, "disassemble", iseq_s_disasm, 1);
01519 }
01520 
01521 

Generated on Wed Aug 10 09:17:08 2011 for Ruby by  doxygen 1.4.7