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