1 /**********************************************************************
6 created at: 2006-07-11(Tue) 09:00:03 +0900
8 Copyright (C) 2006 Koichi Sasada
10 **********************************************************************/
12 #include "ruby/ruby.h"
13 #include "ruby/node.h"
15 /* #define MARK_FREE_DEBUG 1 */
20 #include "insns_info.inc"
23 void iseq_compile(VALUE self
, NODE
*node
);
24 int iseq_translate_threaded_code(rb_iseq_t
*iseq
);
29 compile_data_free(struct iseq_compile_data
*compile_data
)
32 struct iseq_compile_data_storage
*cur
, *next
;
33 cur
= compile_data
->storage_head
;
39 ruby_xfree(compile_data
);
47 RUBY_FREE_ENTER("iseq");
51 /* It's possible that strings are freed
52 * GC_INFO("%s @ %s\n", RSTRING_PTR(iseq->name),
53 * RSTRING_PTR(iseq->filename));
55 if (iseq
->iseq
!= iseq
->iseq_encoded
) {
56 RUBY_FREE_UNLESS_NULL(iseq
->iseq_encoded
);
59 RUBY_FREE_UNLESS_NULL(iseq
->iseq
);
60 RUBY_FREE_UNLESS_NULL(iseq
->insn_info_table
);
61 RUBY_FREE_UNLESS_NULL(iseq
->local_table
);
62 RUBY_FREE_UNLESS_NULL(iseq
->catch_table
);
63 RUBY_FREE_UNLESS_NULL(iseq
->arg_opt_table
);
64 compile_data_free(iseq
->compile_data
);
67 RUBY_FREE_LEAVE("iseq");
74 RUBY_MARK_ENTER("iseq");
78 RUBY_GC_INFO("%s @ %s\n", RSTRING_PTR(iseq
->name
), RSTRING_PTR(iseq
->filename
));
79 RUBY_MARK_UNLESS_NULL(iseq
->mark_ary
);
80 RUBY_MARK_UNLESS_NULL(iseq
->name
);
81 RUBY_MARK_UNLESS_NULL(iseq
->filename
);
82 RUBY_MARK_UNLESS_NULL((VALUE
)iseq
->cref_stack
);
83 RUBY_MARK_UNLESS_NULL(iseq
->klass
);
84 /* RUBY_MARK_UNLESS_NULL((VALUE)iseq->node); */
85 /* RUBY_MARK_UNLESS_NULL(iseq->cached_special_block); */
87 if (iseq
->compile_data
!= 0) {
88 RUBY_MARK_UNLESS_NULL(iseq
->compile_data
->mark_ary
);
89 RUBY_MARK_UNLESS_NULL(iseq
->compile_data
->err_info
);
90 RUBY_MARK_UNLESS_NULL(iseq
->compile_data
->catch_table_ary
);
93 RUBY_MARK_LEAVE("iseq");
97 iseq_alloc(VALUE klass
)
102 obj
= Data_Make_Struct(klass
, rb_iseq_t
, iseq_mark
, iseq_free
, iseq
);
103 MEMZERO(iseq
, rb_iseq_t
, 1);
108 set_relation(rb_iseq_t
*iseq
, const VALUE parent
)
110 const int type
= iseq
->type
;
111 rb_thread_t
*th
= GET_THREAD();
113 /* set class nest stack */
114 if (type
== ISEQ_TYPE_TOP
) {
115 /* toplevel is private */
116 iseq
->cref_stack
= NEW_BLOCK(th
->top_wrapper
? th
->top_wrapper
: rb_cObject
);
117 iseq
->cref_stack
->nd_file
= 0;
118 iseq
->cref_stack
->nd_visi
= NOEX_PRIVATE
;
120 else if (type
== ISEQ_TYPE_METHOD
|| type
== ISEQ_TYPE_CLASS
) {
121 iseq
->cref_stack
= NEW_BLOCK(0); /* place holder */
122 iseq
->cref_stack
->nd_file
= 0;
124 else if (RTEST(parent
)) {
126 GetISeqPtr(parent
, piseq
);
127 iseq
->cref_stack
= piseq
->cref_stack
;
130 if (type
== ISEQ_TYPE_TOP
||
131 type
== ISEQ_TYPE_METHOD
|| type
== ISEQ_TYPE_CLASS
) {
132 iseq
->local_iseq
= iseq
;
134 else if (RTEST(parent
)) {
136 GetISeqPtr(parent
, piseq
);
137 iseq
->local_iseq
= piseq
->local_iseq
;
142 GetISeqPtr(parent
, piseq
);
143 iseq
->parent_iseq
= piseq
;
148 prepare_iseq_build(rb_iseq_t
*iseq
,
149 VALUE name
, VALUE filename
,
150 VALUE parent
, VALUE type
, VALUE block_opt
,
151 const rb_compile_option_t
*option
)
154 OBJ_FREEZE(filename
);
157 iseq
->filename
= filename
;
158 iseq
->defined_method_id
= 0;
159 iseq
->mark_ary
= rb_ary_new();
160 RBASIC(iseq
->mark_ary
)->klass
= 0;
164 iseq
->arg_block
= -1;
168 * iseq->special_block_builder = GC_GUARDED_PTR_REF(block_opt);
169 * iseq->cached_special_block_builder = 0;
170 * iseq->cached_special_block = 0;
173 iseq
->compile_data
= ALLOC(struct iseq_compile_data
);
174 MEMZERO(iseq
->compile_data
, struct iseq_compile_data
, 1);
175 iseq
->compile_data
->mark_ary
= rb_ary_new();
176 RBASIC(iseq
->compile_data
->mark_ary
)->klass
= 0;
178 iseq
->compile_data
->storage_head
= iseq
->compile_data
->storage_current
=
179 (struct iseq_compile_data_storage
*)
180 ALLOC_N(char, INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE
+
181 sizeof(struct iseq_compile_data_storage
));
183 iseq
->compile_data
->catch_table_ary
= rb_ary_new();
184 iseq
->compile_data
->storage_head
->pos
= 0;
185 iseq
->compile_data
->storage_head
->next
= 0;
186 iseq
->compile_data
->storage_head
->size
=
187 INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE
;
188 iseq
->compile_data
->storage_head
->buff
=
189 (char *)(&iseq
->compile_data
->storage_head
->buff
+ 1);
190 iseq
->compile_data
->option
= option
;
192 set_relation(iseq
, parent
);
198 cleanup_iseq_build(rb_iseq_t
*iseq
)
200 struct iseq_compile_data
*data
= iseq
->compile_data
;
201 VALUE err
= data
->err_info
;
202 iseq
->compile_data
= 0;
203 compile_data_free(data
);
206 rb_funcall2(err
, rb_intern("set_backtrace"), 1, &iseq
->filename
);
212 static rb_compile_option_t COMPILE_OPTION_DEFAULT
= {
213 OPT_INLINE_CONST_CACHE
, /* int inline_const_cache; */
214 OPT_PEEPHOLE_OPTIMIZATION
, /* int peephole_optimization; */
215 OPT_TAILCALL_OPTIMIZATION
, /* int tailcall_optimization */
216 OPT_SPECIALISED_INSTRUCTION
, /* int specialized_instruction; */
217 OPT_OPERANDS_UNIFICATION
, /* int operands_unification; */
218 OPT_INSTRUCTIONS_UNIFICATION
, /* int instructions_unification; */
219 OPT_STACK_CACHING
, /* int stack_caching; */
220 OPT_TRACE_INSTRUCTION
, /* int trace_instruction */
222 static const rb_compile_option_t COMPILE_OPTION_FALSE
;
225 make_compile_option(rb_compile_option_t
*option
, VALUE opt
)
228 *option
= COMPILE_OPTION_DEFAULT
;
230 else if (opt
== Qfalse
) {
231 *option
= COMPILE_OPTION_FALSE
;
233 else if (opt
== Qtrue
) {
234 memset(option
, 1, sizeof(rb_compile_option_t
));
236 else if (CLASS_OF(opt
) == rb_cHash
) {
237 *option
= COMPILE_OPTION_DEFAULT
;
239 #define SET_COMPILE_OPTION(o, h, mem) \
240 { VALUE flag = rb_hash_aref(h, ID2SYM(rb_intern(#mem))); \
241 if (flag == Qtrue) { o->mem = 1; } \
242 else if (flag == Qfalse) { o->mem = 0; } \
244 #define SET_COMPILE_OPTION_NUM(o, h, mem) \
245 { VALUE num = rb_hash_aref(opt, ID2SYM(rb_intern(#mem))); \
246 if (!NIL_P(num)) o->mem = NUM2INT(num); \
248 SET_COMPILE_OPTION(option
, opt
, inline_const_cache
);
249 SET_COMPILE_OPTION(option
, opt
, peephole_optimization
);
250 SET_COMPILE_OPTION(option
, opt
, tailcall_optimization
);
251 SET_COMPILE_OPTION(option
, opt
, specialized_instruction
);
252 SET_COMPILE_OPTION(option
, opt
, operands_unification
);
253 SET_COMPILE_OPTION(option
, opt
, instructions_unification
);
254 SET_COMPILE_OPTION(option
, opt
, stack_caching
);
255 SET_COMPILE_OPTION(option
, opt
, trace_instruction
);
256 SET_COMPILE_OPTION_NUM(option
, opt
, debug_level
);
257 #undef SET_COMPILE_OPTION
258 #undef SET_COMPILE_OPTION_NUM
261 rb_raise(rb_eTypeError
, "Compile option must be Hash/true/false/nil");
266 make_compile_option_value(rb_compile_option_t
*option
)
268 VALUE opt
= rb_hash_new();
269 #define SET_COMPILE_OPTION(o, h, mem) \
270 rb_hash_aset(h, ID2SYM(rb_intern(#mem)), o->mem ? Qtrue : Qfalse)
271 #define SET_COMPILE_OPTION_NUM(o, h, mem) \
272 rb_hash_aset(h, ID2SYM(rb_intern(#mem)), INT2NUM(o->mem))
274 SET_COMPILE_OPTION(option
, opt
, inline_const_cache
);
275 SET_COMPILE_OPTION(option
, opt
, peephole_optimization
);
276 SET_COMPILE_OPTION(option
, opt
, tailcall_optimization
);
277 SET_COMPILE_OPTION(option
, opt
, specialized_instruction
);
278 SET_COMPILE_OPTION(option
, opt
, operands_unification
);
279 SET_COMPILE_OPTION(option
, opt
, instructions_unification
);
280 SET_COMPILE_OPTION(option
, opt
, stack_caching
);
281 SET_COMPILE_OPTION_NUM(option
, opt
, debug_level
);
283 #undef SET_COMPILE_OPTION
284 #undef SET_COMPILE_OPTION_NUM
289 rb_iseq_new(NODE
*node
, VALUE name
, VALUE filename
,
290 VALUE parent
, VALUE type
)
292 return rb_iseq_new_with_opt(node
, name
, filename
, parent
, type
,
293 &COMPILE_OPTION_DEFAULT
);
297 rb_iseq_new_with_bopt_and_opt(NODE
*node
, VALUE name
, VALUE filename
,
298 VALUE parent
, VALUE type
, VALUE bopt
,
299 const rb_compile_option_t
*option
)
302 VALUE self
= iseq_alloc(rb_cISeq
);
304 GetISeqPtr(self
, iseq
);
307 prepare_iseq_build(iseq
, name
, filename
, parent
, type
, bopt
, option
);
308 iseq_compile(self
, node
);
309 cleanup_iseq_build(iseq
);
314 rb_iseq_new_with_opt(NODE
*node
, VALUE name
, VALUE filename
,
315 VALUE parent
, VALUE type
,
316 const rb_compile_option_t
*option
)
318 return rb_iseq_new_with_bopt_and_opt(node
, name
, filename
, parent
, type
,
323 rb_iseq_new_with_bopt(NODE
*node
, VALUE name
, VALUE filename
,
324 VALUE parent
, VALUE type
, VALUE bopt
)
326 return rb_iseq_new_with_bopt_and_opt(node
, name
, filename
, parent
, type
,
327 bopt
, &COMPILE_OPTION_DEFAULT
);
330 VALUE
iseq_build_from_ary(rb_iseq_t
*iseq
, VALUE locals
, VALUE args
,
331 VALUE exception
, VALUE body
);
333 #define CHECK_ARRAY(v) rb_convert_type(v, T_ARRAY, "Array", "to_ary")
334 #define CHECK_STRING(v) rb_convert_type(v, T_STRING, "String", "to_str")
335 #define CHECK_SYMBOL(v) rb_convert_type(v, T_SYMBOL, "Symbol", "to_sym")
336 static inline VALUE
CHECK_INTEGER(VALUE v
) {NUM2LONG(v
); return v
;}
338 iseq_load(VALUE self
, VALUE data
, VALUE parent
, VALUE opt
)
340 VALUE iseqval
= iseq_alloc(rb_cISeq
);
342 VALUE magic
, version1
, version2
, format_type
, misc
;
343 VALUE name
, filename
;
344 VALUE type
, body
, locals
, args
, exception
;
347 struct st_table
*type_map
= 0;
349 rb_compile_option_t option
;
352 /* [magic, major_version, minor_version, format_type, misc,
354 * type, locals, args, exception_table, body]
357 data
= CHECK_ARRAY(data
);
359 magic
= CHECK_STRING(rb_ary_entry(data
, i
++));
360 version1
= CHECK_INTEGER(rb_ary_entry(data
, i
++));
361 version2
= CHECK_INTEGER(rb_ary_entry(data
, i
++));
362 format_type
= CHECK_INTEGER(rb_ary_entry(data
, i
++));
363 misc
= rb_ary_entry(data
, i
++); /* TODO */
365 name
= CHECK_STRING(rb_ary_entry(data
, i
++));
366 filename
= CHECK_STRING(rb_ary_entry(data
, i
++));
368 type
= CHECK_SYMBOL(rb_ary_entry(data
, i
++));
369 locals
= CHECK_ARRAY(rb_ary_entry(data
, i
++));
371 args
= rb_ary_entry(data
, i
++);
372 if (FIXNUM_P(args
) || (args
= CHECK_ARRAY(args
))) {
376 exception
= CHECK_ARRAY(rb_ary_entry(data
, i
++));
377 body
= CHECK_ARRAY(rb_ary_entry(data
, i
++));
379 GetISeqPtr(iseqval
, iseq
);
380 iseq
->self
= iseqval
;
383 type_map
= st_init_numtable();
384 st_insert(type_map
, ID2SYM(rb_intern("top")), ISEQ_TYPE_TOP
);
385 st_insert(type_map
, ID2SYM(rb_intern("method")), ISEQ_TYPE_METHOD
);
386 st_insert(type_map
, ID2SYM(rb_intern("block")), ISEQ_TYPE_BLOCK
);
387 st_insert(type_map
, ID2SYM(rb_intern("class")), ISEQ_TYPE_CLASS
);
388 st_insert(type_map
, ID2SYM(rb_intern("rescue")), ISEQ_TYPE_RESCUE
);
389 st_insert(type_map
, ID2SYM(rb_intern("ensure")), ISEQ_TYPE_ENSURE
);
390 st_insert(type_map
, ID2SYM(rb_intern("eval")), ISEQ_TYPE_EVAL
);
393 if (st_lookup(type_map
, type
, &iseq_type
) == 0) {
394 const char *typename
= rb_id2name(type
);
396 rb_raise(rb_eTypeError
, "unsupport type: :%s", typename
);
398 rb_raise(rb_eTypeError
, "unsupport type: %p", (void *)type
);
401 if (parent
== Qnil
) {
405 make_compile_option(&option
, opt
);
406 prepare_iseq_build(iseq
, name
, filename
,
407 parent
, iseq_type
, 0, &option
);
409 iseq_build_from_ary(iseq
, locals
, args
, exception
, body
);
411 cleanup_iseq_build(iseq
);
416 iseq_s_load(int argc
, VALUE
*argv
, VALUE self
)
418 VALUE data
, opt
=Qnil
;
419 rb_scan_args(argc
, argv
, "11", &data
, &opt
);
421 return iseq_load(self
, data
, 0, opt
);
425 compile_string(VALUE str
, VALUE file
, VALUE line
)
427 VALUE parser
= rb_parser_new();
428 NODE
*node
= rb_parser_compile_string(parser
, StringValueCStr(file
),
432 rb_exc_raise(GET_THREAD()->errinfo
); /* TODO: check err */
438 rb_iseq_compile_with_option(VALUE src
, VALUE file
, VALUE line
, VALUE opt
)
440 rb_compile_option_t option
;
441 NODE
*node
= compile_string(StringValue(src
), file
, line
);
442 rb_thread_t
*th
= GET_THREAD();
443 make_compile_option(&option
, opt
);
445 if (th
->base_block
) {
446 return rb_iseq_new_with_opt(node
, th
->base_block
->iseq
->name
,
447 file
, th
->base_block
->iseq
->self
,
448 ISEQ_TYPE_EVAL
, &option
);
451 return rb_iseq_new_with_opt(node
, rb_str_new2("<compiled>"), file
, Qfalse
,
452 ISEQ_TYPE_TOP
, &option
);
457 rb_iseq_compile(VALUE src
, VALUE file
, VALUE line
)
459 return rb_iseq_compile_with_option(src
, file
, line
, Qnil
);
463 iseq_s_compile(int argc
, VALUE
*argv
, VALUE self
)
465 VALUE src
, file
= Qnil
, line
= INT2FIX(1), opt
= Qnil
;
469 rb_scan_args(argc
, argv
, "13", &src
, &file
, &line
, &opt
);
470 file
= file
== Qnil
? rb_str_new2("<compiled>") : file
;
471 line
= line
== Qnil
? INT2FIX(1) : line
;
473 return rb_iseq_compile_with_option(src
, file
, line
, opt
);
477 iseq_s_compile_file(int argc
, VALUE
*argv
, VALUE self
)
479 VALUE file
, line
= INT2FIX(1), opt
= Qnil
;
484 rb_compile_option_t option
;
487 rb_scan_args(argc
, argv
, "11", &file
, &opt
);
488 fname
= StringValueCStr(file
);
490 f
= rb_file_open(fname
, "r");
492 parser
= rb_parser_new();
493 node
= rb_parser_compile_file(parser
, fname
, f
, NUM2INT(line
));
494 make_compile_option(&option
, opt
);
495 return rb_iseq_new_with_opt(node
, rb_str_new2("<main>"), file
, Qfalse
,
496 ISEQ_TYPE_TOP
, &option
);
500 iseq_s_compile_option_set(VALUE self
, VALUE opt
)
502 rb_compile_option_t option
;
504 make_compile_option(&option
, opt
);
505 COMPILE_OPTION_DEFAULT
= option
;
510 iseq_s_compile_option_get(VALUE self
)
512 return make_compile_option_value(&COMPILE_OPTION_DEFAULT
);
516 iseq_check(VALUE val
)
519 GetISeqPtr(val
, iseq
);
521 rb_raise(rb_eTypeError
, "uninitialized InstructionSequence");
527 iseq_eval(VALUE self
)
530 return rb_iseq_eval(self
);
534 iseq_inspect(VALUE self
)
537 rb_iseq_t
*iseq
= iseq_check(self
);
539 snprintf(buff
, sizeof(buff
), "<ISeq:%s@%s>",
540 RSTRING_PTR(iseq
->name
), RSTRING_PTR(iseq
->filename
));
542 return rb_str_new2(buff
);
545 VALUE
iseq_data_to_ary(rb_iseq_t
*iseq
);
548 iseq_to_a(VALUE self
)
550 rb_iseq_t
*iseq
= iseq_check(self
);
552 return iseq_data_to_ary(iseq
);
555 /* TODO: search algorithm is brute force.
556 this should be binary search or so. */
558 static struct iseq_insn_info_entry
*
559 get_insn_info(const rb_iseq_t
*iseq
, const unsigned long pos
)
561 unsigned long i
, size
= iseq
->insn_info_size
;
562 struct iseq_insn_info_entry
*table
= iseq
->insn_info_table
;
564 for (i
= 0; i
< size
; i
++) {
565 if (table
[i
].position
== pos
) {
573 static unsigned short
574 find_line_no(rb_iseq_t
*iseq
, unsigned long pos
)
576 struct iseq_insn_info_entry
*entry
= get_insn_info(iseq
, pos
);
578 return entry
->line_no
;
585 static unsigned short
586 find_prev_line_no(rb_iseq_t
*iseqdat
, unsigned long pos
)
588 unsigned long i
, size
= iseqdat
->insn_info_size
;
589 struct iseq_insn_info_entry
*iiary
= iseqdat
->insn_info_table
;
591 for (i
= 0; i
< size
; i
++) {
592 if (iiary
[i
].position
== pos
) {
594 return iiary
[i
- 1].line_no
;
606 insn_operand_intern(rb_iseq_t
*iseq
,
607 int insn
, int op_no
, VALUE op
,
608 int len
, int pos
, VALUE
*pnop
, VALUE child
)
610 const char *types
= insn_op_types(insn
);
611 char type
= types
[op_no
];
616 case TS_OFFSET
: /* LONG */
617 snprintf(buff
, sizeof(buff
), "%ld", pos
+ len
+ op
);
618 ret
= rb_str_new2(buff
);
621 case TS_NUM
: /* ULONG */
622 snprintf(buff
, sizeof(buff
), "%lu", op
);
623 ret
= rb_str_new2(buff
);
628 rb_iseq_t
*ip
= iseq
->local_iseq
;
629 int lidx
= ip
->local_size
- op
;
630 const char *name
= rb_id2name(ip
->local_table
[lidx
]);
633 ret
= rb_str_new2(name
);
636 ret
= rb_str_new2("*");
641 if (insn
== BIN(getdynamic
) || insn
== BIN(setdynamic
)) {
642 rb_iseq_t
*ip
= iseq
;
643 int level
= *pnop
, i
;
645 for (i
= 0; i
< level
; i
++) {
646 ip
= ip
->parent_iseq
;
648 name
= rb_id2name(ip
->local_table
[ip
->local_size
- op
]);
653 ret
= rb_str_new2(name
);
656 ret
= rb_inspect(INT2FIX(op
));
660 case TS_ID
: /* ID (symbol) */
662 case TS_VALUE
: /* VALUE */
663 ret
= rb_inspect(op
);
664 if (CLASS_OF(op
) == rb_cISeq
) {
665 rb_ary_push(child
, op
);
669 case TS_ISEQ
: /* iseq */
671 rb_iseq_t
*iseq
= (rb_iseq_t
*)op
;
675 rb_ary_push(child
, iseq
->self
);
679 ret
= rb_str_new2("nil");
685 struct global_entry
*entry
= (struct global_entry
*)op
;
686 ret
= rb_str_dup(rb_id2str(entry
->id
));
691 ret
= rb_str_new2("<ic>");
695 ret
= rb_str_new2("<cdhash>");
699 ret
= rb_str_new2("<funcptr>");
703 rb_bug("ruby_iseq_disasm: unknown operand type: %c", type
);
709 * Disassemble a instruction
710 * Iseq -> Iseq inspect object
713 ruby_iseq_disasm_insn(VALUE ret
, VALUE
*iseq
, int pos
,
714 rb_iseq_t
*iseqdat
, VALUE child
)
716 int insn
= iseq
[pos
];
717 int len
= insn_len(insn
);
719 const char *types
= insn_op_types(insn
);
720 VALUE str
= rb_str_new(0, 0);
722 char insn_name_buff
[0x100];
724 strcpy(insn_name_buff
, insn_name(insn
));
726 for (i
= 0; insn_name_buff
[i
]; i
++) {
727 if (insn_name_buff
[i
] == '_') {
728 insn_name_buff
[i
] = 0;
733 snprintf(buff
, sizeof(buff
), "%04d %-16s ", pos
, insn_name_buff
);
734 rb_str_cat2(str
, buff
);
736 for (j
= 0; types
[j
]; j
++) {
737 const char *types
= insn_op_types(insn
);
738 VALUE opstr
= insn_operand_intern(iseqdat
, insn
, j
, iseq
[pos
+ j
+ 1],
739 len
, pos
, &iseq
[pos
+ j
+ 2],
741 rb_str_concat(str
, opstr
);
744 rb_str_cat2(str
, ", ");
749 int line_no
= find_line_no(iseqdat
, pos
);
750 int prev
= find_prev_line_no(iseqdat
, pos
);
751 if (line_no
&& line_no
!= prev
) {
752 snprintf(buff
, sizeof(buff
), "%-70s(%4d)", RSTRING_PTR(str
),
754 str
= rb_str_new2(buff
);
759 struct iseq_insn_info_entry
*entry
= get_insn_info(iseqdat
, pos
);
760 snprintf(buff
, sizeof(buff
), "%-60s(line: %d, sp: %d)",
761 RSTRING_PTR(str
), entry
->line_no
, entry
->sp
);
762 str
= rb_str_new2(buff
);
766 rb_str_cat2(str
, "\n");
767 rb_str_concat(ret
, str
);
770 printf("%s\n", RSTRING_PTR(str
));
779 case CATCH_TYPE_RESCUE
:
781 case CATCH_TYPE_ENSURE
:
783 case CATCH_TYPE_RETRY
:
785 case CATCH_TYPE_BREAK
:
787 case CATCH_TYPE_REDO
:
789 case CATCH_TYPE_NEXT
:
792 rb_bug("unknown catch type (%d)", type
);
798 ruby_iseq_disasm(VALUE self
)
800 rb_iseq_t
*iseqdat
= iseq_check(self
);
802 VALUE str
= rb_str_new(0, 0);
803 VALUE child
= rb_ary_new();
808 enum {header_minlen
= 72};
812 iseq
= iseqdat
->iseq
;
813 size
= iseqdat
->iseq_size
;
815 rb_str_cat2(str
, "== disasm: ");
817 rb_str_concat(str
, iseq_inspect(iseqdat
->self
));
818 if ((i
= RSTRING_LEN(str
)) < header_minlen
) {
819 rb_str_resize(str
, header_minlen
);
820 memset(RSTRING_PTR(str
) + i
, '=', header_minlen
- i
);
822 rb_str_cat2(str
, "\n");
824 /* show catch table information */
825 if (iseqdat
->catch_table_size
!= 0) {
826 rb_str_cat2(str
, "== catch table\n");
828 for (i
= 0; i
< iseqdat
->catch_table_size
; i
++) {
829 struct iseq_catch_table_entry
*entry
= &iseqdat
->catch_table
[i
];
831 "| catch type: %-6s st: %04d ed: %04d sp: %04d cont: %04d\n",
832 catch_type((int)entry
->type
), (int)entry
->start
,
833 (int)entry
->end
, (int)entry
->sp
, (int)entry
->cont
);
834 rb_str_cat2(str
, buff
);
836 rb_str_concat(str
, ruby_iseq_disasm(entry
->iseq
));
839 if (iseqdat
->catch_table_size
!= 0) {
840 rb_str_cat2(str
, "|-------------------------------------"
841 "-----------------------------------\n");
844 /* show local table information */
845 tbl
= iseqdat
->local_table
;
848 snprintf(buff
, sizeof(buff
),
849 "local table (size: %d, argc: %d "
850 "[opts: %d, rest: %d, post: %d, block: %d] s%d)\n",
851 iseqdat
->local_size
, iseqdat
->argc
,
852 iseqdat
->arg_opts
, iseqdat
->arg_rest
,
853 iseqdat
->arg_post_len
, iseqdat
->arg_block
,
854 iseqdat
->arg_simple
);
855 rb_str_cat2(str
, buff
);
857 for (i
= 0; i
< iseqdat
->local_table_size
; i
++) {
858 const char *name
= rb_id2name(tbl
[i
]);
860 char argi
[0x100] = "";
861 char opti
[0x100] = "";
863 if (iseqdat
->arg_opts
) {
864 int argc
= iseqdat
->argc
;
865 int opts
= iseqdat
->arg_opts
;
866 if (i
>= argc
&& i
< argc
+ opts
- 1) {
867 snprintf(opti
, sizeof(opti
), "Opt=%ld",
868 iseqdat
->arg_opt_table
[i
- argc
]);
872 snprintf(argi
, sizeof(argi
), "%s%s%s%s%s", /* arg, opts, rest, post block */
873 iseqdat
->argc
> i
? "Arg" : "",
875 iseqdat
->arg_rest
== i
? "Rest" : "",
876 (iseqdat
->arg_post_start
<= i
&&
877 i
< iseqdat
->arg_post_start
+ iseqdat
->arg_post_len
) ? "Post" : "",
878 iseqdat
->arg_block
== i
? "Block" : "");
880 snprintf(info
, sizeof(info
), "%s%s%s%s", name
? name
: "?",
881 *argi
? "<" : "", argi
, *argi
? ">" : "");
883 snprintf(buff
, sizeof(buff
), "[%2d] %-11s",
884 iseqdat
->local_size
- i
, info
);
886 rb_str_cat2(str
, buff
);
888 rb_str_cat2(str
, "\n");
892 for (i
= 0; i
< size
;) {
893 i
+= ruby_iseq_disasm_insn(str
, iseq
, i
, iseqdat
, child
);
896 for (i
= 0; i
< RARRAY_LEN(child
); i
++) {
897 VALUE isv
= rb_ary_entry(child
, i
);
898 rb_str_concat(str
, ruby_iseq_disasm(isv
));
905 iseq_s_disasm(VALUE klass
, VALUE body
)
907 extern NODE
*rb_method_body(VALUE body
);
913 if ((node
= rb_method_body(body
)) != 0) {
914 if (nd_type(node
) == RUBY_VM_METHOD_NODE
) {
915 VALUE iseqval
= (VALUE
)node
->nd_body
;
916 ret
= ruby_iseq_disasm(iseqval
);
924 ruby_node_name(int node
)
927 #include "node_name.inc"
929 rb_bug("unknown node (%d)", node
);
934 #define DECL_SYMBOL(name) \
935 static VALUE sym_##name
937 #define INIT_SYMBOL(name) \
938 sym_##name = ID2SYM(rb_intern(#name))
941 register_label(struct st_table
*table
, int idx
)
946 snprintf(buff
, 0x20, "label_%u", idx
);
947 sym
= ID2SYM(rb_intern(buff
));
948 st_insert(table
, idx
, sym
);
953 exception_type2symbol(VALUE type
)
957 case CATCH_TYPE_RESCUE
: id
= rb_intern("rescue"); break;
958 case CATCH_TYPE_ENSURE
: id
= rb_intern("ensure"); break;
959 case CATCH_TYPE_RETRY
: id
= rb_intern("retry"); break;
960 case CATCH_TYPE_BREAK
: id
= rb_intern("break"); break;
961 case CATCH_TYPE_REDO
: id
= rb_intern("redo"); break;
962 case CATCH_TYPE_NEXT
: id
= rb_intern("next"); break;
970 cdhash_each(VALUE key
, VALUE value
, VALUE ary
)
972 rb_ary_push(ary
, key
);
973 rb_ary_push(ary
, value
);
978 iseq_data_to_ary(rb_iseq_t
*iseq
)
980 int i
, pos
, line
= 0;
983 VALUE val
= rb_ary_new();
984 VALUE type
; /* Symbol */
985 VALUE locals
= rb_ary_new();
986 VALUE args
= rb_ary_new();
987 VALUE body
= rb_ary_new(); /* [[:insn1, ...], ...] */
989 VALUE exception
= rb_ary_new(); /* [[....]] */
990 VALUE misc
= rb_hash_new();
992 static VALUE insn_syms
[VM_INSTRUCTION_SIZE
];
993 struct st_table
*labels_table
= st_init_numtable();
1000 DECL_SYMBOL(ensure
);
1005 for (i
=0; i
<VM_INSTRUCTION_SIZE
; i
++) {
1006 insn_syms
[i
] = ID2SYM(rb_intern(insn_name(i
)));
1009 INIT_SYMBOL(method
);
1012 INIT_SYMBOL(rescue
);
1013 INIT_SYMBOL(ensure
);
1018 switch(iseq
->type
) {
1019 case ISEQ_TYPE_TOP
: type
= sym_top
; break;
1020 case ISEQ_TYPE_METHOD
: type
= sym_method
; break;
1021 case ISEQ_TYPE_BLOCK
: type
= sym_block
; break;
1022 case ISEQ_TYPE_CLASS
: type
= sym_class
; break;
1023 case ISEQ_TYPE_RESCUE
: type
= sym_rescue
; break;
1024 case ISEQ_TYPE_ENSURE
: type
= sym_ensure
; break;
1025 case ISEQ_TYPE_EVAL
: type
= sym_eval
; break;
1026 default: rb_bug("unsupported iseq type");
1030 for (i
=0; i
<iseq
->local_table_size
; i
++) {
1031 ID lid
= iseq
->local_table
[i
];
1033 if (rb_id2str(lid
)) rb_ary_push(locals
, ID2SYM(lid
));
1036 rb_ary_push(locals
, ID2SYM(rb_intern("#arg_rest")));
1044 * [label1, label2, ...] # opts
1052 VALUE arg_opt_labels
= rb_ary_new();
1055 for (j
=0; j
<iseq
->arg_opts
; j
++) {
1056 rb_ary_push(arg_opt_labels
,
1057 register_label(labels_table
, iseq
->arg_opt_table
[j
]));
1061 if (iseq
->arg_simple
== 1) {
1062 args
= INT2FIX(iseq
->argc
);
1065 rb_ary_push(args
, INT2FIX(iseq
->argc
));
1066 rb_ary_push(args
, arg_opt_labels
);
1067 rb_ary_push(args
, INT2FIX(iseq
->arg_post_len
));
1068 rb_ary_push(args
, INT2FIX(iseq
->arg_post_start
));
1069 rb_ary_push(args
, INT2FIX(iseq
->arg_rest
));
1070 rb_ary_push(args
, INT2FIX(iseq
->arg_block
));
1071 rb_ary_push(args
, INT2FIX(iseq
->arg_simple
));
1076 for (seq
= iseq
->iseq
; seq
< iseq
->iseq
+ iseq
->iseq_size
; ) {
1077 VALUE insn
= *seq
++;
1078 int j
, len
= insn_len(insn
);
1079 VALUE
*nseq
= seq
+ len
- 1;
1080 VALUE ary
= rb_ary_new2(len
);
1082 rb_ary_push(ary
, insn_syms
[insn
]);
1083 for (j
=0; j
<len
-1; j
++, seq
++) {
1084 switch (insn_op_type(insn
, j
)) {
1086 unsigned int idx
= nseq
- iseq
->iseq
+ *seq
;
1087 rb_ary_push(ary
, register_label(labels_table
, idx
));
1093 rb_ary_push(ary
, INT2FIX(*seq
));
1096 rb_ary_push(ary
, *seq
);
1100 rb_iseq_t
*iseq
= (rb_iseq_t
*)*seq
;
1102 VALUE val
= iseq_data_to_ary(iseq
);
1103 rb_ary_push(ary
, val
);
1106 rb_ary_push(ary
, Qnil
);
1112 struct global_entry
*entry
= (struct global_entry
*)*seq
;
1113 rb_ary_push(ary
, ID2SYM(entry
->id
));
1117 rb_ary_push(ary
, Qnil
);
1120 rb_ary_push(ary
, ID2SYM(*seq
));
1125 VALUE val
= rb_ary_new();
1128 rb_hash_foreach(hash
, cdhash_each
, val
);
1130 for (i
=0; i
<RARRAY_LEN(val
); i
+=2) {
1131 VALUE pos
= FIX2INT(rb_ary_entry(val
, i
+1));
1132 unsigned int idx
= nseq
- iseq
->iseq
+ pos
;
1134 rb_ary_store(val
, i
+1,
1135 register_label(labels_table
, idx
));
1137 rb_ary_push(ary
, val
);
1141 rb_bug("unknown operand: %c", insn_op_type(insn
, j
));
1144 rb_ary_push(body
, ary
);
1150 for (i
=0; i
<iseq
->catch_table_size
; i
++) {
1151 VALUE ary
= rb_ary_new();
1152 struct iseq_catch_table_entry
*entry
= &iseq
->catch_table
[i
];
1153 rb_ary_push(ary
, exception_type2symbol(entry
->type
));
1156 GetISeqPtr(entry
->iseq
, eiseq
);
1157 rb_ary_push(ary
, iseq_data_to_ary(eiseq
));
1160 rb_ary_push(ary
, Qnil
);
1162 rb_ary_push(ary
, register_label(labels_table
, entry
->start
));
1163 rb_ary_push(ary
, register_label(labels_table
, entry
->end
));
1164 rb_ary_push(ary
, register_label(labels_table
, entry
->cont
));
1165 rb_ary_push(ary
, INT2FIX(entry
->sp
));
1166 rb_ary_push(exception
, ary
);
1169 /* make body with labels and insert line number */
1170 body
= rb_ary_new();
1172 for (i
=0, pos
=0; i
<RARRAY_LEN(nbody
); i
++) {
1173 VALUE ary
= RARRAY_PTR(nbody
)[i
];
1176 if (st_lookup(labels_table
, pos
, &label
)) {
1177 rb_ary_push(body
, label
);
1180 if (iseq
->insn_info_table
[i
].line_no
!= line
) {
1181 line
= iseq
->insn_info_table
[i
].line_no
;
1182 rb_ary_push(body
, INT2FIX(line
));
1185 rb_ary_push(body
, ary
);
1186 pos
+= RARRAY_LEN(ary
);
1189 st_free_table(labels_table
);
1191 rb_hash_aset(misc
, ID2SYM(rb_intern("arg_size")), INT2FIX(iseq
->arg_size
));
1192 rb_hash_aset(misc
, ID2SYM(rb_intern("local_size")), INT2FIX(iseq
->local_size
));
1193 rb_hash_aset(misc
, ID2SYM(rb_intern("stack_max")), INT2FIX(iseq
->stack_max
));
1196 * [:magic, :major_version, :minor_version, :format_type, :misc,
1197 * :name, :filename, :type, :locals, :args,
1198 * :catch_table, :bytecode]
1200 rb_ary_push(val
, rb_str_new2("YARVInstructionSequence/SimpleDataFormat"));
1201 rb_ary_push(val
, INT2FIX(1));
1202 rb_ary_push(val
, INT2FIX(1));
1203 rb_ary_push(val
, INT2FIX(1));
1204 rb_ary_push(val
, misc
);
1205 rb_ary_push(val
, iseq
->name
);
1206 rb_ary_push(val
, iseq
->filename
);
1207 rb_ary_push(val
, type
);
1208 rb_ary_push(val
, locals
);
1209 rb_ary_push(val
, args
);
1210 rb_ary_push(val
, exception
);
1211 rb_ary_push(val
, body
);
1216 insn_make_insn_table(void)
1218 struct st_table
*table
;
1220 table
= st_init_numtable();
1222 for (i
=0; i
<VM_INSTRUCTION_SIZE
; i
++) {
1223 st_insert(table
, ID2SYM(rb_intern(insn_name(i
))), i
);
1232 rb_iseq_build_for_ruby2cext(
1233 const rb_iseq_t
*iseq_template
,
1234 const rb_insn_func_t
*func
,
1235 const struct iseq_insn_info_entry
*insn_info_table
,
1236 const char **local_table
,
1237 const VALUE
*arg_opt_table
,
1238 const struct iseq_catch_table_entry
*catch_table
,
1240 const char *filename
)
1243 VALUE iseqval
= iseq_alloc(rb_cISeq
);
1245 GetISeqPtr(iseqval
, iseq
);
1248 *iseq
= *iseq_template
;
1249 iseq
->name
= rb_str_new2(name
);
1250 iseq
->filename
= rb_str_new2(filename
);
1251 iseq
->mark_ary
= rb_ary_new();
1252 iseq
->self
= iseqval
;
1254 iseq
->iseq
= ALLOC_N(VALUE
, iseq
->iseq_size
);
1256 for (i
=0; i
<iseq
->iseq_size
; i
+=2) {
1257 iseq
->iseq
[i
] = BIN(opt_call_c_function
);
1258 iseq
->iseq
[i
+1] = (VALUE
)func
;
1261 iseq_translate_threaded_code(iseq
);
1263 #define ALLOC_AND_COPY(dst, src, type, size) do { \
1265 (dst) = ALLOC_N(type, (size)); \
1266 MEMCPY((dst), (src), type, (size)); \
1270 ALLOC_AND_COPY(iseq
->insn_info_table
, insn_info_table
,
1271 struct iseq_insn_info_entry
, iseq
->insn_info_size
);
1273 ALLOC_AND_COPY(iseq
->catch_table
, catch_table
,
1274 struct iseq_catch_table_entry
, iseq
->catch_table_size
);
1276 ALLOC_AND_COPY(iseq
->arg_opt_table
, arg_opt_table
,
1277 VALUE
, iseq
->arg_opts
);
1279 set_relation(iseq
, 0);
1287 /* declare ::VM::InstructionSequence */
1288 rb_cISeq
= rb_define_class_under(rb_cVM
, "InstructionSequence", rb_cObject
);
1289 rb_define_alloc_func(rb_cISeq
, iseq_alloc
);
1290 rb_define_method(rb_cISeq
, "inspect", iseq_inspect
, 0);
1291 rb_define_method(rb_cISeq
, "disasm", ruby_iseq_disasm
, 0);
1292 rb_define_method(rb_cISeq
, "disassemble", ruby_iseq_disasm
, 0);
1293 rb_define_method(rb_cISeq
, "to_a", iseq_to_a
, 0);
1294 rb_define_method(rb_cISeq
, "eval", iseq_eval
, 0);
1296 /* disable this feature because there is no verifier. */
1297 /* rb_define_singleton_method(rb_cISeq, "load", iseq_s_load, -1); */
1299 rb_define_singleton_method(rb_cISeq
, "compile", iseq_s_compile
, -1);
1300 rb_define_singleton_method(rb_cISeq
, "new", iseq_s_compile
, -1);
1301 rb_define_singleton_method(rb_cISeq
, "compile_file", iseq_s_compile_file
, -1);
1302 rb_define_singleton_method(rb_cISeq
, "compile_option", iseq_s_compile_option_get
, 0);
1303 rb_define_singleton_method(rb_cISeq
, "compile_option=", iseq_s_compile_option_set
, 1);
1304 rb_define_singleton_method(rb_cISeq
, "disasm", iseq_s_disasm
, 1);
1305 rb_define_singleton_method(rb_cISeq
, "disassemble", iseq_s_disasm
, 1);