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