00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "ruby/ruby.h"
00013 #include "internal.h"
00014
00015
00016 #include "gc.h"
00017 #include "vm_core.h"
00018 #include "iseq.h"
00019
00020 #include "insns.inc"
00021 #include "insns_info.inc"
00022
00023 #define ISEQ_MAJOR_VERSION 1
00024 #define ISEQ_MINOR_VERSION 2
00025
00026 VALUE rb_cISeq;
00027
00028 #define hidden_obj_p(obj) (!SPECIAL_CONST_P(obj) && !RBASIC(obj)->klass)
00029
00030 static inline VALUE
00031 obj_resurrect(VALUE obj)
00032 {
00033 if (hidden_obj_p(obj)) {
00034 switch (BUILTIN_TYPE(obj)) {
00035 case T_STRING:
00036 obj = rb_str_resurrect(obj);
00037 break;
00038 case T_ARRAY:
00039 obj = rb_ary_resurrect(obj);
00040 break;
00041 }
00042 }
00043 return obj;
00044 }
00045
00046 static void
00047 compile_data_free(struct iseq_compile_data *compile_data)
00048 {
00049 if (compile_data) {
00050 struct iseq_compile_data_storage *cur, *next;
00051 cur = compile_data->storage_head;
00052 while (cur) {
00053 next = cur->next;
00054 ruby_xfree(cur);
00055 cur = next;
00056 }
00057 ruby_xfree(compile_data);
00058 }
00059 }
00060
00061 static void
00062 iseq_free(void *ptr)
00063 {
00064 rb_iseq_t *iseq;
00065 RUBY_FREE_ENTER("iseq");
00066
00067 if (ptr) {
00068 iseq = ptr;
00069 if (!iseq->orig) {
00070
00071 if (0) {
00072 RUBY_GC_INFO("%s @ %s\n", RSTRING_PTR(iseq->name),
00073 RSTRING_PTR(iseq->filename));
00074 }
00075
00076 if (iseq->iseq != iseq->iseq_encoded) {
00077 RUBY_FREE_UNLESS_NULL(iseq->iseq_encoded);
00078 }
00079
00080 RUBY_FREE_UNLESS_NULL(iseq->iseq);
00081 RUBY_FREE_UNLESS_NULL(iseq->insn_info_table);
00082 RUBY_FREE_UNLESS_NULL(iseq->local_table);
00083 RUBY_FREE_UNLESS_NULL(iseq->ic_entries);
00084 RUBY_FREE_UNLESS_NULL(iseq->catch_table);
00085 RUBY_FREE_UNLESS_NULL(iseq->arg_opt_table);
00086 compile_data_free(iseq->compile_data);
00087 }
00088 ruby_xfree(ptr);
00089 }
00090 RUBY_FREE_LEAVE("iseq");
00091 }
00092
00093 static void
00094 iseq_mark(void *ptr)
00095 {
00096 RUBY_MARK_ENTER("iseq");
00097
00098 if (ptr) {
00099 rb_iseq_t *iseq = ptr;
00100
00101 RUBY_GC_INFO("%s @ %s\n", RSTRING_PTR(iseq->name), RSTRING_PTR(iseq->filename));
00102 RUBY_MARK_UNLESS_NULL(iseq->mark_ary);
00103 RUBY_MARK_UNLESS_NULL(iseq->name);
00104 RUBY_MARK_UNLESS_NULL(iseq->filename);
00105 RUBY_MARK_UNLESS_NULL(iseq->filepath);
00106 RUBY_MARK_UNLESS_NULL((VALUE)iseq->cref_stack);
00107 RUBY_MARK_UNLESS_NULL(iseq->klass);
00108 RUBY_MARK_UNLESS_NULL(iseq->coverage);
00109 #if 0
00110 RUBY_MARK_UNLESS_NULL((VALUE)iseq->node);
00111 RUBY_MARK_UNLESS_NULL(iseq->cached_special_block);
00112 #endif
00113 RUBY_MARK_UNLESS_NULL(iseq->orig);
00114
00115 if (iseq->compile_data != 0) {
00116 struct iseq_compile_data *const compile_data = iseq->compile_data;
00117 RUBY_MARK_UNLESS_NULL(compile_data->mark_ary);
00118 RUBY_MARK_UNLESS_NULL(compile_data->err_info);
00119 RUBY_MARK_UNLESS_NULL(compile_data->catch_table_ary);
00120 }
00121 }
00122 RUBY_MARK_LEAVE("iseq");
00123 }
00124
00125 static size_t
00126 iseq_memsize(const void *ptr)
00127 {
00128 size_t size = sizeof(rb_iseq_t);
00129 const rb_iseq_t *iseq;
00130
00131 if (ptr) {
00132 iseq = ptr;
00133 if (!iseq->orig) {
00134 if (iseq->iseq != iseq->iseq_encoded) {
00135 size += iseq->iseq_size * sizeof(VALUE);
00136 }
00137
00138 size += iseq->iseq_size * sizeof(VALUE);
00139 size += iseq->insn_info_size * sizeof(struct iseq_insn_info_entry);
00140 size += iseq->local_table_size * sizeof(ID);
00141 size += iseq->catch_table_size * sizeof(struct iseq_catch_table_entry);
00142 size += iseq->arg_opts * sizeof(VALUE);
00143 size += iseq->ic_size * sizeof(struct iseq_inline_cache_entry);
00144
00145 if (iseq->compile_data) {
00146 struct iseq_compile_data_storage *cur;
00147
00148 cur = iseq->compile_data->storage_head;
00149 while (cur) {
00150 size += cur->size + sizeof(struct iseq_compile_data_storage);
00151 cur = cur->next;
00152 }
00153 size += sizeof(struct iseq_compile_data);
00154 }
00155 }
00156 }
00157
00158 return size;
00159 }
00160
00161 static const rb_data_type_t iseq_data_type = {
00162 "iseq",
00163 {
00164 iseq_mark,
00165 iseq_free,
00166 iseq_memsize,
00167 },
00168 };
00169
00170 static VALUE
00171 iseq_alloc(VALUE klass)
00172 {
00173 rb_iseq_t *iseq;
00174 return TypedData_Make_Struct(klass, rb_iseq_t, &iseq_data_type, iseq);
00175 }
00176
00177 static void
00178 set_relation(rb_iseq_t *iseq, const VALUE parent)
00179 {
00180 const VALUE type = iseq->type;
00181 rb_thread_t *th = GET_THREAD();
00182
00183
00184 if (type == ISEQ_TYPE_TOP) {
00185
00186 iseq->cref_stack = NEW_BLOCK(rb_cObject);
00187 iseq->cref_stack->nd_visi = NOEX_PRIVATE;
00188 if (th->top_wrapper) {
00189 NODE *cref = NEW_BLOCK(th->top_wrapper);
00190 cref->nd_visi = NOEX_PRIVATE;
00191 cref->nd_next = iseq->cref_stack;
00192 iseq->cref_stack = cref;
00193 }
00194 }
00195 else if (type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) {
00196 iseq->cref_stack = NEW_BLOCK(0);
00197 }
00198 else if (RTEST(parent)) {
00199 rb_iseq_t *piseq;
00200 GetISeqPtr(parent, piseq);
00201 iseq->cref_stack = piseq->cref_stack;
00202 }
00203
00204 if (type == ISEQ_TYPE_TOP ||
00205 type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) {
00206 iseq->local_iseq = iseq;
00207 }
00208 else if (RTEST(parent)) {
00209 rb_iseq_t *piseq;
00210 GetISeqPtr(parent, piseq);
00211 iseq->local_iseq = piseq->local_iseq;
00212 }
00213
00214 if (RTEST(parent)) {
00215 rb_iseq_t *piseq;
00216 GetISeqPtr(parent, piseq);
00217 iseq->parent_iseq = piseq;
00218 }
00219
00220 if (type == ISEQ_TYPE_MAIN) {
00221 iseq->local_iseq = iseq;
00222 }
00223 }
00224
00225 static VALUE
00226 prepare_iseq_build(rb_iseq_t *iseq,
00227 VALUE name, VALUE filename, VALUE filepath, VALUE line_no,
00228 VALUE parent, enum iseq_type type, VALUE block_opt,
00229 const rb_compile_option_t *option)
00230 {
00231 OBJ_FREEZE(name);
00232 OBJ_FREEZE(filename);
00233
00234 iseq->name = name;
00235 iseq->filename = filename;
00236 iseq->filepath = filepath;
00237 iseq->line_no = (unsigned short)line_no;
00238 iseq->defined_method_id = 0;
00239 iseq->mark_ary = rb_ary_tmp_new(3);
00240 OBJ_UNTRUST(iseq->mark_ary);
00241 RBASIC(iseq->mark_ary)->klass = 0;
00242
00243 iseq->type = type;
00244 iseq->arg_rest = -1;
00245 iseq->arg_block = -1;
00246 iseq->klass = 0;
00247
00248
00249
00250
00251
00252
00253
00254 iseq->compile_data = ALLOC(struct iseq_compile_data);
00255 MEMZERO(iseq->compile_data, struct iseq_compile_data, 1);
00256 iseq->compile_data->err_info = Qnil;
00257 iseq->compile_data->mark_ary = rb_ary_tmp_new(3);
00258
00259 iseq->compile_data->storage_head = iseq->compile_data->storage_current =
00260 (struct iseq_compile_data_storage *)
00261 ALLOC_N(char, INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE +
00262 sizeof(struct iseq_compile_data_storage));
00263
00264 iseq->compile_data->catch_table_ary = rb_ary_new();
00265 iseq->compile_data->storage_head->pos = 0;
00266 iseq->compile_data->storage_head->next = 0;
00267 iseq->compile_data->storage_head->size =
00268 INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE;
00269 iseq->compile_data->storage_head->buff =
00270 (char *)(&iseq->compile_data->storage_head->buff + 1);
00271 iseq->compile_data->option = option;
00272 iseq->compile_data->last_coverable_line = -1;
00273
00274 set_relation(iseq, parent);
00275
00276 iseq->coverage = Qfalse;
00277 if (!GET_THREAD()->parse_in_eval) {
00278 VALUE coverages = rb_get_coverages();
00279 if (RTEST(coverages)) {
00280 iseq->coverage = rb_hash_lookup(coverages, filename);
00281 if (NIL_P(iseq->coverage)) iseq->coverage = Qfalse;
00282 }
00283 }
00284
00285 return Qtrue;
00286 }
00287
00288 static VALUE
00289 cleanup_iseq_build(rb_iseq_t *iseq)
00290 {
00291 struct iseq_compile_data *data = iseq->compile_data;
00292 VALUE err = data->err_info;
00293 iseq->compile_data = 0;
00294 compile_data_free(data);
00295
00296 if (RTEST(err)) {
00297 rb_funcall2(err, rb_intern("set_backtrace"), 1, &iseq->filename);
00298 rb_exc_raise(err);
00299 }
00300 return Qtrue;
00301 }
00302
00303 static rb_compile_option_t COMPILE_OPTION_DEFAULT = {
00304 OPT_INLINE_CONST_CACHE,
00305 OPT_PEEPHOLE_OPTIMIZATION,
00306 OPT_TAILCALL_OPTIMIZATION,
00307 OPT_SPECIALISED_INSTRUCTION,
00308 OPT_OPERANDS_UNIFICATION,
00309 OPT_INSTRUCTIONS_UNIFICATION,
00310 OPT_STACK_CACHING,
00311 OPT_TRACE_INSTRUCTION,
00312 };
00313 static const rb_compile_option_t COMPILE_OPTION_FALSE = {0};
00314
00315 static void
00316 make_compile_option(rb_compile_option_t *option, VALUE opt)
00317 {
00318 if (opt == Qnil) {
00319 *option = COMPILE_OPTION_DEFAULT;
00320 }
00321 else if (opt == Qfalse) {
00322 *option = COMPILE_OPTION_FALSE;
00323 }
00324 else if (opt == Qtrue) {
00325 memset(option, 1, sizeof(rb_compile_option_t));
00326 }
00327 else if (CLASS_OF(opt) == rb_cHash) {
00328 *option = COMPILE_OPTION_DEFAULT;
00329
00330 #define SET_COMPILE_OPTION(o, h, mem) \
00331 { VALUE flag = rb_hash_aref((h), ID2SYM(rb_intern(#mem))); \
00332 if (flag == Qtrue) { (o)->mem = 1; } \
00333 else if (flag == Qfalse) { (o)->mem = 0; } \
00334 }
00335 #define SET_COMPILE_OPTION_NUM(o, h, mem) \
00336 { VALUE num = rb_hash_aref(opt, ID2SYM(rb_intern(#mem))); \
00337 if (!NIL_P(num)) (o)->mem = NUM2INT(num); \
00338 }
00339 SET_COMPILE_OPTION(option, opt, inline_const_cache);
00340 SET_COMPILE_OPTION(option, opt, peephole_optimization);
00341 SET_COMPILE_OPTION(option, opt, tailcall_optimization);
00342 SET_COMPILE_OPTION(option, opt, specialized_instruction);
00343 SET_COMPILE_OPTION(option, opt, operands_unification);
00344 SET_COMPILE_OPTION(option, opt, instructions_unification);
00345 SET_COMPILE_OPTION(option, opt, stack_caching);
00346 SET_COMPILE_OPTION(option, opt, trace_instruction);
00347 SET_COMPILE_OPTION_NUM(option, opt, debug_level);
00348 #undef SET_COMPILE_OPTION
00349 #undef SET_COMPILE_OPTION_NUM
00350 }
00351 else {
00352 rb_raise(rb_eTypeError, "Compile option must be Hash/true/false/nil");
00353 }
00354 }
00355
00356 static VALUE
00357 make_compile_option_value(rb_compile_option_t *option)
00358 {
00359 VALUE opt = rb_hash_new();
00360 #define SET_COMPILE_OPTION(o, h, mem) \
00361 rb_hash_aset((h), ID2SYM(rb_intern(#mem)), (o)->mem ? Qtrue : Qfalse)
00362 #define SET_COMPILE_OPTION_NUM(o, h, mem) \
00363 rb_hash_aset((h), ID2SYM(rb_intern(#mem)), INT2NUM((o)->mem))
00364 {
00365 SET_COMPILE_OPTION(option, opt, inline_const_cache);
00366 SET_COMPILE_OPTION(option, opt, peephole_optimization);
00367 SET_COMPILE_OPTION(option, opt, tailcall_optimization);
00368 SET_COMPILE_OPTION(option, opt, specialized_instruction);
00369 SET_COMPILE_OPTION(option, opt, operands_unification);
00370 SET_COMPILE_OPTION(option, opt, instructions_unification);
00371 SET_COMPILE_OPTION(option, opt, stack_caching);
00372 SET_COMPILE_OPTION_NUM(option, opt, debug_level);
00373 }
00374 #undef SET_COMPILE_OPTION
00375 #undef SET_COMPILE_OPTION_NUM
00376 return opt;
00377 }
00378
00379 VALUE
00380 rb_iseq_new(NODE *node, VALUE name, VALUE filename, VALUE filepath,
00381 VALUE parent, enum iseq_type type)
00382 {
00383 return rb_iseq_new_with_opt(node, name, filename, filepath, INT2FIX(0), parent, type,
00384 &COMPILE_OPTION_DEFAULT);
00385 }
00386
00387 VALUE
00388 rb_iseq_new_top(NODE *node, VALUE name, VALUE filename, VALUE filepath, VALUE parent)
00389 {
00390 return rb_iseq_new_with_opt(node, name, filename, filepath, INT2FIX(0), parent, ISEQ_TYPE_TOP,
00391 &COMPILE_OPTION_DEFAULT);
00392 }
00393
00394 VALUE
00395 rb_iseq_new_main(NODE *node, VALUE filename, VALUE filepath)
00396 {
00397 rb_thread_t *th = GET_THREAD();
00398 VALUE parent = th->base_block->iseq->self;
00399 return rb_iseq_new_with_opt(node, rb_str_new2("<main>"), filename, filepath, INT2FIX(0),
00400 parent, ISEQ_TYPE_MAIN, &COMPILE_OPTION_DEFAULT);
00401 }
00402
00403 static VALUE
00404 rb_iseq_new_with_bopt_and_opt(NODE *node, VALUE name, VALUE filename, VALUE filepath, VALUE line_no,
00405 VALUE parent, enum iseq_type type, VALUE bopt,
00406 const rb_compile_option_t *option)
00407 {
00408 rb_iseq_t *iseq;
00409 VALUE self = iseq_alloc(rb_cISeq);
00410
00411 GetISeqPtr(self, iseq);
00412 iseq->self = self;
00413
00414 prepare_iseq_build(iseq, name, filename, filepath, line_no, parent, type, bopt, option);
00415 rb_iseq_compile_node(self, node);
00416 cleanup_iseq_build(iseq);
00417 return self;
00418 }
00419
00420 VALUE
00421 rb_iseq_new_with_opt(NODE *node, VALUE name, VALUE filename, VALUE filepath, VALUE line_no,
00422 VALUE parent, enum iseq_type type,
00423 const rb_compile_option_t *option)
00424 {
00425
00426 return rb_iseq_new_with_bopt_and_opt(node, name, filename, filepath, line_no, parent, type,
00427 Qfalse, option);
00428 }
00429
00430 VALUE
00431 rb_iseq_new_with_bopt(NODE *node, VALUE name, VALUE filename, VALUE filepath, VALUE line_no,
00432 VALUE parent, enum iseq_type type, VALUE bopt)
00433 {
00434
00435 return rb_iseq_new_with_bopt_and_opt(node, name, filename, filepath, line_no, parent, type,
00436 bopt, &COMPILE_OPTION_DEFAULT);
00437 }
00438
00439 #define CHECK_ARRAY(v) rb_convert_type((v), T_ARRAY, "Array", "to_ary")
00440 #define CHECK_STRING(v) rb_convert_type((v), T_STRING, "String", "to_str")
00441 #define CHECK_SYMBOL(v) rb_convert_type((v), T_SYMBOL, "Symbol", "to_sym")
00442 static inline VALUE CHECK_INTEGER(VALUE v) {(void)NUM2LONG(v); return v;}
00443 static VALUE
00444 iseq_load(VALUE self, VALUE data, VALUE parent, VALUE opt)
00445 {
00446 VALUE iseqval = iseq_alloc(self);
00447
00448 VALUE magic, version1, version2, format_type, misc;
00449 VALUE name, filename, filepath, line_no;
00450 VALUE type, body, locals, args, exception;
00451
00452 st_data_t iseq_type;
00453 struct st_table *type_map = 0;
00454 rb_iseq_t *iseq;
00455 rb_compile_option_t option;
00456 int i = 0;
00457
00458
00459
00460
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++);
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);
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
00685
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:
00745 ret = rb_sprintf("%"PRIdVALUE, (VALUE)(pos + len + op));
00746 break;
00747
00748 case TS_NUM:
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:
00787 op = ID2SYM(op);
00788
00789 case TS_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:
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
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
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
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",
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
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;
01111 VALUE locals = rb_ary_new();
01112 VALUE args = rb_ary_new();
01113 VALUE body = rb_ary_new();
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
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
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
01173 {
01174
01175
01176
01177
01178
01179
01180
01181
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
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
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
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
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);
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
01331
01332
01333
01334 rb_ary_push(val, rb_str_new2("YARVInstructionSequence/SimpleDataFormat"));
01335 rb_ary_push(val, INT2FIX(ISEQ_MAJOR_VERSION));
01336 rb_ary_push(val, INT2FIX(ISEQ_MINOR_VERSION));
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
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
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
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
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
01518
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