00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "ruby/ruby.h"
00013 #include "internal.h"
00014 #include "eval_intern.h"
00015
00016
00017 #include "gc.h"
00018 #include "vm_core.h"
00019 #include "iseq.h"
00020
00021 #include "insns.inc"
00022 #include "insns_info.inc"
00023
00024 #define ISEQ_MAJOR_VERSION 2
00025 #define ISEQ_MINOR_VERSION 1
00026
00027 VALUE rb_cISeq;
00028
00029 #define hidden_obj_p(obj) (!SPECIAL_CONST_P(obj) && !RBASIC(obj)->klass)
00030
00031 static inline VALUE
00032 obj_resurrect(VALUE obj)
00033 {
00034 if (hidden_obj_p(obj)) {
00035 switch (BUILTIN_TYPE(obj)) {
00036 case T_STRING:
00037 obj = rb_str_resurrect(obj);
00038 break;
00039 case T_ARRAY:
00040 obj = rb_ary_resurrect(obj);
00041 break;
00042 }
00043 }
00044 return obj;
00045 }
00046
00047 static void
00048 compile_data_free(struct iseq_compile_data *compile_data)
00049 {
00050 if (compile_data) {
00051 struct iseq_compile_data_storage *cur, *next;
00052 cur = compile_data->storage_head;
00053 while (cur) {
00054 next = cur->next;
00055 ruby_xfree(cur);
00056 cur = next;
00057 }
00058 ruby_xfree(compile_data);
00059 }
00060 }
00061
00062 static void
00063 iseq_free(void *ptr)
00064 {
00065 rb_iseq_t *iseq;
00066 RUBY_FREE_ENTER("iseq");
00067
00068 if (ptr) {
00069 iseq = ptr;
00070 if (!iseq->orig) {
00071
00072 if (0) {
00073 RUBY_GC_INFO("%s @ %s\n", RSTRING_PTR(iseq->location.label),
00074 RSTRING_PTR(iseq->location.path));
00075 }
00076
00077 if (iseq->iseq != iseq->iseq_encoded) {
00078 RUBY_FREE_UNLESS_NULL(iseq->iseq_encoded);
00079 }
00080
00081 RUBY_FREE_UNLESS_NULL(iseq->iseq);
00082 RUBY_FREE_UNLESS_NULL(iseq->line_info_table);
00083 RUBY_FREE_UNLESS_NULL(iseq->local_table);
00084 RUBY_FREE_UNLESS_NULL(iseq->is_entries);
00085 RUBY_FREE_UNLESS_NULL(iseq->callinfo_entries);
00086 RUBY_FREE_UNLESS_NULL(iseq->catch_table);
00087 RUBY_FREE_UNLESS_NULL(iseq->arg_opt_table);
00088 RUBY_FREE_UNLESS_NULL(iseq->arg_keyword_table);
00089 compile_data_free(iseq->compile_data);
00090 }
00091 ruby_xfree(ptr);
00092 }
00093 RUBY_FREE_LEAVE("iseq");
00094 }
00095
00096 static void
00097 iseq_mark(void *ptr)
00098 {
00099 RUBY_MARK_ENTER("iseq");
00100
00101 if (ptr) {
00102 rb_iseq_t *iseq = ptr;
00103
00104 RUBY_GC_INFO("%s @ %s\n", RSTRING_PTR(iseq->location.label), RSTRING_PTR(iseq->location.path));
00105 RUBY_MARK_UNLESS_NULL(iseq->mark_ary);
00106
00107 RUBY_MARK_UNLESS_NULL(iseq->location.label);
00108 RUBY_MARK_UNLESS_NULL(iseq->location.base_label);
00109 RUBY_MARK_UNLESS_NULL(iseq->location.path);
00110 RUBY_MARK_UNLESS_NULL(iseq->location.absolute_path);
00111
00112 RUBY_MARK_UNLESS_NULL((VALUE)iseq->cref_stack);
00113 RUBY_MARK_UNLESS_NULL(iseq->klass);
00114 RUBY_MARK_UNLESS_NULL(iseq->coverage);
00115 RUBY_MARK_UNLESS_NULL(iseq->orig);
00116
00117 if (iseq->compile_data != 0) {
00118 struct iseq_compile_data *const compile_data = iseq->compile_data;
00119 RUBY_MARK_UNLESS_NULL(compile_data->mark_ary);
00120 RUBY_MARK_UNLESS_NULL(compile_data->err_info);
00121 RUBY_MARK_UNLESS_NULL(compile_data->catch_table_ary);
00122 }
00123 }
00124 RUBY_MARK_LEAVE("iseq");
00125 }
00126
00127 static size_t
00128 iseq_memsize(const void *ptr)
00129 {
00130 size_t size = sizeof(rb_iseq_t);
00131 const rb_iseq_t *iseq;
00132
00133 if (ptr) {
00134 iseq = ptr;
00135 if (!iseq->orig) {
00136 if (iseq->iseq != iseq->iseq_encoded) {
00137 size += iseq->iseq_size * sizeof(VALUE);
00138 }
00139
00140 size += iseq->iseq_size * sizeof(VALUE);
00141 size += iseq->line_info_size * sizeof(struct iseq_line_info_entry);
00142 size += iseq->local_table_size * sizeof(ID);
00143 size += iseq->catch_table_size * sizeof(struct iseq_catch_table_entry);
00144 size += iseq->arg_opts * sizeof(VALUE);
00145 size += iseq->is_size * sizeof(union iseq_inline_storage_entry);
00146 size += iseq->callinfo_size * sizeof(rb_call_info_t);
00147
00148 if (iseq->compile_data) {
00149 struct iseq_compile_data_storage *cur;
00150
00151 cur = iseq->compile_data->storage_head;
00152 while (cur) {
00153 size += cur->size + sizeof(struct iseq_compile_data_storage);
00154 cur = cur->next;
00155 }
00156 size += sizeof(struct iseq_compile_data);
00157 }
00158 }
00159 }
00160
00161 return size;
00162 }
00163
00164 static const rb_data_type_t iseq_data_type = {
00165 "iseq",
00166 {
00167 iseq_mark,
00168 iseq_free,
00169 iseq_memsize,
00170 },
00171 NULL, NULL,
00172 RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
00173 };
00174
00175 static VALUE
00176 iseq_alloc(VALUE klass)
00177 {
00178 rb_iseq_t *iseq;
00179 return TypedData_Make_Struct(klass, rb_iseq_t, &iseq_data_type, iseq);
00180 }
00181
00182 static rb_iseq_location_t *
00183 iseq_location_setup(rb_iseq_t *iseq, VALUE path, VALUE absolute_path, VALUE name, size_t first_lineno)
00184 {
00185 rb_iseq_location_t *loc = &iseq->location;
00186 RB_OBJ_WRITE(iseq->self, &loc->path, path);
00187 if (RTEST(absolute_path) && rb_str_cmp(path, absolute_path) == 0) {
00188 RB_OBJ_WRITE(iseq->self, &loc->absolute_path, path);
00189 }
00190 else {
00191 RB_OBJ_WRITE(iseq->self, &loc->absolute_path, absolute_path);
00192 }
00193 RB_OBJ_WRITE(iseq->self, &loc->label, name);
00194 RB_OBJ_WRITE(iseq->self, &loc->base_label, name);
00195 loc->first_lineno = first_lineno;
00196 return loc;
00197 }
00198
00199 #define ISEQ_SET_CREF(iseq, cref) RB_OBJ_WRITE((iseq)->self, &(iseq)->cref_stack, (cref))
00200
00201 static void
00202 set_relation(rb_iseq_t *iseq, const VALUE parent)
00203 {
00204 const VALUE type = iseq->type;
00205 rb_thread_t *th = GET_THREAD();
00206 rb_iseq_t *piseq;
00207
00208
00209 if (type == ISEQ_TYPE_TOP) {
00210
00211 RB_OBJ_WRITE(iseq->self, &iseq->cref_stack, NEW_CREF(rb_cObject));
00212 iseq->cref_stack->nd_refinements = Qnil;
00213 iseq->cref_stack->nd_visi = NOEX_PRIVATE;
00214 if (th->top_wrapper) {
00215 NODE *cref = NEW_CREF(th->top_wrapper);
00216 cref->nd_refinements = Qnil;
00217 cref->nd_visi = NOEX_PRIVATE;
00218 RB_OBJ_WRITE(cref, &cref->nd_next, iseq->cref_stack);
00219 ISEQ_SET_CREF(iseq, cref);
00220 }
00221 iseq->local_iseq = iseq;
00222 }
00223 else if (type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) {
00224 ISEQ_SET_CREF(iseq, NEW_CREF(0));
00225 iseq->cref_stack->nd_refinements = Qnil;
00226 iseq->local_iseq = iseq;
00227 }
00228 else if (RTEST(parent)) {
00229 GetISeqPtr(parent, piseq);
00230 ISEQ_SET_CREF(iseq, piseq->cref_stack);
00231 iseq->local_iseq = piseq->local_iseq;
00232 }
00233
00234 if (RTEST(parent)) {
00235 GetISeqPtr(parent, piseq);
00236 iseq->parent_iseq = piseq;
00237 }
00238
00239 if (type == ISEQ_TYPE_MAIN) {
00240 iseq->local_iseq = iseq;
00241 }
00242 }
00243
00244 void
00245 rb_iseq_add_mark_object(rb_iseq_t *iseq, VALUE obj)
00246 {
00247 if (!RTEST(iseq->mark_ary)) {
00248 RB_OBJ_WRITE(iseq->self, &iseq->mark_ary, rb_ary_tmp_new(3));
00249 RBASIC_CLEAR_CLASS(iseq->mark_ary);
00250 }
00251 rb_ary_push(iseq->mark_ary, obj);
00252 }
00253
00254 static VALUE
00255 prepare_iseq_build(rb_iseq_t *iseq,
00256 VALUE name, VALUE path, VALUE absolute_path, VALUE first_lineno,
00257 VALUE parent, enum iseq_type type, VALUE block_opt,
00258 const rb_compile_option_t *option)
00259 {
00260 iseq->type = type;
00261 iseq->arg_rest = -1;
00262 iseq->arg_block = -1;
00263 iseq->arg_keyword = -1;
00264 RB_OBJ_WRITE(iseq->self, &iseq->klass, 0);
00265 set_relation(iseq, parent);
00266
00267 name = rb_fstring(name);
00268 path = rb_fstring(path);
00269 if (RTEST(absolute_path))
00270 absolute_path = rb_fstring(absolute_path);
00271
00272 iseq_location_setup(iseq, path, absolute_path, name, first_lineno);
00273 if (iseq != iseq->local_iseq) {
00274 RB_OBJ_WRITE(iseq->self, &iseq->location.base_label, iseq->local_iseq->location.label);
00275 }
00276
00277 iseq->defined_method_id = 0;
00278 RB_OBJ_WRITE(iseq->self, &iseq->mark_ary, 0);
00279
00280
00281
00282
00283
00284
00285
00286 iseq->compile_data = ALLOC(struct iseq_compile_data);
00287 MEMZERO(iseq->compile_data, struct iseq_compile_data, 1);
00288 RB_OBJ_WRITE(iseq->self, &iseq->compile_data->err_info, Qnil);
00289 RB_OBJ_WRITE(iseq->self, &iseq->compile_data->mark_ary, rb_ary_tmp_new(3));
00290
00291 iseq->compile_data->storage_head = iseq->compile_data->storage_current =
00292 (struct iseq_compile_data_storage *)
00293 ALLOC_N(char, INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE +
00294 sizeof(struct iseq_compile_data_storage));
00295
00296 RB_OBJ_WRITE(iseq->self, &iseq->compile_data->catch_table_ary, rb_ary_new());
00297 iseq->compile_data->storage_head->pos = 0;
00298 iseq->compile_data->storage_head->next = 0;
00299 iseq->compile_data->storage_head->size =
00300 INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE;
00301 iseq->compile_data->storage_head->buff =
00302 (char *)(&iseq->compile_data->storage_head->buff + 1);
00303 iseq->compile_data->option = option;
00304 iseq->compile_data->last_coverable_line = -1;
00305
00306 RB_OBJ_WRITE(iseq->self, &iseq->coverage, Qfalse);
00307 if (!GET_THREAD()->parse_in_eval) {
00308 VALUE coverages = rb_get_coverages();
00309 if (RTEST(coverages)) {
00310 RB_OBJ_WRITE(iseq->self, &iseq->coverage, rb_hash_lookup(coverages, path));
00311 if (NIL_P(iseq->coverage)) RB_OBJ_WRITE(iseq->self, &iseq->coverage, Qfalse);
00312 }
00313 }
00314
00315 return Qtrue;
00316 }
00317
00318 static VALUE
00319 cleanup_iseq_build(rb_iseq_t *iseq)
00320 {
00321 struct iseq_compile_data *data = iseq->compile_data;
00322 VALUE err = data->err_info;
00323 iseq->compile_data = 0;
00324 compile_data_free(data);
00325
00326 if (RTEST(err)) {
00327 rb_funcall2(err, rb_intern("set_backtrace"), 1, &iseq->location.path);
00328 rb_exc_raise(err);
00329 }
00330 return Qtrue;
00331 }
00332
00333 static rb_compile_option_t COMPILE_OPTION_DEFAULT = {
00334 OPT_INLINE_CONST_CACHE,
00335 OPT_PEEPHOLE_OPTIMIZATION,
00336 OPT_TAILCALL_OPTIMIZATION,
00337 OPT_SPECIALISED_INSTRUCTION,
00338 OPT_OPERANDS_UNIFICATION,
00339 OPT_INSTRUCTIONS_UNIFICATION,
00340 OPT_STACK_CACHING,
00341 OPT_TRACE_INSTRUCTION,
00342 };
00343 static const rb_compile_option_t COMPILE_OPTION_FALSE = {0};
00344
00345 static void
00346 make_compile_option(rb_compile_option_t *option, VALUE opt)
00347 {
00348 if (opt == Qnil) {
00349 *option = COMPILE_OPTION_DEFAULT;
00350 }
00351 else if (opt == Qfalse) {
00352 *option = COMPILE_OPTION_FALSE;
00353 }
00354 else if (opt == Qtrue) {
00355 int i;
00356 for (i = 0; i < (int)(sizeof(rb_compile_option_t) / sizeof(int)); ++i)
00357 ((int *)option)[i] = 1;
00358 }
00359 else if (CLASS_OF(opt) == rb_cHash) {
00360 *option = COMPILE_OPTION_DEFAULT;
00361
00362 #define SET_COMPILE_OPTION(o, h, mem) \
00363 { VALUE flag = rb_hash_aref((h), ID2SYM(rb_intern(#mem))); \
00364 if (flag == Qtrue) { (o)->mem = 1; } \
00365 else if (flag == Qfalse) { (o)->mem = 0; } \
00366 }
00367 #define SET_COMPILE_OPTION_NUM(o, h, mem) \
00368 { VALUE num = rb_hash_aref(opt, ID2SYM(rb_intern(#mem))); \
00369 if (!NIL_P(num)) (o)->mem = NUM2INT(num); \
00370 }
00371 SET_COMPILE_OPTION(option, opt, inline_const_cache);
00372 SET_COMPILE_OPTION(option, opt, peephole_optimization);
00373 SET_COMPILE_OPTION(option, opt, tailcall_optimization);
00374 SET_COMPILE_OPTION(option, opt, specialized_instruction);
00375 SET_COMPILE_OPTION(option, opt, operands_unification);
00376 SET_COMPILE_OPTION(option, opt, instructions_unification);
00377 SET_COMPILE_OPTION(option, opt, stack_caching);
00378 SET_COMPILE_OPTION(option, opt, trace_instruction);
00379 SET_COMPILE_OPTION_NUM(option, opt, debug_level);
00380 #undef SET_COMPILE_OPTION
00381 #undef SET_COMPILE_OPTION_NUM
00382 }
00383 else {
00384 rb_raise(rb_eTypeError, "Compile option must be Hash/true/false/nil");
00385 }
00386 }
00387
00388 static VALUE
00389 make_compile_option_value(rb_compile_option_t *option)
00390 {
00391 VALUE opt = rb_hash_new();
00392 #define SET_COMPILE_OPTION(o, h, mem) \
00393 rb_hash_aset((h), ID2SYM(rb_intern(#mem)), (o)->mem ? Qtrue : Qfalse)
00394 #define SET_COMPILE_OPTION_NUM(o, h, mem) \
00395 rb_hash_aset((h), ID2SYM(rb_intern(#mem)), INT2NUM((o)->mem))
00396 {
00397 SET_COMPILE_OPTION(option, opt, inline_const_cache);
00398 SET_COMPILE_OPTION(option, opt, peephole_optimization);
00399 SET_COMPILE_OPTION(option, opt, tailcall_optimization);
00400 SET_COMPILE_OPTION(option, opt, specialized_instruction);
00401 SET_COMPILE_OPTION(option, opt, operands_unification);
00402 SET_COMPILE_OPTION(option, opt, instructions_unification);
00403 SET_COMPILE_OPTION(option, opt, stack_caching);
00404 SET_COMPILE_OPTION(option, opt, trace_instruction);
00405 SET_COMPILE_OPTION_NUM(option, opt, debug_level);
00406 }
00407 #undef SET_COMPILE_OPTION
00408 #undef SET_COMPILE_OPTION_NUM
00409 return opt;
00410 }
00411
00412 VALUE
00413 rb_iseq_new(NODE *node, VALUE name, VALUE path, VALUE absolute_path,
00414 VALUE parent, enum iseq_type type)
00415 {
00416 return rb_iseq_new_with_opt(node, name, path, absolute_path, INT2FIX(0), parent, type,
00417 &COMPILE_OPTION_DEFAULT);
00418 }
00419
00420 VALUE
00421 rb_iseq_new_top(NODE *node, VALUE name, VALUE path, VALUE absolute_path, VALUE parent)
00422 {
00423 return rb_iseq_new_with_opt(node, name, path, absolute_path, INT2FIX(0), parent, ISEQ_TYPE_TOP,
00424 &COMPILE_OPTION_DEFAULT);
00425 }
00426
00427 VALUE
00428 rb_iseq_new_main(NODE *node, VALUE path, VALUE absolute_path)
00429 {
00430 rb_thread_t *th = GET_THREAD();
00431 VALUE parent = th->base_block->iseq->self;
00432 return rb_iseq_new_with_opt(node, rb_str_new2("<main>"), path, absolute_path, INT2FIX(0),
00433 parent, ISEQ_TYPE_MAIN, &COMPILE_OPTION_DEFAULT);
00434 }
00435
00436 static VALUE
00437 rb_iseq_new_with_bopt_and_opt(NODE *node, VALUE name, VALUE path, VALUE absolute_path, VALUE first_lineno,
00438 VALUE parent, enum iseq_type type, VALUE bopt,
00439 const rb_compile_option_t *option)
00440 {
00441 rb_iseq_t *iseq;
00442 VALUE self = iseq_alloc(rb_cISeq);
00443
00444 GetISeqPtr(self, iseq);
00445 iseq->self = self;
00446
00447 prepare_iseq_build(iseq, name, path, absolute_path, first_lineno, parent, type, bopt, option);
00448 rb_iseq_compile_node(self, node);
00449 cleanup_iseq_build(iseq);
00450 return self;
00451 }
00452
00453 VALUE
00454 rb_iseq_new_with_opt(NODE *node, VALUE name, VALUE path, VALUE absolute_path, VALUE first_lineno,
00455 VALUE parent, enum iseq_type type,
00456 const rb_compile_option_t *option)
00457 {
00458
00459 return rb_iseq_new_with_bopt_and_opt(node, name, path, absolute_path, first_lineno, parent, type,
00460 Qfalse, option);
00461 }
00462
00463 VALUE
00464 rb_iseq_new_with_bopt(NODE *node, VALUE name, VALUE path, VALUE absolute_path, VALUE first_lineno,
00465 VALUE parent, enum iseq_type type, VALUE bopt)
00466 {
00467
00468 return rb_iseq_new_with_bopt_and_opt(node, name, path, absolute_path, first_lineno, parent, type,
00469 bopt, &COMPILE_OPTION_DEFAULT);
00470 }
00471
00472 #define CHECK_ARRAY(v) rb_convert_type((v), T_ARRAY, "Array", "to_ary")
00473 #define CHECK_STRING(v) rb_convert_type((v), T_STRING, "String", "to_str")
00474 #define CHECK_SYMBOL(v) rb_convert_type((v), T_SYMBOL, "Symbol", "to_sym")
00475 static inline VALUE CHECK_INTEGER(VALUE v) {(void)NUM2LONG(v); return v;}
00476 static VALUE
00477 iseq_load(VALUE self, VALUE data, VALUE parent, VALUE opt)
00478 {
00479 VALUE iseqval = iseq_alloc(self);
00480
00481 VALUE magic, version1, version2, format_type, misc;
00482 VALUE name, path, absolute_path, first_lineno;
00483 VALUE type, body, locals, args, exception;
00484
00485 st_data_t iseq_type;
00486 static struct st_table *type_map_cache = 0;
00487 struct st_table *type_map = 0;
00488 rb_iseq_t *iseq;
00489 rb_compile_option_t option;
00490 int i = 0;
00491
00492
00493
00494
00495
00496
00497 data = CHECK_ARRAY(data);
00498
00499 magic = CHECK_STRING(rb_ary_entry(data, i++));
00500 version1 = CHECK_INTEGER(rb_ary_entry(data, i++));
00501 version2 = CHECK_INTEGER(rb_ary_entry(data, i++));
00502 format_type = CHECK_INTEGER(rb_ary_entry(data, i++));
00503 misc = rb_ary_entry(data, i++);
00504 ((void)magic, (void)version1, (void)version2, (void)format_type, (void)misc);
00505
00506 name = CHECK_STRING(rb_ary_entry(data, i++));
00507 path = CHECK_STRING(rb_ary_entry(data, i++));
00508 absolute_path = rb_ary_entry(data, i++);
00509 absolute_path = NIL_P(absolute_path) ? Qnil : CHECK_STRING(absolute_path);
00510 first_lineno = CHECK_INTEGER(rb_ary_entry(data, i++));
00511
00512 type = CHECK_SYMBOL(rb_ary_entry(data, i++));
00513 locals = CHECK_ARRAY(rb_ary_entry(data, i++));
00514
00515 args = rb_ary_entry(data, i++);
00516 if (FIXNUM_P(args) || (args = CHECK_ARRAY(args))) {
00517
00518 }
00519
00520 exception = CHECK_ARRAY(rb_ary_entry(data, i++));
00521 body = CHECK_ARRAY(rb_ary_entry(data, i++));
00522
00523 GetISeqPtr(iseqval, iseq);
00524 iseq->self = iseqval;
00525 iseq->local_iseq = iseq;
00526
00527 type_map = type_map_cache;
00528 if (type_map == 0) {
00529 struct st_table *cached_map;
00530 type_map = st_init_numtable();
00531 st_insert(type_map, ID2SYM(rb_intern("top")), ISEQ_TYPE_TOP);
00532 st_insert(type_map, ID2SYM(rb_intern("method")), ISEQ_TYPE_METHOD);
00533 st_insert(type_map, ID2SYM(rb_intern("block")), ISEQ_TYPE_BLOCK);
00534 st_insert(type_map, ID2SYM(rb_intern("class")), ISEQ_TYPE_CLASS);
00535 st_insert(type_map, ID2SYM(rb_intern("rescue")), ISEQ_TYPE_RESCUE);
00536 st_insert(type_map, ID2SYM(rb_intern("ensure")), ISEQ_TYPE_ENSURE);
00537 st_insert(type_map, ID2SYM(rb_intern("eval")), ISEQ_TYPE_EVAL);
00538 st_insert(type_map, ID2SYM(rb_intern("main")), ISEQ_TYPE_MAIN);
00539 st_insert(type_map, ID2SYM(rb_intern("defined_guard")), ISEQ_TYPE_DEFINED_GUARD);
00540 cached_map = ATOMIC_PTR_CAS(type_map_cache, (struct st_table *)0, type_map);
00541 if (cached_map) {
00542 st_free_table(type_map);
00543 type_map = cached_map;
00544 }
00545 }
00546
00547 if (st_lookup(type_map, type, &iseq_type) == 0) {
00548 ID typeid = SYM2ID(type);
00549 VALUE typename = rb_id2str(typeid);
00550 if (typename)
00551 rb_raise(rb_eTypeError, "unsupport type: :%"PRIsVALUE, typename);
00552 else
00553 rb_raise(rb_eTypeError, "unsupport type: %p", (void *)typeid);
00554 }
00555
00556 if (parent == Qnil) {
00557 parent = 0;
00558 }
00559
00560 make_compile_option(&option, opt);
00561 prepare_iseq_build(iseq, name, path, absolute_path, first_lineno,
00562 parent, (enum iseq_type)iseq_type, 0, &option);
00563
00564 rb_iseq_build_from_ary(iseq, locals, args, exception, body);
00565
00566 cleanup_iseq_build(iseq);
00567 return iseqval;
00568 }
00569
00570
00571
00572
00573 static VALUE
00574 iseq_s_load(int argc, VALUE *argv, VALUE self)
00575 {
00576 VALUE data, opt=Qnil;
00577 rb_scan_args(argc, argv, "11", &data, &opt);
00578
00579 return iseq_load(self, data, 0, opt);
00580 }
00581
00582 VALUE
00583 rb_iseq_load(VALUE data, VALUE parent, VALUE opt)
00584 {
00585 return iseq_load(rb_cISeq, data, parent, opt);
00586 }
00587
00588 VALUE
00589 rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE absolute_path, VALUE line, rb_block_t *base_block, VALUE opt)
00590 {
00591 int state;
00592 rb_thread_t *th = GET_THREAD();
00593 rb_block_t *prev_base_block = th->base_block;
00594 VALUE iseqval = Qundef;
00595
00596 th->base_block = base_block;
00597
00598 TH_PUSH_TAG(th);
00599 if ((state = EXEC_TAG()) == 0) {
00600 VALUE parser;
00601 int ln = NUM2INT(line);
00602 NODE *node;
00603 rb_compile_option_t option;
00604
00605 StringValueCStr(file);
00606 make_compile_option(&option, opt);
00607
00608 parser = rb_parser_new();
00609
00610 if (RB_TYPE_P((src), T_FILE))
00611 node = rb_parser_compile_file_path(parser, file, src, ln);
00612 else {
00613 node = rb_parser_compile_string_path(parser, file, src, ln);
00614
00615 if (!node) {
00616 rb_exc_raise(GET_THREAD()->errinfo);
00617 }
00618 }
00619
00620 if (base_block && base_block->iseq) {
00621 iseqval = rb_iseq_new_with_opt(node, base_block->iseq->location.label,
00622 file, absolute_path, line, base_block->iseq->self,
00623 ISEQ_TYPE_EVAL, &option);
00624 }
00625 else {
00626 iseqval = rb_iseq_new_with_opt(node, rb_str_new2("<compiled>"), file, absolute_path, line, Qfalse,
00627 ISEQ_TYPE_TOP, &option);
00628 }
00629 }
00630 TH_POP_TAG();
00631
00632 th->base_block = prev_base_block;
00633
00634 if (state) {
00635 JUMP_TAG(state);
00636 }
00637
00638 return iseqval;
00639 }
00640
00641 VALUE
00642 rb_iseq_compile(VALUE src, VALUE file, VALUE line)
00643 {
00644 return rb_iseq_compile_with_option(src, file, Qnil, line, 0, Qnil);
00645 }
00646
00647 VALUE
00648 rb_iseq_compile_on_base(VALUE src, VALUE file, VALUE line, rb_block_t *base_block)
00649 {
00650 return rb_iseq_compile_with_option(src, file, Qnil, line, base_block, Qnil);
00651 }
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674 static VALUE
00675 iseq_s_compile(int argc, VALUE *argv, VALUE self)
00676 {
00677 VALUE src, file = Qnil, path = Qnil, line = INT2FIX(1), opt = Qnil;
00678
00679 rb_secure(1);
00680
00681 rb_scan_args(argc, argv, "14", &src, &file, &path, &line, &opt);
00682 if (NIL_P(file)) file = rb_str_new2("<compiled>");
00683 if (NIL_P(line)) line = INT2FIX(1);
00684
00685 return rb_iseq_compile_with_option(src, file, path, line, 0, opt);
00686 }
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708 static VALUE
00709 iseq_s_compile_file(int argc, VALUE *argv, VALUE self)
00710 {
00711 VALUE file, line = INT2FIX(1), opt = Qnil;
00712 VALUE parser;
00713 VALUE f;
00714 NODE *node;
00715 const char *fname;
00716 rb_compile_option_t option;
00717
00718 rb_secure(1);
00719 rb_scan_args(argc, argv, "11", &file, &opt);
00720 FilePathValue(file);
00721 fname = StringValueCStr(file);
00722
00723 f = rb_file_open_str(file, "r");
00724
00725 parser = rb_parser_new();
00726 node = rb_parser_compile_file(parser, fname, f, NUM2INT(line));
00727 make_compile_option(&option, opt);
00728 return rb_iseq_new_with_opt(node, rb_str_new2("<main>"), file,
00729 rb_realpath_internal(Qnil, file, 1), line, Qfalse,
00730 ISEQ_TYPE_TOP, &option);
00731 }
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765 static VALUE
00766 iseq_s_compile_option_set(VALUE self, VALUE opt)
00767 {
00768 rb_compile_option_t option;
00769 rb_secure(1);
00770 make_compile_option(&option, opt);
00771 COMPILE_OPTION_DEFAULT = option;
00772 return opt;
00773 }
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783 static VALUE
00784 iseq_s_compile_option_get(VALUE self)
00785 {
00786 return make_compile_option_value(&COMPILE_OPTION_DEFAULT);
00787 }
00788
00789 static rb_iseq_t *
00790 iseq_check(VALUE val)
00791 {
00792 rb_iseq_t *iseq;
00793 GetISeqPtr(val, iseq);
00794 if (!iseq->location.label) {
00795 rb_raise(rb_eTypeError, "uninitialized InstructionSequence");
00796 }
00797 return iseq;
00798 }
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808 static VALUE
00809 iseq_eval(VALUE self)
00810 {
00811 rb_secure(1);
00812 return rb_iseq_eval(self);
00813 }
00814
00815
00816
00817
00818
00819 static VALUE
00820 iseq_inspect(VALUE self)
00821 {
00822 rb_iseq_t *iseq;
00823 GetISeqPtr(self, iseq);
00824 if (!iseq->location.label) {
00825 return rb_sprintf("#<%s: uninitialized>", rb_obj_classname(self));
00826 }
00827
00828 return rb_sprintf("<%s:%s@%s>",
00829 rb_obj_classname(self),
00830 RSTRING_PTR(iseq->location.label), RSTRING_PTR(iseq->location.path));
00831 }
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856 VALUE
00857 rb_iseq_path(VALUE self)
00858 {
00859 rb_iseq_t *iseq;
00860 GetISeqPtr(self, iseq);
00861 return iseq->location.path;
00862 }
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880 VALUE
00881 rb_iseq_absolute_path(VALUE self)
00882 {
00883 rb_iseq_t *iseq;
00884 GetISeqPtr(self, iseq);
00885 return iseq->location.absolute_path;
00886 }
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911 VALUE
00912 rb_iseq_label(VALUE self)
00913 {
00914 rb_iseq_t *iseq;
00915 GetISeqPtr(self, iseq);
00916 return iseq->location.label;
00917 }
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939 VALUE
00940 rb_iseq_base_label(VALUE self)
00941 {
00942 rb_iseq_t *iseq;
00943 GetISeqPtr(self, iseq);
00944 return iseq->location.base_label;
00945 }
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957 VALUE
00958 rb_iseq_first_lineno(VALUE self)
00959 {
00960 rb_iseq_t *iseq;
00961 GetISeqPtr(self, iseq);
00962 return iseq->location.first_lineno;
00963 }
00964
00965 VALUE
00966 rb_iseq_klass(VALUE self)
00967 {
00968 rb_iseq_t *iseq;
00969 GetISeqPtr(self, iseq);
00970 return iseq->local_iseq->klass;
00971 }
00972
00973 VALUE
00974 rb_iseq_method_name(VALUE self)
00975 {
00976 rb_iseq_t *iseq, *local_iseq;
00977 GetISeqPtr(self, iseq);
00978 local_iseq = iseq->local_iseq;
00979 if (local_iseq->type == ISEQ_TYPE_METHOD) {
00980 return local_iseq->location.base_label;
00981 }
00982 else {
00983 return Qnil;
00984 }
00985 }
00986
00987 static
00988 VALUE iseq_data_to_ary(rb_iseq_t *iseq);
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075 static VALUE
01076 iseq_to_a(VALUE self)
01077 {
01078 rb_iseq_t *iseq = iseq_check(self);
01079 rb_secure(1);
01080 return iseq_data_to_ary(iseq);
01081 }
01082
01083
01084
01085
01086 static struct iseq_line_info_entry *
01087 get_line_info(const rb_iseq_t *iseq, size_t pos)
01088 {
01089 size_t i = 0, size = iseq->line_info_size;
01090 struct iseq_line_info_entry *table = iseq->line_info_table;
01091 const int debug = 0;
01092
01093 if (debug) {
01094 printf("size: %"PRIdSIZE"\n", size);
01095 printf("table[%"PRIdSIZE"]: position: %d, line: %d, pos: %"PRIdSIZE"\n",
01096 i, table[i].position, table[i].line_no, pos);
01097 }
01098
01099 if (size == 0) {
01100 return 0;
01101 }
01102 else if (size == 1) {
01103 return &table[0];
01104 }
01105 else {
01106 for (i=1; i<size; i++) {
01107 if (debug) printf("table[%"PRIdSIZE"]: position: %d, line: %d, pos: %"PRIdSIZE"\n",
01108 i, table[i].position, table[i].line_no, pos);
01109
01110 if (table[i].position == pos) {
01111 return &table[i];
01112 }
01113 if (table[i].position > pos) {
01114 return &table[i-1];
01115 }
01116 }
01117 }
01118 return &table[i-1];
01119 }
01120
01121 static unsigned int
01122 find_line_no(const rb_iseq_t *iseq, size_t pos)
01123 {
01124 struct iseq_line_info_entry *entry = get_line_info(iseq, pos);
01125 if (entry) {
01126 return entry->line_no;
01127 }
01128 else {
01129 return 0;
01130 }
01131 }
01132
01133 unsigned int
01134 rb_iseq_line_no(const rb_iseq_t *iseq, size_t pos)
01135 {
01136 if (pos == 0) {
01137 return find_line_no(iseq, pos);
01138 }
01139 else {
01140 return find_line_no(iseq, pos - 1);
01141 }
01142 }
01143
01144 static VALUE
01145 id_to_name(ID id, VALUE default_value)
01146 {
01147 VALUE str = rb_id2str(id);
01148 if (!str) {
01149 str = default_value;
01150 }
01151 else if (!rb_str_symname_p(str)) {
01152 str = rb_str_inspect(str);
01153 }
01154 return str;
01155 }
01156
01157 VALUE
01158 rb_insn_operand_intern(rb_iseq_t *iseq,
01159 VALUE insn, int op_no, VALUE op,
01160 int len, size_t pos, VALUE *pnop, VALUE child)
01161 {
01162 const char *types = insn_op_types(insn);
01163 char type = types[op_no];
01164 VALUE ret;
01165
01166 switch (type) {
01167 case TS_OFFSET:
01168 ret = rb_sprintf("%"PRIdVALUE, (VALUE)(pos + len + op));
01169 break;
01170
01171 case TS_NUM:
01172 ret = rb_sprintf("%"PRIuVALUE, op);
01173 break;
01174
01175 case TS_LINDEX:{
01176 if (insn == BIN(getlocal) || insn == BIN(setlocal)) {
01177 if (pnop) {
01178 rb_iseq_t *diseq = iseq;
01179 VALUE level = *pnop, i;
01180
01181 for (i = 0; i < level; i++) {
01182 diseq = diseq->parent_iseq;
01183 }
01184 ret = id_to_name(diseq->local_table[diseq->local_size - op], INT2FIX('*'));
01185 }
01186 else {
01187 ret = rb_sprintf("%"PRIuVALUE, op);
01188 }
01189 }
01190 else {
01191 ret = rb_inspect(INT2FIX(op));
01192 }
01193 break;
01194 }
01195 case TS_ID:
01196 op = ID2SYM(op);
01197
01198 case TS_VALUE:
01199 op = obj_resurrect(op);
01200 ret = rb_inspect(op);
01201 if (CLASS_OF(op) == rb_cISeq) {
01202 if (child) {
01203 rb_ary_push(child, op);
01204 }
01205 }
01206 break;
01207
01208 case TS_ISEQ:
01209 {
01210 rb_iseq_t *iseq = (rb_iseq_t *)op;
01211 if (iseq) {
01212 ret = iseq->location.label;
01213 if (child) {
01214 rb_ary_push(child, iseq->self);
01215 }
01216 }
01217 else {
01218 ret = rb_str_new2("nil");
01219 }
01220 break;
01221 }
01222 case TS_GENTRY:
01223 {
01224 struct rb_global_entry *entry = (struct rb_global_entry *)op;
01225 ret = rb_str_dup(rb_id2str(entry->id));
01226 }
01227 break;
01228
01229 case TS_IC:
01230 ret = rb_sprintf("<is:%"PRIdPTRDIFF">", (union iseq_inline_storage_entry *)op - iseq->is_entries);
01231 break;
01232
01233 case TS_CALLINFO:
01234 {
01235 rb_call_info_t *ci = (rb_call_info_t *)op;
01236 VALUE ary = rb_ary_new();
01237
01238 if (ci->mid) {
01239 rb_ary_push(ary, rb_sprintf("mid:%s", rb_id2name(ci->mid)));
01240 }
01241
01242 rb_ary_push(ary, rb_sprintf("argc:%d", ci->orig_argc));
01243
01244 if (ci->blockiseq) {
01245 if (child) {
01246 rb_ary_push(child, ci->blockiseq->self);
01247 }
01248 rb_ary_push(ary, rb_sprintf("block:%"PRIsVALUE, ci->blockiseq->location.label));
01249 }
01250
01251 if (ci->flag) {
01252 VALUE flags = rb_ary_new();
01253 if (ci->flag & VM_CALL_ARGS_SPLAT) rb_ary_push(flags, rb_str_new2("ARGS_SPLAT"));
01254 if (ci->flag & VM_CALL_ARGS_BLOCKARG) rb_ary_push(flags, rb_str_new2("ARGS_BLOCKARG"));
01255 if (ci->flag & VM_CALL_FCALL) rb_ary_push(flags, rb_str_new2("FCALL"));
01256 if (ci->flag & VM_CALL_VCALL) rb_ary_push(flags, rb_str_new2("VCALL"));
01257 if (ci->flag & VM_CALL_TAILCALL) rb_ary_push(flags, rb_str_new2("TAILCALL"));
01258 if (ci->flag & VM_CALL_SUPER) rb_ary_push(flags, rb_str_new2("SUPER"));
01259 if (ci->flag & VM_CALL_OPT_SEND) rb_ary_push(flags, rb_str_new2("SNED"));
01260 if (ci->flag & VM_CALL_ARGS_SKIP_SETUP) rb_ary_push(flags, rb_str_new2("ARGS_SKIP"));
01261 rb_ary_push(ary, rb_ary_join(flags, rb_str_new2("|")));
01262 }
01263 ret = rb_sprintf("<callinfo!%"PRIsVALUE">", rb_ary_join(ary, rb_str_new2(", ")));
01264 }
01265 break;
01266
01267 case TS_CDHASH:
01268 ret = rb_str_new2("<cdhash>");
01269 break;
01270
01271 case TS_FUNCPTR:
01272 ret = rb_str_new2("<funcptr>");
01273 break;
01274
01275 default:
01276 rb_bug("insn_operand_intern: unknown operand type: %c", type);
01277 }
01278 return ret;
01279 }
01280
01285 int
01286 rb_iseq_disasm_insn(VALUE ret, VALUE *iseq, size_t pos,
01287 rb_iseq_t *iseqdat, VALUE child)
01288 {
01289 VALUE insn = iseq[pos];
01290 int len = insn_len(insn);
01291 int j;
01292 const char *types = insn_op_types(insn);
01293 VALUE str = rb_str_new(0, 0);
01294 const char *insn_name_buff;
01295
01296 insn_name_buff = insn_name(insn);
01297 if (1) {
01298 rb_str_catf(str, "%04"PRIdSIZE" %-16s ", pos, insn_name_buff);
01299 }
01300 else {
01301 rb_str_catf(str, "%04"PRIdSIZE" %-16.*s ", pos,
01302 (int)strcspn(insn_name_buff, "_"), insn_name_buff);
01303 }
01304
01305 for (j = 0; types[j]; j++) {
01306 const char *types = insn_op_types(insn);
01307 VALUE opstr = rb_insn_operand_intern(iseqdat, insn, j, iseq[pos + j + 1],
01308 len, pos, &iseq[pos + j + 2],
01309 child);
01310 rb_str_concat(str, opstr);
01311
01312 if (types[j + 1]) {
01313 rb_str_cat2(str, ", ");
01314 }
01315 }
01316
01317 {
01318 unsigned int line_no = find_line_no(iseqdat, pos);
01319 unsigned int prev = pos == 0 ? 0 : find_line_no(iseqdat, pos - 1);
01320 if (line_no && line_no != prev) {
01321 long slen = RSTRING_LEN(str);
01322 slen = (slen > 70) ? 0 : (70 - slen);
01323 str = rb_str_catf(str, "%*s(%4d)", (int)slen, "", line_no);
01324 }
01325 }
01326
01327 if (ret) {
01328 rb_str_cat2(str, "\n");
01329 rb_str_concat(ret, str);
01330 }
01331 else {
01332 printf("%s\n", RSTRING_PTR(str));
01333 }
01334 return len;
01335 }
01336
01337 static const char *
01338 catch_type(int type)
01339 {
01340 switch (type) {
01341 case CATCH_TYPE_RESCUE:
01342 return "rescue";
01343 case CATCH_TYPE_ENSURE:
01344 return "ensure";
01345 case CATCH_TYPE_RETRY:
01346 return "retry";
01347 case CATCH_TYPE_BREAK:
01348 return "break";
01349 case CATCH_TYPE_REDO:
01350 return "redo";
01351 case CATCH_TYPE_NEXT:
01352 return "next";
01353 default:
01354 rb_bug("unknown catch type (%d)", type);
01355 return 0;
01356 }
01357 }
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377 VALUE
01378 rb_iseq_disasm(VALUE self)
01379 {
01380 rb_iseq_t *iseqdat = iseq_check(self);
01381 VALUE *iseq;
01382 VALUE str = rb_str_new(0, 0);
01383 VALUE child = rb_ary_new();
01384 unsigned long size;
01385 int i;
01386 long l;
01387 ID *tbl;
01388 size_t n;
01389 enum {header_minlen = 72};
01390
01391 rb_secure(1);
01392
01393 iseq = iseqdat->iseq;
01394 size = iseqdat->iseq_size;
01395
01396 rb_str_cat2(str, "== disasm: ");
01397
01398 rb_str_concat(str, iseq_inspect(iseqdat->self));
01399 if ((l = RSTRING_LEN(str)) < header_minlen) {
01400 rb_str_resize(str, header_minlen);
01401 memset(RSTRING_PTR(str) + l, '=', header_minlen - l);
01402 }
01403 rb_str_cat2(str, "\n");
01404
01405
01406 if (iseqdat->catch_table_size != 0) {
01407 rb_str_cat2(str, "== catch table\n");
01408 }
01409 for (i = 0; i < iseqdat->catch_table_size; i++) {
01410 struct iseq_catch_table_entry *entry = &iseqdat->catch_table[i];
01411 rb_str_catf(str,
01412 "| catch type: %-6s st: %04d ed: %04d sp: %04d cont: %04d\n",
01413 catch_type((int)entry->type), (int)entry->start,
01414 (int)entry->end, (int)entry->sp, (int)entry->cont);
01415 if (entry->iseq) {
01416 rb_str_concat(str, rb_iseq_disasm(entry->iseq));
01417 }
01418 }
01419 if (iseqdat->catch_table_size != 0) {
01420 rb_str_cat2(str, "|-------------------------------------"
01421 "-----------------------------------\n");
01422 }
01423
01424
01425 tbl = iseqdat->local_table;
01426
01427 if (tbl) {
01428 rb_str_catf(str,
01429 "local table (size: %d, argc: %d "
01430 "[opts: %d, rest: %d, post: %d, block: %d, keyword: %d@%d] s%d)\n",
01431 iseqdat->local_size, iseqdat->argc,
01432 iseqdat->arg_opts, iseqdat->arg_rest,
01433 iseqdat->arg_post_len, iseqdat->arg_block,
01434 iseqdat->arg_keywords, iseqdat->local_size-iseqdat->arg_keyword,
01435 iseqdat->arg_simple);
01436
01437 for (i = 0; i < iseqdat->local_table_size; i++) {
01438 long width;
01439 VALUE name = id_to_name(tbl[i], 0);
01440 char argi[0x100] = "";
01441 char opti[0x100] = "";
01442
01443 if (iseqdat->arg_opts) {
01444 int argc = iseqdat->argc;
01445 int opts = iseqdat->arg_opts;
01446 if (i >= argc && i < argc + opts - 1) {
01447 snprintf(opti, sizeof(opti), "Opt=%"PRIdVALUE,
01448 iseqdat->arg_opt_table[i - argc]);
01449 }
01450 }
01451
01452 snprintf(argi, sizeof(argi), "%s%s%s%s%s",
01453 iseqdat->argc > i ? "Arg" : "",
01454 opti,
01455 iseqdat->arg_rest == i ? "Rest" : "",
01456 (iseqdat->arg_post_start <= i &&
01457 i < iseqdat->arg_post_start + iseqdat->arg_post_len) ? "Post" : "",
01458 iseqdat->arg_block == i ? "Block" : "");
01459
01460 rb_str_catf(str, "[%2d] ", iseqdat->local_size - i);
01461 width = RSTRING_LEN(str) + 11;
01462 if (name)
01463 rb_str_append(str, name);
01464 else
01465 rb_str_cat2(str, "?");
01466 if (*argi) rb_str_catf(str, "<%s>", argi);
01467 if ((width -= RSTRING_LEN(str)) > 0) rb_str_catf(str, "%*s", (int)width, "");
01468 }
01469 rb_str_cat2(str, "\n");
01470 }
01471
01472
01473 for (n = 0; n < size;) {
01474 n += rb_iseq_disasm_insn(str, iseq, n, iseqdat, child);
01475 }
01476
01477 for (i = 0; i < RARRAY_LEN(child); i++) {
01478 VALUE isv = rb_ary_entry(child, i);
01479 rb_str_concat(str, rb_iseq_disasm(isv));
01480 }
01481
01482 return str;
01483 }
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507
01508
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520 static VALUE
01521 iseq_s_of(VALUE klass, VALUE body)
01522 {
01523 VALUE ret = Qnil;
01524 rb_iseq_t *iseq;
01525
01526 rb_secure(1);
01527
01528 if (rb_obj_is_proc(body)) {
01529 rb_proc_t *proc;
01530 GetProcPtr(body, proc);
01531 iseq = proc->block.iseq;
01532 if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
01533 ret = iseq->self;
01534 }
01535 }
01536 else if ((iseq = rb_method_get_iseq(body)) != 0) {
01537 ret = iseq->self;
01538 }
01539 return ret;
01540 }
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567
01568
01569
01570
01571
01572
01573
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595 static VALUE
01596 iseq_s_disasm(VALUE klass, VALUE body)
01597 {
01598 VALUE iseqval = iseq_s_of(klass, body);
01599 return NIL_P(iseqval) ? Qnil : rb_iseq_disasm(iseqval);
01600 }
01601
01602 const char *
01603 ruby_node_name(int node)
01604 {
01605 switch (node) {
01606 #include "node_name.inc"
01607 default:
01608 rb_bug("unknown node (%d)", node);
01609 return 0;
01610 }
01611 }
01612
01613 #define DECL_SYMBOL(name) \
01614 static VALUE sym_##name
01615
01616 #define INIT_SYMBOL(name) \
01617 sym_##name = ID2SYM(rb_intern(#name))
01618
01619 static VALUE
01620 register_label(struct st_table *table, unsigned long idx)
01621 {
01622 VALUE sym;
01623 char buff[8 + (sizeof(idx) * CHAR_BIT * 32 / 100)];
01624
01625 snprintf(buff, sizeof(buff), "label_%lu", idx);
01626 sym = ID2SYM(rb_intern(buff));
01627 st_insert(table, idx, sym);
01628 return sym;
01629 }
01630
01631 static VALUE
01632 exception_type2symbol(VALUE type)
01633 {
01634 ID id;
01635 switch (type) {
01636 case CATCH_TYPE_RESCUE: CONST_ID(id, "rescue"); break;
01637 case CATCH_TYPE_ENSURE: CONST_ID(id, "ensure"); break;
01638 case CATCH_TYPE_RETRY: CONST_ID(id, "retry"); break;
01639 case CATCH_TYPE_BREAK: CONST_ID(id, "break"); break;
01640 case CATCH_TYPE_REDO: CONST_ID(id, "redo"); break;
01641 case CATCH_TYPE_NEXT: CONST_ID(id, "next"); break;
01642 default:
01643 rb_bug("...");
01644 }
01645 return ID2SYM(id);
01646 }
01647
01648 static int
01649 cdhash_each(VALUE key, VALUE value, VALUE ary)
01650 {
01651 rb_ary_push(ary, obj_resurrect(key));
01652 rb_ary_push(ary, value);
01653 return ST_CONTINUE;
01654 }
01655
01656 static VALUE
01657 iseq_data_to_ary(rb_iseq_t *iseq)
01658 {
01659 long i;
01660 size_t ti;
01661 unsigned int pos;
01662 unsigned int line = 0;
01663 VALUE *seq;
01664
01665 VALUE val = rb_ary_new();
01666 VALUE type;
01667 VALUE locals = rb_ary_new();
01668 VALUE args = rb_ary_new();
01669 VALUE body = rb_ary_new();
01670 VALUE nbody;
01671 VALUE exception = rb_ary_new();
01672 VALUE misc = rb_hash_new();
01673
01674 static VALUE insn_syms[VM_INSTRUCTION_SIZE];
01675 struct st_table *labels_table = st_init_numtable();
01676
01677 DECL_SYMBOL(top);
01678 DECL_SYMBOL(method);
01679 DECL_SYMBOL(block);
01680 DECL_SYMBOL(class);
01681 DECL_SYMBOL(rescue);
01682 DECL_SYMBOL(ensure);
01683 DECL_SYMBOL(eval);
01684 DECL_SYMBOL(main);
01685 DECL_SYMBOL(defined_guard);
01686
01687 if (sym_top == 0) {
01688 int i;
01689 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
01690 insn_syms[i] = ID2SYM(rb_intern(insn_name(i)));
01691 }
01692 INIT_SYMBOL(top);
01693 INIT_SYMBOL(method);
01694 INIT_SYMBOL(block);
01695 INIT_SYMBOL(class);
01696 INIT_SYMBOL(rescue);
01697 INIT_SYMBOL(ensure);
01698 INIT_SYMBOL(eval);
01699 INIT_SYMBOL(main);
01700 INIT_SYMBOL(defined_guard);
01701 }
01702
01703
01704 switch (iseq->type) {
01705 case ISEQ_TYPE_TOP: type = sym_top; break;
01706 case ISEQ_TYPE_METHOD: type = sym_method; break;
01707 case ISEQ_TYPE_BLOCK: type = sym_block; break;
01708 case ISEQ_TYPE_CLASS: type = sym_class; break;
01709 case ISEQ_TYPE_RESCUE: type = sym_rescue; break;
01710 case ISEQ_TYPE_ENSURE: type = sym_ensure; break;
01711 case ISEQ_TYPE_EVAL: type = sym_eval; break;
01712 case ISEQ_TYPE_MAIN: type = sym_main; break;
01713 case ISEQ_TYPE_DEFINED_GUARD: type = sym_defined_guard; break;
01714 default: rb_bug("unsupported iseq type");
01715 };
01716
01717
01718 for (i=0; i<iseq->local_table_size; i++) {
01719 ID lid = iseq->local_table[i];
01720 if (lid) {
01721 if (rb_id2str(lid)) rb_ary_push(locals, ID2SYM(lid));
01722 }
01723 else {
01724 rb_ary_push(locals, ID2SYM(rb_intern("#arg_rest")));
01725 }
01726 }
01727
01728
01729 {
01730
01731
01732
01733
01734
01735
01736
01737
01738
01739
01740 VALUE arg_opt_labels = rb_ary_new();
01741 int j;
01742
01743 for (j=0; j<iseq->arg_opts; j++) {
01744 rb_ary_push(arg_opt_labels,
01745 register_label(labels_table, iseq->arg_opt_table[j]));
01746 }
01747
01748
01749 if (iseq->arg_simple == 1) {
01750 args = INT2FIX(iseq->argc);
01751 }
01752 else {
01753 rb_ary_push(args, INT2FIX(iseq->argc));
01754 rb_ary_push(args, arg_opt_labels);
01755 rb_ary_push(args, INT2FIX(iseq->arg_post_len));
01756 rb_ary_push(args, INT2FIX(iseq->arg_post_start));
01757 rb_ary_push(args, INT2FIX(iseq->arg_rest));
01758 rb_ary_push(args, INT2FIX(iseq->arg_block));
01759 rb_ary_push(args, INT2FIX(iseq->arg_simple));
01760 }
01761 }
01762
01763
01764 for (seq = iseq->iseq; seq < iseq->iseq + iseq->iseq_size; ) {
01765 VALUE insn = *seq++;
01766 int j, len = insn_len(insn);
01767 VALUE *nseq = seq + len - 1;
01768 VALUE ary = rb_ary_new2(len);
01769
01770 rb_ary_push(ary, insn_syms[insn]);
01771 for (j=0; j<len-1; j++, seq++) {
01772 switch (insn_op_type(insn, j)) {
01773 case TS_OFFSET: {
01774 unsigned long idx = nseq - iseq->iseq + *seq;
01775 rb_ary_push(ary, register_label(labels_table, idx));
01776 break;
01777 }
01778 case TS_LINDEX:
01779 case TS_NUM:
01780 rb_ary_push(ary, INT2FIX(*seq));
01781 break;
01782 case TS_VALUE:
01783 rb_ary_push(ary, obj_resurrect(*seq));
01784 break;
01785 case TS_ISEQ:
01786 {
01787 rb_iseq_t *iseq = (rb_iseq_t *)*seq;
01788 if (iseq) {
01789 VALUE val = iseq_data_to_ary(iseq);
01790 rb_ary_push(ary, val);
01791 }
01792 else {
01793 rb_ary_push(ary, Qnil);
01794 }
01795 }
01796 break;
01797 case TS_GENTRY:
01798 {
01799 struct rb_global_entry *entry = (struct rb_global_entry *)*seq;
01800 rb_ary_push(ary, ID2SYM(entry->id));
01801 }
01802 break;
01803 case TS_IC:
01804 {
01805 union iseq_inline_storage_entry *is = (union iseq_inline_storage_entry *)*seq;
01806 rb_ary_push(ary, INT2FIX(is - iseq->is_entries));
01807 }
01808 break;
01809 case TS_CALLINFO:
01810 {
01811 rb_call_info_t *ci = (rb_call_info_t *)*seq;
01812 VALUE e = rb_hash_new();
01813 rb_hash_aset(e, ID2SYM(rb_intern("mid")), ci->mid ? ID2SYM(ci->mid) : Qnil);
01814 rb_hash_aset(e, ID2SYM(rb_intern("flag")), ULONG2NUM(ci->flag));
01815 rb_hash_aset(e, ID2SYM(rb_intern("orig_argc")), INT2FIX(ci->orig_argc));
01816 rb_hash_aset(e, ID2SYM(rb_intern("blockptr")), ci->blockiseq ? iseq_data_to_ary(ci->blockiseq) : Qnil);
01817 rb_ary_push(ary, e);
01818 }
01819 break;
01820 case TS_ID:
01821 rb_ary_push(ary, ID2SYM(*seq));
01822 break;
01823 case TS_CDHASH:
01824 {
01825 VALUE hash = *seq;
01826 VALUE val = rb_ary_new();
01827 int i;
01828
01829 rb_hash_foreach(hash, cdhash_each, val);
01830
01831 for (i=0; i<RARRAY_LEN(val); i+=2) {
01832 VALUE pos = FIX2INT(rb_ary_entry(val, i+1));
01833 unsigned long idx = nseq - iseq->iseq + pos;
01834
01835 rb_ary_store(val, i+1,
01836 register_label(labels_table, idx));
01837 }
01838 rb_ary_push(ary, val);
01839 }
01840 break;
01841 default:
01842 rb_bug("unknown operand: %c", insn_op_type(insn, j));
01843 }
01844 }
01845 rb_ary_push(body, ary);
01846 }
01847
01848 nbody = body;
01849
01850
01851 for (i=0; i<iseq->catch_table_size; i++) {
01852 VALUE ary = rb_ary_new();
01853 struct iseq_catch_table_entry *entry = &iseq->catch_table[i];
01854 rb_ary_push(ary, exception_type2symbol(entry->type));
01855 if (entry->iseq) {
01856 rb_iseq_t *eiseq;
01857 GetISeqPtr(entry->iseq, eiseq);
01858 rb_ary_push(ary, iseq_data_to_ary(eiseq));
01859 }
01860 else {
01861 rb_ary_push(ary, Qnil);
01862 }
01863 rb_ary_push(ary, register_label(labels_table, entry->start));
01864 rb_ary_push(ary, register_label(labels_table, entry->end));
01865 rb_ary_push(ary, register_label(labels_table, entry->cont));
01866 rb_ary_push(ary, INT2FIX(entry->sp));
01867 rb_ary_push(exception, ary);
01868 }
01869
01870
01871 body = rb_ary_new();
01872 ti = 0;
01873
01874 for (i=0, pos=0; i<RARRAY_LEN(nbody); i++) {
01875 VALUE ary = RARRAY_AREF(nbody, i);
01876 st_data_t label;
01877
01878 if (st_lookup(labels_table, pos, &label)) {
01879 rb_ary_push(body, (VALUE)label);
01880 }
01881
01882 if (ti < iseq->line_info_size && iseq->line_info_table[ti].position == pos) {
01883 line = iseq->line_info_table[ti].line_no;
01884 rb_ary_push(body, INT2FIX(line));
01885 ti++;
01886 }
01887
01888 rb_ary_push(body, ary);
01889 pos += RARRAY_LENINT(ary);
01890 }
01891
01892 st_free_table(labels_table);
01893
01894 rb_hash_aset(misc, ID2SYM(rb_intern("arg_size")), INT2FIX(iseq->arg_size));
01895 rb_hash_aset(misc, ID2SYM(rb_intern("local_size")), INT2FIX(iseq->local_size));
01896 rb_hash_aset(misc, ID2SYM(rb_intern("stack_max")), INT2FIX(iseq->stack_max));
01897
01898
01899
01900
01901
01902
01903
01904 rb_ary_push(val, rb_str_new2("YARVInstructionSequence/SimpleDataFormat"));
01905 rb_ary_push(val, INT2FIX(ISEQ_MAJOR_VERSION));
01906 rb_ary_push(val, INT2FIX(ISEQ_MINOR_VERSION));
01907 rb_ary_push(val, INT2FIX(1));
01908 rb_ary_push(val, misc);
01909 rb_ary_push(val, iseq->location.label);
01910 rb_ary_push(val, iseq->location.path);
01911 rb_ary_push(val, iseq->location.absolute_path);
01912 rb_ary_push(val, iseq->location.first_lineno);
01913 rb_ary_push(val, type);
01914 rb_ary_push(val, locals);
01915 rb_ary_push(val, args);
01916 rb_ary_push(val, exception);
01917 rb_ary_push(val, body);
01918 return val;
01919 }
01920
01921 VALUE
01922 rb_iseq_clone(VALUE iseqval, VALUE newcbase)
01923 {
01924 VALUE newiseq = iseq_alloc(rb_cISeq);
01925 rb_iseq_t *iseq0, *iseq1;
01926
01927 GetISeqPtr(iseqval, iseq0);
01928 GetISeqPtr(newiseq, iseq1);
01929
01930 MEMCPY(iseq1, iseq0, rb_iseq_t, 1);
01931
01932 iseq1->self = newiseq;
01933 if (!iseq1->orig) {
01934 RB_OBJ_WRITE(iseq1->self, &iseq1->orig, iseqval);
01935 }
01936 if (iseq0->local_iseq == iseq0) {
01937 iseq1->local_iseq = iseq1;
01938 }
01939 if (newcbase) {
01940 ISEQ_SET_CREF(iseq1, NEW_CREF(newcbase));
01941 RB_OBJ_WRITE(iseq1->cref_stack, &iseq1->cref_stack->nd_refinements, iseq0->cref_stack->nd_refinements);
01942 iseq1->cref_stack->nd_visi = iseq0->cref_stack->nd_visi;
01943 if (iseq0->cref_stack->nd_next) {
01944 RB_OBJ_WRITE(iseq1->cref_stack, &iseq1->cref_stack->nd_next, iseq0->cref_stack->nd_next);
01945 }
01946 RB_OBJ_WRITE(iseq1->self, &iseq1->klass, newcbase);
01947 }
01948
01949 return newiseq;
01950 }
01951
01952 VALUE
01953 rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
01954 {
01955 int i, r;
01956 VALUE a, args = rb_ary_new2(iseq->arg_size);
01957 ID req, opt, rest, block, key, keyrest;
01958 #define PARAM_TYPE(type) rb_ary_push(a = rb_ary_new2(2), ID2SYM(type))
01959 #define PARAM_ID(i) iseq->local_table[(i)]
01960 #define PARAM(i, type) ( \
01961 PARAM_TYPE(type), \
01962 rb_id2str(PARAM_ID(i)) ? \
01963 rb_ary_push(a, ID2SYM(PARAM_ID(i))) : \
01964 a)
01965
01966 CONST_ID(req, "req");
01967 CONST_ID(opt, "opt");
01968 if (is_proc) {
01969 for (i = 0; i < iseq->argc; i++) {
01970 PARAM_TYPE(opt);
01971 rb_ary_push(a, rb_id2str(PARAM_ID(i)) ? ID2SYM(PARAM_ID(i)) : Qnil);
01972 rb_ary_push(args, a);
01973 }
01974 }
01975 else {
01976 for (i = 0; i < iseq->argc; i++) {
01977 rb_ary_push(args, PARAM(i, req));
01978 }
01979 }
01980 r = iseq->argc + iseq->arg_opts - 1;
01981 for (; i < r; i++) {
01982 PARAM_TYPE(opt);
01983 if (rb_id2str(PARAM_ID(i))) {
01984 rb_ary_push(a, ID2SYM(PARAM_ID(i)));
01985 }
01986 rb_ary_push(args, a);
01987 }
01988 if (iseq->arg_rest != -1) {
01989 CONST_ID(rest, "rest");
01990 rb_ary_push(args, PARAM(iseq->arg_rest, rest));
01991 }
01992 r = iseq->arg_post_start + iseq->arg_post_len;
01993 if (is_proc) {
01994 for (i = iseq->arg_post_start; i < r; i++) {
01995 PARAM_TYPE(opt);
01996 rb_ary_push(a, rb_id2str(PARAM_ID(i)) ? ID2SYM(PARAM_ID(i)) : Qnil);
01997 rb_ary_push(args, a);
01998 }
01999 }
02000 else {
02001 for (i = iseq->arg_post_start; i < r; i++) {
02002 rb_ary_push(args, PARAM(i, req));
02003 }
02004 }
02005 if (iseq->arg_keyword != -1) {
02006 i = 0;
02007 if (iseq->arg_keyword_required) {
02008 ID keyreq;
02009 CONST_ID(keyreq, "keyreq");
02010 for (; i < iseq->arg_keyword_required; i++) {
02011 PARAM_TYPE(keyreq);
02012 if (rb_id2str(iseq->arg_keyword_table[i])) {
02013 rb_ary_push(a, ID2SYM(iseq->arg_keyword_table[i]));
02014 }
02015 rb_ary_push(args, a);
02016 }
02017 }
02018 CONST_ID(key, "key");
02019 for (; i < iseq->arg_keywords; i++) {
02020 PARAM_TYPE(key);
02021 if (rb_id2str(iseq->arg_keyword_table[i])) {
02022 rb_ary_push(a, ID2SYM(iseq->arg_keyword_table[i]));
02023 }
02024 rb_ary_push(args, a);
02025 }
02026 if (!iseq->arg_keyword_check) {
02027 CONST_ID(keyrest, "keyrest");
02028 rb_ary_push(args, PARAM(iseq->arg_keyword, keyrest));
02029 }
02030 }
02031 if (iseq->arg_block != -1) {
02032 CONST_ID(block, "block");
02033 rb_ary_push(args, PARAM(iseq->arg_block, block));
02034 }
02035 return args;
02036 }
02037
02038 VALUE
02039 rb_iseq_defined_string(enum defined_type type)
02040 {
02041 static const char expr_names[][18] = {
02042 "nil",
02043 "instance-variable",
02044 "local-variable",
02045 "global-variable",
02046 "class variable",
02047 "constant",
02048 "method",
02049 "yield",
02050 "super",
02051 "self",
02052 "true",
02053 "false",
02054 "assignment",
02055 "expression",
02056 };
02057 const char *estr;
02058 VALUE *defs, str;
02059
02060 if ((unsigned)(type - 1) >= (unsigned)numberof(expr_names)) return 0;
02061 estr = expr_names[type - 1];
02062 if (!estr[0]) return 0;
02063 defs = GET_VM()->defined_strings;
02064 if (!defs) {
02065 defs = ruby_xcalloc(numberof(expr_names), sizeof(VALUE));
02066 GET_VM()->defined_strings = defs;
02067 }
02068 str = defs[type-1];
02069 if (!str) {
02070 str = rb_str_new_cstr(estr);;
02071 OBJ_FREEZE(str);
02072 defs[type-1] = str;
02073 }
02074 return str;
02075 }
02076
02077
02078
02079 VALUE
02080 rb_iseq_build_for_ruby2cext(
02081 const rb_iseq_t *iseq_template,
02082 const rb_insn_func_t *func,
02083 const struct iseq_line_info_entry *line_info_table,
02084 const char **local_table,
02085 const VALUE *arg_opt_table,
02086 const struct iseq_catch_table_entry *catch_table,
02087 const char *name,
02088 const char *path,
02089 const unsigned short first_lineno)
02090 {
02091 unsigned long i;
02092 VALUE iseqval = iseq_alloc(rb_cISeq);
02093 rb_iseq_t *iseq;
02094 GetISeqPtr(iseqval, iseq);
02095
02096
02097 MEMCPY(iseq, iseq_template, rb_iseq_t, 1);
02098 RB_OBJ_WRITE(iseq->self, &iseq->location.label, rb_str_new2(name));
02099 RB_OBJ_WRITE(iseq->self, &iseq->location.path, rb_str_new2(path));
02100 iseq->location.first_lineno = first_lineno;
02101 RB_OBJ_WRITE(iseq->self, &iseq->mark_ary, 0);
02102 iseq->self = iseqval;
02103
02104 iseq->iseq = ALLOC_N(VALUE, iseq->iseq_size);
02105
02106 for (i=0; i<iseq->iseq_size; i+=2) {
02107 iseq->iseq[i] = BIN(opt_call_c_function);
02108 iseq->iseq[i+1] = (VALUE)func;
02109 }
02110
02111 rb_iseq_translate_threaded_code(iseq);
02112
02113 #define ALLOC_AND_COPY(dst, src, type, size) do { \
02114 if (size) { \
02115 (dst) = ALLOC_N(type, (size)); \
02116 MEMCPY((dst), (src), type, (size)); \
02117 } \
02118 } while (0)
02119
02120 ALLOC_AND_COPY(iseq->line_info_table, line_info_table,
02121 struct iseq_line_info_entry, iseq->line_info_size);
02122
02123 ALLOC_AND_COPY(iseq->catch_table, catch_table,
02124 struct iseq_catch_table_entry, iseq->catch_table_size);
02125
02126 ALLOC_AND_COPY(iseq->arg_opt_table, arg_opt_table,
02127 VALUE, iseq->arg_opts);
02128
02129 set_relation(iseq, 0);
02130
02131 return iseqval;
02132 }
02133
02134
02135
02136
02137
02138 int
02139 rb_iseq_line_trace_each(VALUE iseqval, int (*func)(int line, rb_event_flag_t *events_ptr, void *d), void *data)
02140 {
02141 int trace_num = 0;
02142 size_t pos, insn;
02143 rb_iseq_t *iseq;
02144 int cont = 1;
02145 GetISeqPtr(iseqval, iseq);
02146
02147 for (pos = 0; cont && pos < iseq->iseq_size; pos += insn_len(insn)) {
02148 insn = iseq->iseq[pos];
02149
02150 if (insn == BIN(trace)) {
02151 rb_event_flag_t current_events = (VALUE)iseq->iseq[pos+1];
02152
02153 if (current_events & RUBY_EVENT_LINE) {
02154 rb_event_flag_t events = current_events & RUBY_EVENT_SPECIFIED_LINE;
02155 trace_num++;
02156
02157 if (func) {
02158 int line = find_line_no(iseq, pos);
02159
02160 cont = (*func)(line, &events, data);
02161 if (current_events != events) {
02162 iseq->iseq[pos+1] = iseq->iseq_encoded[pos+1] =
02163 (VALUE)(current_events | (events & RUBY_EVENT_SPECIFIED_LINE));
02164 }
02165 }
02166 }
02167 }
02168 }
02169 return trace_num;
02170 }
02171
02172 static int
02173 collect_trace(int line, rb_event_flag_t *events_ptr, void *ptr)
02174 {
02175 VALUE result = (VALUE)ptr;
02176 rb_ary_push(result, INT2NUM(line));
02177 return 1;
02178 }
02179
02180
02181
02182
02183
02184
02185 VALUE
02186 rb_iseq_line_trace_all(VALUE iseqval)
02187 {
02188 VALUE result = rb_ary_new();
02189 rb_iseq_line_trace_each(iseqval, collect_trace, (void *)result);
02190 return result;
02191 }
02192
02193 struct set_specifc_data {
02194 int pos;
02195 int set;
02196 int prev;
02197 };
02198
02199 static int
02200 line_trace_specify(int line, rb_event_flag_t *events_ptr, void *ptr)
02201 {
02202 struct set_specifc_data *data = (struct set_specifc_data *)ptr;
02203
02204 if (data->pos == 0) {
02205 data->prev = *events_ptr & RUBY_EVENT_SPECIFIED_LINE ? 1 : 2;
02206 if (data->set) {
02207 *events_ptr = *events_ptr | RUBY_EVENT_SPECIFIED_LINE;
02208 }
02209 else {
02210 *events_ptr = *events_ptr & ~RUBY_EVENT_SPECIFIED_LINE;
02211 }
02212 return 0;
02213 }
02214 else {
02215 data->pos--;
02216 return 1;
02217 }
02218 }
02219
02220
02221
02222
02223
02224
02225
02226
02227
02228
02229
02230
02231
02232 VALUE
02233 rb_iseq_line_trace_specify(VALUE iseqval, VALUE pos, VALUE set)
02234 {
02235 struct set_specifc_data data;
02236
02237 data.prev = 0;
02238 data.pos = NUM2INT(pos);
02239 if (data.pos < 0) rb_raise(rb_eTypeError, "`pos' is negative");
02240
02241 switch (set) {
02242 case Qtrue: data.set = 1; break;
02243 case Qfalse: data.set = 0; break;
02244 default:
02245 rb_raise(rb_eTypeError, "`set' should be true/false");
02246 }
02247
02248 rb_iseq_line_trace_each(iseqval, line_trace_specify, (void *)&data);
02249
02250 if (data.prev == 0) {
02251 rb_raise(rb_eTypeError, "`pos' is out of range.");
02252 }
02253 return data.prev == 1 ? Qtrue : Qfalse;
02254 }
02255
02256
02257
02258
02259
02260
02261
02262
02263
02264
02265
02266
02267
02268
02269
02270
02271
02272
02273
02274
02275
02276 void
02277 Init_ISeq(void)
02278 {
02279
02280 rb_cISeq = rb_define_class_under(rb_cRubyVM, "InstructionSequence", rb_cObject);
02281 rb_define_alloc_func(rb_cISeq, iseq_alloc);
02282 rb_define_method(rb_cISeq, "inspect", iseq_inspect, 0);
02283 rb_define_method(rb_cISeq, "disasm", rb_iseq_disasm, 0);
02284 rb_define_method(rb_cISeq, "disassemble", rb_iseq_disasm, 0);
02285 rb_define_method(rb_cISeq, "to_a", iseq_to_a, 0);
02286 rb_define_method(rb_cISeq, "eval", iseq_eval, 0);
02287
02288
02289 rb_define_method(rb_cISeq, "path", rb_iseq_path, 0);
02290 rb_define_method(rb_cISeq, "absolute_path", rb_iseq_absolute_path, 0);
02291 rb_define_method(rb_cISeq, "label", rb_iseq_label, 0);
02292 rb_define_method(rb_cISeq, "base_label", rb_iseq_base_label, 0);
02293 rb_define_method(rb_cISeq, "first_lineno", rb_iseq_first_lineno, 0);
02294
02295 #if 0
02296
02297
02298 rb_define_method(rb_cISeq, "line_trace_all", rb_iseq_line_trace_all, 0);
02299 rb_define_method(rb_cISeq, "line_trace_specify", rb_iseq_line_trace_specify, 2);
02300 #else
02301 (void)rb_iseq_line_trace_all;
02302 (void)rb_iseq_line_trace_specify;
02303 #endif
02304
02305 #if 0
02306 rb_define_private_method(rb_cISeq, "marshal_dump", iseq_marshal_dump, 0);
02307 rb_define_private_method(rb_cISeq, "marshal_load", iseq_marshal_load, 1);
02308 #endif
02309
02310
02311
02312 (void)iseq_s_load;
02313
02314 rb_define_singleton_method(rb_cISeq, "compile", iseq_s_compile, -1);
02315 rb_define_singleton_method(rb_cISeq, "new", iseq_s_compile, -1);
02316 rb_define_singleton_method(rb_cISeq, "compile_file", iseq_s_compile_file, -1);
02317 rb_define_singleton_method(rb_cISeq, "compile_option", iseq_s_compile_option_get, 0);
02318 rb_define_singleton_method(rb_cISeq, "compile_option=", iseq_s_compile_option_set, 1);
02319 rb_define_singleton_method(rb_cISeq, "disasm", iseq_s_disasm, 1);
02320 rb_define_singleton_method(rb_cISeq, "disassemble", iseq_s_disasm, 1);
02321 rb_define_singleton_method(rb_cISeq, "of", iseq_s_of, 1);
02322 }
02323