00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "ruby/ruby.h"
00013
00014
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
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
00178 if (type == ISEQ_TYPE_TOP) {
00179
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);
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
00245
00246
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,
00300 OPT_PEEPHOLE_OPTIMIZATION,
00301 OPT_TAILCALL_OPTIMIZATION,
00302 OPT_SPECIALISED_INSTRUCTION,
00303 OPT_OPERANDS_UNIFICATION,
00304 OPT_INSTRUCTIONS_UNIFICATION,
00305 OPT_STACK_CACHING,
00306 OPT_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
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
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
00454
00455
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++);
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);
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
00679
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:
00739 ret = rb_sprintf("%ld", pos + len + op);
00740 break;
00741
00742 case TS_NUM:
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:
00781 op = ID2SYM(op);
00782
00783 case TS_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:
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
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
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
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",
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
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;
01107 VALUE locals = rb_ary_new();
01108 VALUE args = rb_ary_new();
01109 VALUE body = rb_ary_new();
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
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
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
01169 {
01170
01171
01172
01173
01174
01175
01176
01177
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
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
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
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
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
01327
01328
01329
01330 rb_ary_push(val, rb_str_new2("YARVInstructionSequence/SimpleDataFormat"));
01331 rb_ary_push(val, INT2FIX(1));
01332 rb_ary_push(val, INT2FIX(2));
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
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
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
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
01509
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