Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# 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