Ruby 1.9.3p327(2012-11-10revision37606)
|
00001 /********************************************************************** 00002 00003 iseq.c - 00004 00005 $Author: naruse $ 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 #include "internal.h" 00014 00015 /* #define RUBY_MARK_FREE_DEBUG 1 */ 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 /* It's possible that strings are freed */ 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 /* set class nest stack */ 00184 if (type == ISEQ_TYPE_TOP) { 00185 /* toplevel is private */ 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); /* place holder */ 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; /* TODO: really enough? */ 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 * iseq->special_block_builder = GC_GUARDED_PTR_REF(block_opt); 00246 * iseq->cached_special_block_builder = 0; 00247 * iseq->cached_special_block = 0; 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, /* int inline_const_cache; */ 00301 OPT_PEEPHOLE_OPTIMIZATION, /* int peephole_optimization; */ 00302 OPT_TAILCALL_OPTIMIZATION, /* int tailcall_optimization */ 00303 OPT_SPECIALISED_INSTRUCTION, /* int specialized_instruction; */ 00304 OPT_OPERANDS_UNIFICATION, /* int operands_unification; */ 00305 OPT_INSTRUCTIONS_UNIFICATION, /* int instructions_unification; */ 00306 OPT_STACK_CACHING, /* int stack_caching; */ 00307 OPT_TRACE_INSTRUCTION, /* int 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 /* TODO: argument check */ 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 /* TODO: argument check */ 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 /* [magic, major_version, minor_version, format_type, misc, 00455 * name, filename, line_no, 00456 * type, locals, args, exception_table, body] 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++); /* TODO */ 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); /* TODO: check err */ 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 /* TODO: search algorithm is brute force. 00681 this should be binary search or so. */ 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: /* LONG */ 00741 ret = rb_sprintf("%"PRIdVALUE, (VALUE)(pos + len + op)); 00742 break; 00743 00744 case TS_NUM: /* ULONG */ 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: /* ID (symbol) */ 00783 op = ID2SYM(op); 00784 00785 case TS_VALUE: /* 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: /* 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 /* for debug */ 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 /* show catch table information */ 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 /* show local table information */ 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", /* arg, opts, rest, post block */ 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 /* show each line */ 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; /* 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 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); /* reject too huge data */ 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(ISEQ_MAJOR_VERSION)); /* major */ 01332 rb_ary_push(val, INT2FIX(ISEQ_MINOR_VERSION)); /* 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 ::RubyVM::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 #if 0 /* TBD */ 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 /* disable this feature because there is no verifier. */ 01514 /* rb_define_singleton_method(rb_cISeq, "load", iseq_s_load, -1); */ 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