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