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 StringValue(src);
00614 node = rb_parser_compile_string_path(parser, file, src, ln);
00615
00616 if (!node) {
00617 rb_exc_raise(GET_THREAD()->errinfo);
00618 }
00619 }
00620
00621 if (base_block && base_block->iseq) {
00622 iseqval = rb_iseq_new_with_opt(node, base_block->iseq->location.label,
00623 file, absolute_path, line, base_block->iseq->self,
00624 ISEQ_TYPE_EVAL, &option);
00625 }
00626 else {
00627 iseqval = rb_iseq_new_with_opt(node, rb_str_new2("<compiled>"), file, absolute_path, line, Qfalse,
00628 ISEQ_TYPE_TOP, &option);
00629 }
00630 }
00631 TH_POP_TAG();
00632
00633 th->base_block = prev_base_block;
00634
00635 if (state) {
00636 JUMP_TAG(state);
00637 }
00638
00639 return iseqval;
00640 }
00641
00642 VALUE
00643 rb_iseq_compile(VALUE src, VALUE file, VALUE line)
00644 {
00645 return rb_iseq_compile_with_option(src, file, Qnil, line, 0, Qnil);
00646 }
00647
00648 VALUE
00649 rb_iseq_compile_on_base(VALUE src, VALUE file, VALUE line, rb_block_t *base_block)
00650 {
00651 return rb_iseq_compile_with_option(src, file, Qnil, line, base_block, Qnil);
00652 }
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675 static VALUE
00676 iseq_s_compile(int argc, VALUE *argv, VALUE self)
00677 {
00678 VALUE src, file = Qnil, path = Qnil, line = INT2FIX(1), opt = Qnil;
00679
00680 rb_secure(1);
00681
00682 rb_scan_args(argc, argv, "14", &src, &file, &path, &line, &opt);
00683 if (NIL_P(file)) file = rb_str_new2("<compiled>");
00684 if (NIL_P(line)) line = INT2FIX(1);
00685
00686 return rb_iseq_compile_with_option(src, file, path, line, 0, opt);
00687 }
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709 static VALUE
00710 iseq_s_compile_file(int argc, VALUE *argv, VALUE self)
00711 {
00712 VALUE file, line = INT2FIX(1), opt = Qnil;
00713 VALUE parser;
00714 VALUE f;
00715 NODE *node;
00716 const char *fname;
00717 rb_compile_option_t option;
00718
00719 rb_secure(1);
00720 rb_scan_args(argc, argv, "11", &file, &opt);
00721 FilePathValue(file);
00722 fname = StringValueCStr(file);
00723
00724 f = rb_file_open_str(file, "r");
00725
00726 parser = rb_parser_new();
00727 node = rb_parser_compile_file(parser, fname, f, NUM2INT(line));
00728 make_compile_option(&option, opt);
00729 return rb_iseq_new_with_opt(node, rb_str_new2("<main>"), file,
00730 rb_realpath_internal(Qnil, file, 1), line, Qfalse,
00731 ISEQ_TYPE_TOP, &option);
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
00766 static VALUE
00767 iseq_s_compile_option_set(VALUE self, VALUE opt)
00768 {
00769 rb_compile_option_t option;
00770 rb_secure(1);
00771 make_compile_option(&option, opt);
00772 COMPILE_OPTION_DEFAULT = option;
00773 return opt;
00774 }
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784 static VALUE
00785 iseq_s_compile_option_get(VALUE self)
00786 {
00787 return make_compile_option_value(&COMPILE_OPTION_DEFAULT);
00788 }
00789
00790 static rb_iseq_t *
00791 iseq_check(VALUE val)
00792 {
00793 rb_iseq_t *iseq;
00794 GetISeqPtr(val, iseq);
00795 if (!iseq->location.label) {
00796 rb_raise(rb_eTypeError, "uninitialized InstructionSequence");
00797 }
00798 return iseq;
00799 }
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809 static VALUE
00810 iseq_eval(VALUE self)
00811 {
00812 rb_secure(1);
00813 return rb_iseq_eval(self);
00814 }
00815
00816
00817
00818
00819
00820 static VALUE
00821 iseq_inspect(VALUE self)
00822 {
00823 rb_iseq_t *iseq;
00824 GetISeqPtr(self, iseq);
00825 if (!iseq->location.label) {
00826 return rb_sprintf("#<%s: uninitialized>", rb_obj_classname(self));
00827 }
00828
00829 return rb_sprintf("<%s:%s@%s>",
00830 rb_obj_classname(self),
00831 RSTRING_PTR(iseq->location.label), RSTRING_PTR(iseq->location.path));
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
00857 VALUE
00858 rb_iseq_path(VALUE self)
00859 {
00860 rb_iseq_t *iseq;
00861 GetISeqPtr(self, iseq);
00862 return iseq->location.path;
00863 }
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881 VALUE
00882 rb_iseq_absolute_path(VALUE self)
00883 {
00884 rb_iseq_t *iseq;
00885 GetISeqPtr(self, iseq);
00886 return iseq->location.absolute_path;
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
00912 VALUE
00913 rb_iseq_label(VALUE self)
00914 {
00915 rb_iseq_t *iseq;
00916 GetISeqPtr(self, iseq);
00917 return iseq->location.label;
00918 }
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940 VALUE
00941 rb_iseq_base_label(VALUE self)
00942 {
00943 rb_iseq_t *iseq;
00944 GetISeqPtr(self, iseq);
00945 return iseq->location.base_label;
00946 }
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958 VALUE
00959 rb_iseq_first_lineno(VALUE self)
00960 {
00961 rb_iseq_t *iseq;
00962 GetISeqPtr(self, iseq);
00963 return iseq->location.first_lineno;
00964 }
00965
00966 VALUE
00967 rb_iseq_klass(VALUE self)
00968 {
00969 rb_iseq_t *iseq;
00970 GetISeqPtr(self, iseq);
00971 return iseq->local_iseq->klass;
00972 }
00973
00974 VALUE
00975 rb_iseq_method_name(VALUE self)
00976 {
00977 rb_iseq_t *iseq, *local_iseq;
00978 GetISeqPtr(self, iseq);
00979 local_iseq = iseq->local_iseq;
00980 if (local_iseq->type == ISEQ_TYPE_METHOD) {
00981 return local_iseq->location.base_label;
00982 }
00983 else {
00984 return Qnil;
00985 }
00986 }
00987
00988 static
00989 VALUE iseq_data_to_ary(rb_iseq_t *iseq);
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
01076 static VALUE
01077 iseq_to_a(VALUE self)
01078 {
01079 rb_iseq_t *iseq = iseq_check(self);
01080 rb_secure(1);
01081 return iseq_data_to_ary(iseq);
01082 }
01083
01084
01085
01086
01087 static struct iseq_line_info_entry *
01088 get_line_info(const rb_iseq_t *iseq, size_t pos)
01089 {
01090 size_t i = 0, size = iseq->line_info_size;
01091 struct iseq_line_info_entry *table = iseq->line_info_table;
01092 const int debug = 0;
01093
01094 if (debug) {
01095 printf("size: %"PRIdSIZE"\n", size);
01096 printf("table[%"PRIdSIZE"]: position: %d, line: %d, pos: %"PRIdSIZE"\n",
01097 i, table[i].position, table[i].line_no, pos);
01098 }
01099
01100 if (size == 0) {
01101 return 0;
01102 }
01103 else if (size == 1) {
01104 return &table[0];
01105 }
01106 else {
01107 for (i=1; i<size; i++) {
01108 if (debug) printf("table[%"PRIdSIZE"]: position: %d, line: %d, pos: %"PRIdSIZE"\n",
01109 i, table[i].position, table[i].line_no, pos);
01110
01111 if (table[i].position == pos) {
01112 return &table[i];
01113 }
01114 if (table[i].position > pos) {
01115 return &table[i-1];
01116 }
01117 }
01118 }
01119 return &table[i-1];
01120 }
01121
01122 static unsigned int
01123 find_line_no(const rb_iseq_t *iseq, size_t pos)
01124 {
01125 struct iseq_line_info_entry *entry = get_line_info(iseq, pos);
01126 if (entry) {
01127 return entry->line_no;
01128 }
01129 else {
01130 return 0;
01131 }
01132 }
01133
01134 unsigned int
01135 rb_iseq_line_no(const rb_iseq_t *iseq, size_t pos)
01136 {
01137 if (pos == 0) {
01138 return find_line_no(iseq, pos);
01139 }
01140 else {
01141 return find_line_no(iseq, pos - 1);
01142 }
01143 }
01144
01145 static VALUE
01146 id_to_name(ID id, VALUE default_value)
01147 {
01148 VALUE str = rb_id2str(id);
01149 if (!str) {
01150 str = default_value;
01151 }
01152 else if (!rb_str_symname_p(str)) {
01153 str = rb_str_inspect(str);
01154 }
01155 return str;
01156 }
01157
01158 VALUE
01159 rb_insn_operand_intern(rb_iseq_t *iseq,
01160 VALUE insn, int op_no, VALUE op,
01161 int len, size_t pos, VALUE *pnop, VALUE child)
01162 {
01163 const char *types = insn_op_types(insn);
01164 char type = types[op_no];
01165 VALUE ret;
01166
01167 switch (type) {
01168 case TS_OFFSET:
01169 ret = rb_sprintf("%"PRIdVALUE, (VALUE)(pos + len + op));
01170 break;
01171
01172 case TS_NUM:
01173 ret = rb_sprintf("%"PRIuVALUE, op);
01174 break;
01175
01176 case TS_LINDEX:{
01177 if (insn == BIN(getlocal) || insn == BIN(setlocal)) {
01178 if (pnop) {
01179 rb_iseq_t *diseq = iseq;
01180 VALUE level = *pnop, i;
01181
01182 for (i = 0; i < level; i++) {
01183 diseq = diseq->parent_iseq;
01184 }
01185 ret = id_to_name(diseq->local_table[diseq->local_size - op], INT2FIX('*'));
01186 }
01187 else {
01188 ret = rb_sprintf("%"PRIuVALUE, op);
01189 }
01190 }
01191 else {
01192 ret = rb_inspect(INT2FIX(op));
01193 }
01194 break;
01195 }
01196 case TS_ID:
01197 op = ID2SYM(op);
01198
01199 case TS_VALUE:
01200 op = obj_resurrect(op);
01201 ret = rb_inspect(op);
01202 if (CLASS_OF(op) == rb_cISeq) {
01203 if (child) {
01204 rb_ary_push(child, op);
01205 }
01206 }
01207 break;
01208
01209 case TS_ISEQ:
01210 {
01211 rb_iseq_t *iseq = (rb_iseq_t *)op;
01212 if (iseq) {
01213 ret = iseq->location.label;
01214 if (child) {
01215 rb_ary_push(child, iseq->self);
01216 }
01217 }
01218 else {
01219 ret = rb_str_new2("nil");
01220 }
01221 break;
01222 }
01223 case TS_GENTRY:
01224 {
01225 struct rb_global_entry *entry = (struct rb_global_entry *)op;
01226 ret = rb_str_dup(rb_id2str(entry->id));
01227 }
01228 break;
01229
01230 case TS_IC:
01231 ret = rb_sprintf("<is:%"PRIdPTRDIFF">", (union iseq_inline_storage_entry *)op - iseq->is_entries);
01232 break;
01233
01234 case TS_CALLINFO:
01235 {
01236 rb_call_info_t *ci = (rb_call_info_t *)op;
01237 VALUE ary = rb_ary_new();
01238
01239 if (ci->mid) {
01240 rb_ary_push(ary, rb_sprintf("mid:%s", rb_id2name(ci->mid)));
01241 }
01242
01243 rb_ary_push(ary, rb_sprintf("argc:%d", ci->orig_argc));
01244
01245 if (ci->blockiseq) {
01246 if (child) {
01247 rb_ary_push(child, ci->blockiseq->self);
01248 }
01249 rb_ary_push(ary, rb_sprintf("block:%"PRIsVALUE, ci->blockiseq->location.label));
01250 }
01251
01252 if (ci->flag) {
01253 VALUE flags = rb_ary_new();
01254 if (ci->flag & VM_CALL_ARGS_SPLAT) rb_ary_push(flags, rb_str_new2("ARGS_SPLAT"));
01255 if (ci->flag & VM_CALL_ARGS_BLOCKARG) rb_ary_push(flags, rb_str_new2("ARGS_BLOCKARG"));
01256 if (ci->flag & VM_CALL_FCALL) rb_ary_push(flags, rb_str_new2("FCALL"));
01257 if (ci->flag & VM_CALL_VCALL) rb_ary_push(flags, rb_str_new2("VCALL"));
01258 if (ci->flag & VM_CALL_TAILCALL) rb_ary_push(flags, rb_str_new2("TAILCALL"));
01259 if (ci->flag & VM_CALL_SUPER) rb_ary_push(flags, rb_str_new2("SUPER"));
01260 if (ci->flag & VM_CALL_OPT_SEND) rb_ary_push(flags, rb_str_new2("SNED"));
01261 if (ci->flag & VM_CALL_ARGS_SKIP_SETUP) rb_ary_push(flags, rb_str_new2("ARGS_SKIP"));
01262 rb_ary_push(ary, rb_ary_join(flags, rb_str_new2("|")));
01263 }
01264 ret = rb_sprintf("<callinfo!%"PRIsVALUE">", rb_ary_join(ary, rb_str_new2(", ")));
01265 }
01266 break;
01267
01268 case TS_CDHASH:
01269 ret = rb_str_new2("<cdhash>");
01270 break;
01271
01272 case TS_FUNCPTR:
01273 ret = rb_str_new2("<funcptr>");
01274 break;
01275
01276 default:
01277 rb_bug("insn_operand_intern: unknown operand type: %c", type);
01278 }
01279 return ret;
01280 }
01281
01286 int
01287 rb_iseq_disasm_insn(VALUE ret, VALUE *iseq, size_t pos,
01288 rb_iseq_t *iseqdat, VALUE child)
01289 {
01290 VALUE insn = iseq[pos];
01291 int len = insn_len(insn);
01292 int j;
01293 const char *types = insn_op_types(insn);
01294 VALUE str = rb_str_new(0, 0);
01295 const char *insn_name_buff;
01296
01297 insn_name_buff = insn_name(insn);
01298 if (1) {
01299 rb_str_catf(str, "%04"PRIdSIZE" %-16s ", pos, insn_name_buff);
01300 }
01301 else {
01302 rb_str_catf(str, "%04"PRIdSIZE" %-16.*s ", pos,
01303 (int)strcspn(insn_name_buff, "_"), insn_name_buff);
01304 }
01305
01306 for (j = 0; types[j]; j++) {
01307 const char *types = insn_op_types(insn);
01308 VALUE opstr = rb_insn_operand_intern(iseqdat, insn, j, iseq[pos + j + 1],
01309 len, pos, &iseq[pos + j + 2],
01310 child);
01311 rb_str_concat(str, opstr);
01312
01313 if (types[j + 1]) {
01314 rb_str_cat2(str, ", ");
01315 }
01316 }
01317
01318 {
01319 unsigned int line_no = find_line_no(iseqdat, pos);
01320 unsigned int prev = pos == 0 ? 0 : find_line_no(iseqdat, pos - 1);
01321 if (line_no && line_no != prev) {
01322 long slen = RSTRING_LEN(str);
01323 slen = (slen > 70) ? 0 : (70 - slen);
01324 str = rb_str_catf(str, "%*s(%4d)", (int)slen, "", line_no);
01325 }
01326 }
01327
01328 if (ret) {
01329 rb_str_cat2(str, "\n");
01330 rb_str_concat(ret, str);
01331 }
01332 else {
01333 printf("%s\n", RSTRING_PTR(str));
01334 }
01335 return len;
01336 }
01337
01338 static const char *
01339 catch_type(int type)
01340 {
01341 switch (type) {
01342 case CATCH_TYPE_RESCUE:
01343 return "rescue";
01344 case CATCH_TYPE_ENSURE:
01345 return "ensure";
01346 case CATCH_TYPE_RETRY:
01347 return "retry";
01348 case CATCH_TYPE_BREAK:
01349 return "break";
01350 case CATCH_TYPE_REDO:
01351 return "redo";
01352 case CATCH_TYPE_NEXT:
01353 return "next";
01354 default:
01355 rb_bug("unknown catch type (%d)", type);
01356 return 0;
01357 }
01358 }
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378 VALUE
01379 rb_iseq_disasm(VALUE self)
01380 {
01381 rb_iseq_t *iseqdat = iseq_check(self);
01382 VALUE *iseq;
01383 VALUE str = rb_str_new(0, 0);
01384 VALUE child = rb_ary_new();
01385 unsigned long size;
01386 int i;
01387 long l;
01388 ID *tbl;
01389 size_t n;
01390 enum {header_minlen = 72};
01391
01392 rb_secure(1);
01393
01394 iseq = iseqdat->iseq;
01395 size = iseqdat->iseq_size;
01396
01397 rb_str_cat2(str, "== disasm: ");
01398
01399 rb_str_concat(str, iseq_inspect(iseqdat->self));
01400 if ((l = RSTRING_LEN(str)) < header_minlen) {
01401 rb_str_resize(str, header_minlen);
01402 memset(RSTRING_PTR(str) + l, '=', header_minlen - l);
01403 }
01404 rb_str_cat2(str, "\n");
01405
01406
01407 if (iseqdat->catch_table_size != 0) {
01408 rb_str_cat2(str, "== catch table\n");
01409 }
01410 for (i = 0; i < iseqdat->catch_table_size; i++) {
01411 struct iseq_catch_table_entry *entry = &iseqdat->catch_table[i];
01412 rb_str_catf(str,
01413 "| catch type: %-6s st: %04d ed: %04d sp: %04d cont: %04d\n",
01414 catch_type((int)entry->type), (int)entry->start,
01415 (int)entry->end, (int)entry->sp, (int)entry->cont);
01416 if (entry->iseq) {
01417 rb_str_concat(str, rb_iseq_disasm(entry->iseq));
01418 }
01419 }
01420 if (iseqdat->catch_table_size != 0) {
01421 rb_str_cat2(str, "|-------------------------------------"
01422 "-----------------------------------\n");
01423 }
01424
01425
01426 tbl = iseqdat->local_table;
01427
01428 if (tbl) {
01429 rb_str_catf(str,
01430 "local table (size: %d, argc: %d "
01431 "[opts: %d, rest: %d, post: %d, block: %d, keyword: %d@%d] s%d)\n",
01432 iseqdat->local_size, iseqdat->argc,
01433 iseqdat->arg_opts, iseqdat->arg_rest,
01434 iseqdat->arg_post_len, iseqdat->arg_block,
01435 iseqdat->arg_keywords, iseqdat->local_size-iseqdat->arg_keyword,
01436 iseqdat->arg_simple);
01437
01438 for (i = 0; i < iseqdat->local_table_size; i++) {
01439 long width;
01440 VALUE name = id_to_name(tbl[i], 0);
01441 char argi[0x100] = "";
01442 char opti[0x100] = "";
01443
01444 if (iseqdat->arg_opts) {
01445 int argc = iseqdat->argc;
01446 int opts = iseqdat->arg_opts;
01447 if (i >= argc && i < argc + opts - 1) {
01448 snprintf(opti, sizeof(opti), "Opt=%"PRIdVALUE,
01449 iseqdat->arg_opt_table[i - argc]);
01450 }
01451 }
01452
01453 snprintf(argi, sizeof(argi), "%s%s%s%s%s",
01454 iseqdat->argc > i ? "Arg" : "",
01455 opti,
01456 iseqdat->arg_rest == i ? "Rest" : "",
01457 (iseqdat->arg_post_start <= i &&
01458 i < iseqdat->arg_post_start + iseqdat->arg_post_len) ? "Post" : "",
01459 iseqdat->arg_block == i ? "Block" : "");
01460
01461 rb_str_catf(str, "[%2d] ", iseqdat->local_size - i);
01462 width = RSTRING_LEN(str) + 11;
01463 if (name)
01464 rb_str_append(str, name);
01465 else
01466 rb_str_cat2(str, "?");
01467 if (*argi) rb_str_catf(str, "<%s>", argi);
01468 if ((width -= RSTRING_LEN(str)) > 0) rb_str_catf(str, "%*s", (int)width, "");
01469 }
01470 rb_str_cat2(str, "\n");
01471 }
01472
01473
01474 for (n = 0; n < size;) {
01475 n += rb_iseq_disasm_insn(str, iseq, n, iseqdat, child);
01476 }
01477
01478 for (i = 0; i < RARRAY_LEN(child); i++) {
01479 VALUE isv = rb_ary_entry(child, i);
01480 rb_str_concat(str, rb_iseq_disasm(isv));
01481 }
01482
01483 return str;
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
01521 static VALUE
01522 iseq_s_of(VALUE klass, VALUE body)
01523 {
01524 VALUE ret = Qnil;
01525 rb_iseq_t *iseq;
01526
01527 rb_secure(1);
01528
01529 if (rb_obj_is_proc(body)) {
01530 rb_proc_t *proc;
01531 GetProcPtr(body, proc);
01532 iseq = proc->block.iseq;
01533 if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
01534 ret = iseq->self;
01535 }
01536 }
01537 else if ((iseq = rb_method_get_iseq(body)) != 0) {
01538 ret = iseq->self;
01539 }
01540 return ret;
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
01596 static VALUE
01597 iseq_s_disasm(VALUE klass, VALUE body)
01598 {
01599 VALUE iseqval = iseq_s_of(klass, body);
01600 return NIL_P(iseqval) ? Qnil : rb_iseq_disasm(iseqval);
01601 }
01602
01603 const char *
01604 ruby_node_name(int node)
01605 {
01606 switch (node) {
01607 #include "node_name.inc"
01608 default:
01609 rb_bug("unknown node (%d)", node);
01610 return 0;
01611 }
01612 }
01613
01614 #define DECL_SYMBOL(name) \
01615 static VALUE sym_##name
01616
01617 #define INIT_SYMBOL(name) \
01618 sym_##name = ID2SYM(rb_intern(#name))
01619
01620 static VALUE
01621 register_label(struct st_table *table, unsigned long idx)
01622 {
01623 VALUE sym;
01624 char buff[8 + (sizeof(idx) * CHAR_BIT * 32 / 100)];
01625
01626 snprintf(buff, sizeof(buff), "label_%lu", idx);
01627 sym = ID2SYM(rb_intern(buff));
01628 st_insert(table, idx, sym);
01629 return sym;
01630 }
01631
01632 static VALUE
01633 exception_type2symbol(VALUE type)
01634 {
01635 ID id;
01636 switch (type) {
01637 case CATCH_TYPE_RESCUE: CONST_ID(id, "rescue"); break;
01638 case CATCH_TYPE_ENSURE: CONST_ID(id, "ensure"); break;
01639 case CATCH_TYPE_RETRY: CONST_ID(id, "retry"); break;
01640 case CATCH_TYPE_BREAK: CONST_ID(id, "break"); break;
01641 case CATCH_TYPE_REDO: CONST_ID(id, "redo"); break;
01642 case CATCH_TYPE_NEXT: CONST_ID(id, "next"); break;
01643 default:
01644 rb_bug("...");
01645 }
01646 return ID2SYM(id);
01647 }
01648
01649 static int
01650 cdhash_each(VALUE key, VALUE value, VALUE ary)
01651 {
01652 rb_ary_push(ary, obj_resurrect(key));
01653 rb_ary_push(ary, value);
01654 return ST_CONTINUE;
01655 }
01656
01657 static VALUE
01658 iseq_data_to_ary(rb_iseq_t *iseq)
01659 {
01660 long i;
01661 size_t ti;
01662 unsigned int pos;
01663 unsigned int line = 0;
01664 VALUE *seq;
01665
01666 VALUE val = rb_ary_new();
01667 VALUE type;
01668 VALUE locals = rb_ary_new();
01669 VALUE args = rb_ary_new();
01670 VALUE body = rb_ary_new();
01671 VALUE nbody;
01672 VALUE exception = rb_ary_new();
01673 VALUE misc = rb_hash_new();
01674
01675 static VALUE insn_syms[VM_INSTRUCTION_SIZE];
01676 struct st_table *labels_table = st_init_numtable();
01677
01678 DECL_SYMBOL(top);
01679 DECL_SYMBOL(method);
01680 DECL_SYMBOL(block);
01681 DECL_SYMBOL(class);
01682 DECL_SYMBOL(rescue);
01683 DECL_SYMBOL(ensure);
01684 DECL_SYMBOL(eval);
01685 DECL_SYMBOL(main);
01686 DECL_SYMBOL(defined_guard);
01687
01688 if (sym_top == 0) {
01689 int i;
01690 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
01691 insn_syms[i] = ID2SYM(rb_intern(insn_name(i)));
01692 }
01693 INIT_SYMBOL(top);
01694 INIT_SYMBOL(method);
01695 INIT_SYMBOL(block);
01696 INIT_SYMBOL(class);
01697 INIT_SYMBOL(rescue);
01698 INIT_SYMBOL(ensure);
01699 INIT_SYMBOL(eval);
01700 INIT_SYMBOL(main);
01701 INIT_SYMBOL(defined_guard);
01702 }
01703
01704
01705 switch (iseq->type) {
01706 case ISEQ_TYPE_TOP: type = sym_top; break;
01707 case ISEQ_TYPE_METHOD: type = sym_method; break;
01708 case ISEQ_TYPE_BLOCK: type = sym_block; break;
01709 case ISEQ_TYPE_CLASS: type = sym_class; break;
01710 case ISEQ_TYPE_RESCUE: type = sym_rescue; break;
01711 case ISEQ_TYPE_ENSURE: type = sym_ensure; break;
01712 case ISEQ_TYPE_EVAL: type = sym_eval; break;
01713 case ISEQ_TYPE_MAIN: type = sym_main; break;
01714 case ISEQ_TYPE_DEFINED_GUARD: type = sym_defined_guard; break;
01715 default: rb_bug("unsupported iseq type");
01716 };
01717
01718
01719 for (i=0; i<iseq->local_table_size; i++) {
01720 ID lid = iseq->local_table[i];
01721 if (lid) {
01722 if (rb_id2str(lid)) rb_ary_push(locals, ID2SYM(lid));
01723 }
01724 else {
01725 rb_ary_push(locals, ID2SYM(rb_intern("#arg_rest")));
01726 }
01727 }
01728
01729
01730 {
01731
01732
01733
01734
01735
01736
01737
01738
01739
01740
01741 VALUE arg_opt_labels = rb_ary_new();
01742 int j;
01743
01744 for (j=0; j<iseq->arg_opts; j++) {
01745 rb_ary_push(arg_opt_labels,
01746 register_label(labels_table, iseq->arg_opt_table[j]));
01747 }
01748
01749
01750 if (iseq->arg_simple == 1) {
01751 args = INT2FIX(iseq->argc);
01752 }
01753 else {
01754 rb_ary_push(args, INT2FIX(iseq->argc));
01755 rb_ary_push(args, arg_opt_labels);
01756 rb_ary_push(args, INT2FIX(iseq->arg_post_len));
01757 rb_ary_push(args, INT2FIX(iseq->arg_post_start));
01758 rb_ary_push(args, INT2FIX(iseq->arg_rest));
01759 rb_ary_push(args, INT2FIX(iseq->arg_block));
01760 rb_ary_push(args, INT2FIX(iseq->arg_simple));
01761 }
01762 }
01763
01764
01765 for (seq = iseq->iseq; seq < iseq->iseq + iseq->iseq_size; ) {
01766 VALUE insn = *seq++;
01767 int j, len = insn_len(insn);
01768 VALUE *nseq = seq + len - 1;
01769 VALUE ary = rb_ary_new2(len);
01770
01771 rb_ary_push(ary, insn_syms[insn]);
01772 for (j=0; j<len-1; j++, seq++) {
01773 switch (insn_op_type(insn, j)) {
01774 case TS_OFFSET: {
01775 unsigned long idx = nseq - iseq->iseq + *seq;
01776 rb_ary_push(ary, register_label(labels_table, idx));
01777 break;
01778 }
01779 case TS_LINDEX:
01780 case TS_NUM:
01781 rb_ary_push(ary, INT2FIX(*seq));
01782 break;
01783 case TS_VALUE:
01784 rb_ary_push(ary, obj_resurrect(*seq));
01785 break;
01786 case TS_ISEQ:
01787 {
01788 rb_iseq_t *iseq = (rb_iseq_t *)*seq;
01789 if (iseq) {
01790 VALUE val = iseq_data_to_ary(iseq);
01791 rb_ary_push(ary, val);
01792 }
01793 else {
01794 rb_ary_push(ary, Qnil);
01795 }
01796 }
01797 break;
01798 case TS_GENTRY:
01799 {
01800 struct rb_global_entry *entry = (struct rb_global_entry *)*seq;
01801 rb_ary_push(ary, ID2SYM(entry->id));
01802 }
01803 break;
01804 case TS_IC:
01805 {
01806 union iseq_inline_storage_entry *is = (union iseq_inline_storage_entry *)*seq;
01807 rb_ary_push(ary, INT2FIX(is - iseq->is_entries));
01808 }
01809 break;
01810 case TS_CALLINFO:
01811 {
01812 rb_call_info_t *ci = (rb_call_info_t *)*seq;
01813 VALUE e = rb_hash_new();
01814 rb_hash_aset(e, ID2SYM(rb_intern("mid")), ci->mid ? ID2SYM(ci->mid) : Qnil);
01815 rb_hash_aset(e, ID2SYM(rb_intern("flag")), ULONG2NUM(ci->flag));
01816 rb_hash_aset(e, ID2SYM(rb_intern("orig_argc")), INT2FIX(ci->orig_argc));
01817 rb_hash_aset(e, ID2SYM(rb_intern("blockptr")), ci->blockiseq ? iseq_data_to_ary(ci->blockiseq) : Qnil);
01818 rb_ary_push(ary, e);
01819 }
01820 break;
01821 case TS_ID:
01822 rb_ary_push(ary, ID2SYM(*seq));
01823 break;
01824 case TS_CDHASH:
01825 {
01826 VALUE hash = *seq;
01827 VALUE val = rb_ary_new();
01828 int i;
01829
01830 rb_hash_foreach(hash, cdhash_each, val);
01831
01832 for (i=0; i<RARRAY_LEN(val); i+=2) {
01833 VALUE pos = FIX2INT(rb_ary_entry(val, i+1));
01834 unsigned long idx = nseq - iseq->iseq + pos;
01835
01836 rb_ary_store(val, i+1,
01837 register_label(labels_table, idx));
01838 }
01839 rb_ary_push(ary, val);
01840 }
01841 break;
01842 default:
01843 rb_bug("unknown operand: %c", insn_op_type(insn, j));
01844 }
01845 }
01846 rb_ary_push(body, ary);
01847 }
01848
01849 nbody = body;
01850
01851
01852 for (i=0; i<iseq->catch_table_size; i++) {
01853 VALUE ary = rb_ary_new();
01854 struct iseq_catch_table_entry *entry = &iseq->catch_table[i];
01855 rb_ary_push(ary, exception_type2symbol(entry->type));
01856 if (entry->iseq) {
01857 rb_iseq_t *eiseq;
01858 GetISeqPtr(entry->iseq, eiseq);
01859 rb_ary_push(ary, iseq_data_to_ary(eiseq));
01860 }
01861 else {
01862 rb_ary_push(ary, Qnil);
01863 }
01864 rb_ary_push(ary, register_label(labels_table, entry->start));
01865 rb_ary_push(ary, register_label(labels_table, entry->end));
01866 rb_ary_push(ary, register_label(labels_table, entry->cont));
01867 rb_ary_push(ary, INT2FIX(entry->sp));
01868 rb_ary_push(exception, ary);
01869 }
01870
01871
01872 body = rb_ary_new();
01873 ti = 0;
01874
01875 for (i=0, pos=0; i<RARRAY_LEN(nbody); i++) {
01876 VALUE ary = RARRAY_AREF(nbody, i);
01877 st_data_t label;
01878
01879 if (st_lookup(labels_table, pos, &label)) {
01880 rb_ary_push(body, (VALUE)label);
01881 }
01882
01883 if (ti < iseq->line_info_size && iseq->line_info_table[ti].position == pos) {
01884 line = iseq->line_info_table[ti].line_no;
01885 rb_ary_push(body, INT2FIX(line));
01886 ti++;
01887 }
01888
01889 rb_ary_push(body, ary);
01890 pos += RARRAY_LENINT(ary);
01891 }
01892
01893 st_free_table(labels_table);
01894
01895 rb_hash_aset(misc, ID2SYM(rb_intern("arg_size")), INT2FIX(iseq->arg_size));
01896 rb_hash_aset(misc, ID2SYM(rb_intern("local_size")), INT2FIX(iseq->local_size));
01897 rb_hash_aset(misc, ID2SYM(rb_intern("stack_max")), INT2FIX(iseq->stack_max));
01898
01899
01900
01901
01902
01903
01904
01905 rb_ary_push(val, rb_str_new2("YARVInstructionSequence/SimpleDataFormat"));
01906 rb_ary_push(val, INT2FIX(ISEQ_MAJOR_VERSION));
01907 rb_ary_push(val, INT2FIX(ISEQ_MINOR_VERSION));
01908 rb_ary_push(val, INT2FIX(1));
01909 rb_ary_push(val, misc);
01910 rb_ary_push(val, iseq->location.label);
01911 rb_ary_push(val, iseq->location.path);
01912 rb_ary_push(val, iseq->location.absolute_path);
01913 rb_ary_push(val, iseq->location.first_lineno);
01914 rb_ary_push(val, type);
01915 rb_ary_push(val, locals);
01916 rb_ary_push(val, args);
01917 rb_ary_push(val, exception);
01918 rb_ary_push(val, body);
01919 return val;
01920 }
01921
01922 VALUE
01923 rb_iseq_clone(VALUE iseqval, VALUE newcbase)
01924 {
01925 VALUE newiseq = iseq_alloc(rb_cISeq);
01926 rb_iseq_t *iseq0, *iseq1;
01927
01928 GetISeqPtr(iseqval, iseq0);
01929 GetISeqPtr(newiseq, iseq1);
01930
01931 MEMCPY(iseq1, iseq0, rb_iseq_t, 1);
01932
01933 iseq1->self = newiseq;
01934 if (!iseq1->orig) {
01935 RB_OBJ_WRITE(iseq1->self, &iseq1->orig, iseqval);
01936 }
01937 if (iseq0->local_iseq == iseq0) {
01938 iseq1->local_iseq = iseq1;
01939 }
01940 if (newcbase) {
01941 ISEQ_SET_CREF(iseq1, NEW_CREF(newcbase));
01942 RB_OBJ_WRITE(iseq1->cref_stack, &iseq1->cref_stack->nd_refinements, iseq0->cref_stack->nd_refinements);
01943 iseq1->cref_stack->nd_visi = iseq0->cref_stack->nd_visi;
01944 if (iseq0->cref_stack->nd_next) {
01945 RB_OBJ_WRITE(iseq1->cref_stack, &iseq1->cref_stack->nd_next, iseq0->cref_stack->nd_next);
01946 }
01947 RB_OBJ_WRITE(iseq1->self, &iseq1->klass, newcbase);
01948 }
01949
01950 return newiseq;
01951 }
01952
01953 VALUE
01954 rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
01955 {
01956 int i, r;
01957 VALUE a, args = rb_ary_new2(iseq->arg_size);
01958 ID req, opt, rest, block, key, keyrest;
01959 #define PARAM_TYPE(type) rb_ary_push(a = rb_ary_new2(2), ID2SYM(type))
01960 #define PARAM_ID(i) iseq->local_table[(i)]
01961 #define PARAM(i, type) ( \
01962 PARAM_TYPE(type), \
01963 rb_id2str(PARAM_ID(i)) ? \
01964 rb_ary_push(a, ID2SYM(PARAM_ID(i))) : \
01965 a)
01966
01967 CONST_ID(req, "req");
01968 CONST_ID(opt, "opt");
01969 if (is_proc) {
01970 for (i = 0; i < iseq->argc; i++) {
01971 PARAM_TYPE(opt);
01972 rb_ary_push(a, rb_id2str(PARAM_ID(i)) ? ID2SYM(PARAM_ID(i)) : Qnil);
01973 rb_ary_push(args, a);
01974 }
01975 }
01976 else {
01977 for (i = 0; i < iseq->argc; i++) {
01978 rb_ary_push(args, PARAM(i, req));
01979 }
01980 }
01981 r = iseq->argc + iseq->arg_opts - 1;
01982 for (; i < r; i++) {
01983 PARAM_TYPE(opt);
01984 if (rb_id2str(PARAM_ID(i))) {
01985 rb_ary_push(a, ID2SYM(PARAM_ID(i)));
01986 }
01987 rb_ary_push(args, a);
01988 }
01989 if (iseq->arg_rest != -1) {
01990 CONST_ID(rest, "rest");
01991 rb_ary_push(args, PARAM(iseq->arg_rest, rest));
01992 }
01993 r = iseq->arg_post_start + iseq->arg_post_len;
01994 if (is_proc) {
01995 for (i = iseq->arg_post_start; i < r; i++) {
01996 PARAM_TYPE(opt);
01997 rb_ary_push(a, rb_id2str(PARAM_ID(i)) ? ID2SYM(PARAM_ID(i)) : Qnil);
01998 rb_ary_push(args, a);
01999 }
02000 }
02001 else {
02002 for (i = iseq->arg_post_start; i < r; i++) {
02003 rb_ary_push(args, PARAM(i, req));
02004 }
02005 }
02006 if (iseq->arg_keyword != -1) {
02007 i = 0;
02008 if (iseq->arg_keyword_required) {
02009 ID keyreq;
02010 CONST_ID(keyreq, "keyreq");
02011 for (; i < iseq->arg_keyword_required; i++) {
02012 PARAM_TYPE(keyreq);
02013 if (rb_id2str(iseq->arg_keyword_table[i])) {
02014 rb_ary_push(a, ID2SYM(iseq->arg_keyword_table[i]));
02015 }
02016 rb_ary_push(args, a);
02017 }
02018 }
02019 CONST_ID(key, "key");
02020 for (; i < iseq->arg_keywords; i++) {
02021 PARAM_TYPE(key);
02022 if (rb_id2str(iseq->arg_keyword_table[i])) {
02023 rb_ary_push(a, ID2SYM(iseq->arg_keyword_table[i]));
02024 }
02025 rb_ary_push(args, a);
02026 }
02027 if (!iseq->arg_keyword_check) {
02028 CONST_ID(keyrest, "keyrest");
02029 rb_ary_push(args, PARAM(iseq->arg_keyword, keyrest));
02030 }
02031 }
02032 if (iseq->arg_block != -1) {
02033 CONST_ID(block, "block");
02034 rb_ary_push(args, PARAM(iseq->arg_block, block));
02035 }
02036 return args;
02037 }
02038
02039 VALUE
02040 rb_iseq_defined_string(enum defined_type type)
02041 {
02042 static const char expr_names[][18] = {
02043 "nil",
02044 "instance-variable",
02045 "local-variable",
02046 "global-variable",
02047 "class variable",
02048 "constant",
02049 "method",
02050 "yield",
02051 "super",
02052 "self",
02053 "true",
02054 "false",
02055 "assignment",
02056 "expression",
02057 };
02058 const char *estr;
02059 VALUE *defs, str;
02060
02061 if ((unsigned)(type - 1) >= (unsigned)numberof(expr_names)) return 0;
02062 estr = expr_names[type - 1];
02063 if (!estr[0]) return 0;
02064 defs = GET_VM()->defined_strings;
02065 if (!defs) {
02066 defs = ruby_xcalloc(numberof(expr_names), sizeof(VALUE));
02067 GET_VM()->defined_strings = defs;
02068 }
02069 str = defs[type-1];
02070 if (!str) {
02071 str = rb_str_new_cstr(estr);;
02072 OBJ_FREEZE(str);
02073 defs[type-1] = str;
02074 }
02075 return str;
02076 }
02077
02078
02079
02080 VALUE
02081 rb_iseq_build_for_ruby2cext(
02082 const rb_iseq_t *iseq_template,
02083 const rb_insn_func_t *func,
02084 const struct iseq_line_info_entry *line_info_table,
02085 const char **local_table,
02086 const VALUE *arg_opt_table,
02087 const struct iseq_catch_table_entry *catch_table,
02088 const char *name,
02089 const char *path,
02090 const unsigned short first_lineno)
02091 {
02092 unsigned long i;
02093 VALUE iseqval = iseq_alloc(rb_cISeq);
02094 rb_iseq_t *iseq;
02095 GetISeqPtr(iseqval, iseq);
02096
02097
02098 MEMCPY(iseq, iseq_template, rb_iseq_t, 1);
02099 RB_OBJ_WRITE(iseq->self, &iseq->location.label, rb_str_new2(name));
02100 RB_OBJ_WRITE(iseq->self, &iseq->location.path, rb_str_new2(path));
02101 iseq->location.first_lineno = first_lineno;
02102 RB_OBJ_WRITE(iseq->self, &iseq->mark_ary, 0);
02103 iseq->self = iseqval;
02104
02105 iseq->iseq = ALLOC_N(VALUE, iseq->iseq_size);
02106
02107 for (i=0; i<iseq->iseq_size; i+=2) {
02108 iseq->iseq[i] = BIN(opt_call_c_function);
02109 iseq->iseq[i+1] = (VALUE)func;
02110 }
02111
02112 rb_iseq_translate_threaded_code(iseq);
02113
02114 #define ALLOC_AND_COPY(dst, src, type, size) do { \
02115 if (size) { \
02116 (dst) = ALLOC_N(type, (size)); \
02117 MEMCPY((dst), (src), type, (size)); \
02118 } \
02119 } while (0)
02120
02121 ALLOC_AND_COPY(iseq->line_info_table, line_info_table,
02122 struct iseq_line_info_entry, iseq->line_info_size);
02123
02124 ALLOC_AND_COPY(iseq->catch_table, catch_table,
02125 struct iseq_catch_table_entry, iseq->catch_table_size);
02126
02127 ALLOC_AND_COPY(iseq->arg_opt_table, arg_opt_table,
02128 VALUE, iseq->arg_opts);
02129
02130 set_relation(iseq, 0);
02131
02132 return iseqval;
02133 }
02134
02135
02136
02137
02138
02139 int
02140 rb_iseq_line_trace_each(VALUE iseqval, int (*func)(int line, rb_event_flag_t *events_ptr, void *d), void *data)
02141 {
02142 int trace_num = 0;
02143 size_t pos, insn;
02144 rb_iseq_t *iseq;
02145 int cont = 1;
02146 GetISeqPtr(iseqval, iseq);
02147
02148 for (pos = 0; cont && pos < iseq->iseq_size; pos += insn_len(insn)) {
02149 insn = iseq->iseq[pos];
02150
02151 if (insn == BIN(trace)) {
02152 rb_event_flag_t current_events = (VALUE)iseq->iseq[pos+1];
02153
02154 if (current_events & RUBY_EVENT_LINE) {
02155 rb_event_flag_t events = current_events & RUBY_EVENT_SPECIFIED_LINE;
02156 trace_num++;
02157
02158 if (func) {
02159 int line = find_line_no(iseq, pos);
02160
02161 cont = (*func)(line, &events, data);
02162 if (current_events != events) {
02163 iseq->iseq[pos+1] = iseq->iseq_encoded[pos+1] =
02164 (VALUE)(current_events | (events & RUBY_EVENT_SPECIFIED_LINE));
02165 }
02166 }
02167 }
02168 }
02169 }
02170 return trace_num;
02171 }
02172
02173 static int
02174 collect_trace(int line, rb_event_flag_t *events_ptr, void *ptr)
02175 {
02176 VALUE result = (VALUE)ptr;
02177 rb_ary_push(result, INT2NUM(line));
02178 return 1;
02179 }
02180
02181
02182
02183
02184
02185
02186 VALUE
02187 rb_iseq_line_trace_all(VALUE iseqval)
02188 {
02189 VALUE result = rb_ary_new();
02190 rb_iseq_line_trace_each(iseqval, collect_trace, (void *)result);
02191 return result;
02192 }
02193
02194 struct set_specifc_data {
02195 int pos;
02196 int set;
02197 int prev;
02198 };
02199
02200 static int
02201 line_trace_specify(int line, rb_event_flag_t *events_ptr, void *ptr)
02202 {
02203 struct set_specifc_data *data = (struct set_specifc_data *)ptr;
02204
02205 if (data->pos == 0) {
02206 data->prev = *events_ptr & RUBY_EVENT_SPECIFIED_LINE ? 1 : 2;
02207 if (data->set) {
02208 *events_ptr = *events_ptr | RUBY_EVENT_SPECIFIED_LINE;
02209 }
02210 else {
02211 *events_ptr = *events_ptr & ~RUBY_EVENT_SPECIFIED_LINE;
02212 }
02213 return 0;
02214 }
02215 else {
02216 data->pos--;
02217 return 1;
02218 }
02219 }
02220
02221
02222
02223
02224
02225
02226
02227
02228
02229
02230
02231
02232
02233 VALUE
02234 rb_iseq_line_trace_specify(VALUE iseqval, VALUE pos, VALUE set)
02235 {
02236 struct set_specifc_data data;
02237
02238 data.prev = 0;
02239 data.pos = NUM2INT(pos);
02240 if (data.pos < 0) rb_raise(rb_eTypeError, "`pos' is negative");
02241
02242 switch (set) {
02243 case Qtrue: data.set = 1; break;
02244 case Qfalse: data.set = 0; break;
02245 default:
02246 rb_raise(rb_eTypeError, "`set' should be true/false");
02247 }
02248
02249 rb_iseq_line_trace_each(iseqval, line_trace_specify, (void *)&data);
02250
02251 if (data.prev == 0) {
02252 rb_raise(rb_eTypeError, "`pos' is out of range.");
02253 }
02254 return data.prev == 1 ? Qtrue : Qfalse;
02255 }
02256
02257
02258
02259
02260
02261
02262
02263
02264
02265
02266
02267
02268
02269
02270
02271
02272
02273
02274
02275
02276
02277 void
02278 Init_ISeq(void)
02279 {
02280
02281 rb_cISeq = rb_define_class_under(rb_cRubyVM, "InstructionSequence", rb_cObject);
02282 rb_define_alloc_func(rb_cISeq, iseq_alloc);
02283 rb_define_method(rb_cISeq, "inspect", iseq_inspect, 0);
02284 rb_define_method(rb_cISeq, "disasm", rb_iseq_disasm, 0);
02285 rb_define_method(rb_cISeq, "disassemble", rb_iseq_disasm, 0);
02286 rb_define_method(rb_cISeq, "to_a", iseq_to_a, 0);
02287 rb_define_method(rb_cISeq, "eval", iseq_eval, 0);
02288
02289
02290 rb_define_method(rb_cISeq, "path", rb_iseq_path, 0);
02291 rb_define_method(rb_cISeq, "absolute_path", rb_iseq_absolute_path, 0);
02292 rb_define_method(rb_cISeq, "label", rb_iseq_label, 0);
02293 rb_define_method(rb_cISeq, "base_label", rb_iseq_base_label, 0);
02294 rb_define_method(rb_cISeq, "first_lineno", rb_iseq_first_lineno, 0);
02295
02296 #if 0
02297
02298
02299 rb_define_method(rb_cISeq, "line_trace_all", rb_iseq_line_trace_all, 0);
02300 rb_define_method(rb_cISeq, "line_trace_specify", rb_iseq_line_trace_specify, 2);
02301 #else
02302 (void)rb_iseq_line_trace_all;
02303 (void)rb_iseq_line_trace_specify;
02304 #endif
02305
02306 #if 0
02307 rb_define_private_method(rb_cISeq, "marshal_dump", iseq_marshal_dump, 0);
02308 rb_define_private_method(rb_cISeq, "marshal_load", iseq_marshal_load, 1);
02309 #endif
02310
02311
02312
02313 (void)iseq_s_load;
02314
02315 rb_define_singleton_method(rb_cISeq, "compile", iseq_s_compile, -1);
02316 rb_define_singleton_method(rb_cISeq, "new", iseq_s_compile, -1);
02317 rb_define_singleton_method(rb_cISeq, "compile_file", iseq_s_compile_file, -1);
02318 rb_define_singleton_method(rb_cISeq, "compile_option", iseq_s_compile_option_get, 0);
02319 rb_define_singleton_method(rb_cISeq, "compile_option=", iseq_s_compile_option_set, 1);
02320 rb_define_singleton_method(rb_cISeq, "disasm", iseq_s_disasm, 1);
02321 rb_define_singleton_method(rb_cISeq, "disassemble", iseq_s_disasm, 1);
02322 rb_define_singleton_method(rb_cISeq, "of", iseq_s_of, 1);
02323 }
02324