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