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