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");
52 /* It's possible that strings are freed
53 * GC_INFO("%s @ %s\n", RSTRING_PTR(iseq->name),
54 * RSTRING_PTR(iseq->filename));
56 if (iseq
->iseq
!= iseq
->iseq_encoded
) {
57 RUBY_FREE_UNLESS_NULL(iseq
->iseq_encoded
);
60 RUBY_FREE_UNLESS_NULL(iseq
->iseq
);
61 RUBY_FREE_UNLESS_NULL(iseq
->insn_info_table
);
62 RUBY_FREE_UNLESS_NULL(iseq
->local_table
);
63 RUBY_FREE_UNLESS_NULL(iseq
->catch_table
);
64 RUBY_FREE_UNLESS_NULL(iseq
->arg_opt_table
);
65 compile_data_free(iseq
->compile_data
);
69 RUBY_FREE_LEAVE("iseq");
76 RUBY_MARK_ENTER("iseq");
80 RUBY_GC_INFO("%s @ %s\n", RSTRING_PTR(iseq
->name
), RSTRING_PTR(iseq
->filename
));
81 RUBY_MARK_UNLESS_NULL(iseq
->mark_ary
);
82 RUBY_MARK_UNLESS_NULL(iseq
->name
);
83 RUBY_MARK_UNLESS_NULL(iseq
->filename
);
84 RUBY_MARK_UNLESS_NULL((VALUE
)iseq
->cref_stack
);
85 RUBY_MARK_UNLESS_NULL(iseq
->klass
);
86 RUBY_MARK_UNLESS_NULL(iseq
->coverage
);
87 /* RUBY_MARK_UNLESS_NULL((VALUE)iseq->node); */
88 /* RUBY_MARK_UNLESS_NULL(iseq->cached_special_block); */
89 RUBY_MARK_UNLESS_NULL(iseq
->orig
);
91 if (iseq
->compile_data
!= 0) {
92 RUBY_MARK_UNLESS_NULL(iseq
->compile_data
->mark_ary
);
93 RUBY_MARK_UNLESS_NULL(iseq
->compile_data
->err_info
);
94 RUBY_MARK_UNLESS_NULL(iseq
->compile_data
->catch_table_ary
);
97 RUBY_MARK_LEAVE("iseq");
101 iseq_alloc(VALUE klass
)
106 obj
= Data_Make_Struct(klass
, rb_iseq_t
, iseq_mark
, iseq_free
, iseq
);
107 MEMZERO(iseq
, rb_iseq_t
, 1);
112 set_relation(rb_iseq_t
*iseq
, const VALUE parent
)
114 const int type
= iseq
->type
;
115 rb_thread_t
*th
= GET_THREAD();
117 /* set class nest stack */
118 if (type
== ISEQ_TYPE_TOP
) {
119 /* toplevel is private */
120 iseq
->cref_stack
= NEW_BLOCK(th
->top_wrapper
? th
->top_wrapper
: rb_cObject
);
121 iseq
->cref_stack
->nd_file
= 0;
122 iseq
->cref_stack
->nd_visi
= NOEX_PRIVATE
;
124 else if (type
== ISEQ_TYPE_METHOD
|| type
== ISEQ_TYPE_CLASS
) {
125 iseq
->cref_stack
= NEW_BLOCK(0); /* place holder */
126 iseq
->cref_stack
->nd_file
= 0;
128 else if (RTEST(parent
)) {
130 GetISeqPtr(parent
, piseq
);
131 iseq
->cref_stack
= piseq
->cref_stack
;
134 if (type
== ISEQ_TYPE_TOP
||
135 type
== ISEQ_TYPE_METHOD
|| type
== ISEQ_TYPE_CLASS
) {
136 iseq
->local_iseq
= iseq
;
138 else if (RTEST(parent
)) {
140 GetISeqPtr(parent
, piseq
);
141 iseq
->local_iseq
= piseq
->local_iseq
;
146 GetISeqPtr(parent
, piseq
);
147 iseq
->parent_iseq
= piseq
;
152 prepare_iseq_build(rb_iseq_t
*iseq
,
153 VALUE name
, VALUE filename
,
154 VALUE parent
, VALUE type
, VALUE block_opt
,
155 const rb_compile_option_t
*option
)
158 OBJ_FREEZE(filename
);
161 iseq
->filename
= filename
;
162 iseq
->defined_method_id
= 0;
163 iseq
->mark_ary
= rb_ary_new();
164 RBASIC(iseq
->mark_ary
)->klass
= 0;
168 iseq
->arg_block
= -1;
172 * iseq->special_block_builder = GC_GUARDED_PTR_REF(block_opt);
173 * iseq->cached_special_block_builder = 0;
174 * iseq->cached_special_block = 0;
177 iseq
->compile_data
= ALLOC(struct iseq_compile_data
);
178 MEMZERO(iseq
->compile_data
, struct iseq_compile_data
, 1);
179 iseq
->compile_data
->mark_ary
= rb_ary_new();
180 RBASIC(iseq
->compile_data
->mark_ary
)->klass
= 0;
182 iseq
->compile_data
->storage_head
= iseq
->compile_data
->storage_current
=
183 (struct iseq_compile_data_storage
*)
184 ALLOC_N(char, INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE
+
185 sizeof(struct iseq_compile_data_storage
));
187 iseq
->compile_data
->catch_table_ary
= rb_ary_new();
188 iseq
->compile_data
->storage_head
->pos
= 0;
189 iseq
->compile_data
->storage_head
->next
= 0;
190 iseq
->compile_data
->storage_head
->size
=
191 INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE
;
192 iseq
->compile_data
->storage_head
->buff
=
193 (char *)(&iseq
->compile_data
->storage_head
->buff
+ 1);
194 iseq
->compile_data
->option
= option
;
196 set_relation(iseq
, parent
);
198 iseq
->coverage
= Qfalse
;
199 if (!GET_THREAD()->parse_in_eval
) {
200 extern VALUE
rb_get_coverages(void);
201 VALUE coverages
= rb_get_coverages();
202 if (RTEST(coverages
)) {
203 iseq
->coverage
= rb_hash_lookup(coverages
, filename
);
204 if (NIL_P(iseq
->coverage
)) iseq
->coverage
= Qfalse
;
212 cleanup_iseq_build(rb_iseq_t
*iseq
)
214 struct iseq_compile_data
*data
= iseq
->compile_data
;
215 VALUE err
= data
->err_info
;
216 iseq
->compile_data
= 0;
217 compile_data_free(data
);
220 rb_funcall2(err
, rb_intern("set_backtrace"), 1, &iseq
->filename
);
226 static rb_compile_option_t COMPILE_OPTION_DEFAULT
= {
227 OPT_INLINE_CONST_CACHE
, /* int inline_const_cache; */
228 OPT_PEEPHOLE_OPTIMIZATION
, /* int peephole_optimization; */
229 OPT_TAILCALL_OPTIMIZATION
, /* int tailcall_optimization */
230 OPT_SPECIALISED_INSTRUCTION
, /* int specialized_instruction; */
231 OPT_OPERANDS_UNIFICATION
, /* int operands_unification; */
232 OPT_INSTRUCTIONS_UNIFICATION
, /* int instructions_unification; */
233 OPT_STACK_CACHING
, /* int stack_caching; */
234 OPT_TRACE_INSTRUCTION
, /* int trace_instruction */
236 static const rb_compile_option_t COMPILE_OPTION_FALSE
= {0};
239 make_compile_option(rb_compile_option_t
*option
, VALUE opt
)
242 *option
= COMPILE_OPTION_DEFAULT
;
244 else if (opt
== Qfalse
) {
245 *option
= COMPILE_OPTION_FALSE
;
247 else if (opt
== Qtrue
) {
248 memset(option
, 1, sizeof(rb_compile_option_t
));
250 else if (CLASS_OF(opt
) == rb_cHash
) {
251 *option
= COMPILE_OPTION_DEFAULT
;
253 #define SET_COMPILE_OPTION(o, h, mem) \
254 { VALUE flag = rb_hash_aref(h, ID2SYM(rb_intern(#mem))); \
255 if (flag == Qtrue) { o->mem = 1; } \
256 else if (flag == Qfalse) { o->mem = 0; } \
258 #define SET_COMPILE_OPTION_NUM(o, h, mem) \
259 { VALUE num = rb_hash_aref(opt, ID2SYM(rb_intern(#mem))); \
260 if (!NIL_P(num)) o->mem = NUM2INT(num); \
262 SET_COMPILE_OPTION(option
, opt
, inline_const_cache
);
263 SET_COMPILE_OPTION(option
, opt
, peephole_optimization
);
264 SET_COMPILE_OPTION(option
, opt
, tailcall_optimization
);
265 SET_COMPILE_OPTION(option
, opt
, specialized_instruction
);
266 SET_COMPILE_OPTION(option
, opt
, operands_unification
);
267 SET_COMPILE_OPTION(option
, opt
, instructions_unification
);
268 SET_COMPILE_OPTION(option
, opt
, stack_caching
);
269 SET_COMPILE_OPTION(option
, opt
, trace_instruction
);
270 SET_COMPILE_OPTION_NUM(option
, opt
, debug_level
);
271 #undef SET_COMPILE_OPTION
272 #undef SET_COMPILE_OPTION_NUM
275 rb_raise(rb_eTypeError
, "Compile option must be Hash/true/false/nil");
280 make_compile_option_value(rb_compile_option_t
*option
)
282 VALUE opt
= rb_hash_new();
283 #define SET_COMPILE_OPTION(o, h, mem) \
284 rb_hash_aset(h, ID2SYM(rb_intern(#mem)), o->mem ? Qtrue : Qfalse)
285 #define SET_COMPILE_OPTION_NUM(o, h, mem) \
286 rb_hash_aset(h, ID2SYM(rb_intern(#mem)), INT2NUM(o->mem))
288 SET_COMPILE_OPTION(option
, opt
, inline_const_cache
);
289 SET_COMPILE_OPTION(option
, opt
, peephole_optimization
);
290 SET_COMPILE_OPTION(option
, opt
, tailcall_optimization
);
291 SET_COMPILE_OPTION(option
, opt
, specialized_instruction
);
292 SET_COMPILE_OPTION(option
, opt
, operands_unification
);
293 SET_COMPILE_OPTION(option
, opt
, instructions_unification
);
294 SET_COMPILE_OPTION(option
, opt
, stack_caching
);
295 SET_COMPILE_OPTION_NUM(option
, opt
, debug_level
);
297 #undef SET_COMPILE_OPTION
298 #undef SET_COMPILE_OPTION_NUM
303 rb_iseq_new(NODE
*node
, VALUE name
, VALUE filename
,
304 VALUE parent
, VALUE type
)
306 return rb_iseq_new_with_opt(node
, name
, filename
, parent
, type
,
307 &COMPILE_OPTION_DEFAULT
);
311 rb_iseq_new_with_bopt_and_opt(NODE
*node
, VALUE name
, VALUE filename
,
312 VALUE parent
, VALUE type
, VALUE bopt
,
313 const rb_compile_option_t
*option
)
316 VALUE self
= iseq_alloc(rb_cISeq
);
318 GetISeqPtr(self
, iseq
);
321 prepare_iseq_build(iseq
, name
, filename
, parent
, type
, bopt
, option
);
322 iseq_compile(self
, node
);
323 cleanup_iseq_build(iseq
);
328 rb_iseq_new_with_opt(NODE
*node
, VALUE name
, VALUE filename
,
329 VALUE parent
, VALUE type
,
330 const rb_compile_option_t
*option
)
332 return rb_iseq_new_with_bopt_and_opt(node
, name
, filename
, parent
, type
,
337 rb_iseq_new_with_bopt(NODE
*node
, VALUE name
, VALUE filename
,
338 VALUE parent
, VALUE type
, VALUE bopt
)
340 return rb_iseq_new_with_bopt_and_opt(node
, name
, filename
, parent
, type
,
341 bopt
, &COMPILE_OPTION_DEFAULT
);
344 VALUE
iseq_build_from_ary(rb_iseq_t
*iseq
, VALUE locals
, VALUE args
,
345 VALUE exception
, VALUE body
);
347 #define CHECK_ARRAY(v) rb_convert_type(v, T_ARRAY, "Array", "to_ary")
348 #define CHECK_STRING(v) rb_convert_type(v, T_STRING, "String", "to_str")
349 #define CHECK_SYMBOL(v) rb_convert_type(v, T_SYMBOL, "Symbol", "to_sym")
350 static inline VALUE
CHECK_INTEGER(VALUE v
) {NUM2LONG(v
); return v
;}
352 iseq_load(VALUE self
, VALUE data
, VALUE parent
, VALUE opt
)
354 VALUE iseqval
= iseq_alloc(rb_cISeq
);
356 VALUE magic
, version1
, version2
, format_type
, misc
;
357 VALUE name
, filename
;
358 VALUE type
, body
, locals
, args
, exception
;
361 struct st_table
*type_map
= 0;
363 rb_compile_option_t option
;
366 /* [magic, major_version, minor_version, format_type, misc,
368 * type, locals, args, exception_table, body]
371 data
= CHECK_ARRAY(data
);
373 magic
= CHECK_STRING(rb_ary_entry(data
, i
++));
374 version1
= CHECK_INTEGER(rb_ary_entry(data
, i
++));
375 version2
= CHECK_INTEGER(rb_ary_entry(data
, i
++));
376 format_type
= CHECK_INTEGER(rb_ary_entry(data
, i
++));
377 misc
= rb_ary_entry(data
, i
++); /* TODO */
379 name
= CHECK_STRING(rb_ary_entry(data
, i
++));
380 filename
= CHECK_STRING(rb_ary_entry(data
, i
++));
382 type
= CHECK_SYMBOL(rb_ary_entry(data
, i
++));
383 locals
= CHECK_ARRAY(rb_ary_entry(data
, i
++));
385 args
= rb_ary_entry(data
, i
++);
386 if (FIXNUM_P(args
) || (args
= CHECK_ARRAY(args
))) {
390 exception
= CHECK_ARRAY(rb_ary_entry(data
, i
++));
391 body
= CHECK_ARRAY(rb_ary_entry(data
, i
++));
393 GetISeqPtr(iseqval
, iseq
);
394 iseq
->self
= iseqval
;
397 type_map
= st_init_numtable();
398 st_insert(type_map
, ID2SYM(rb_intern("top")), ISEQ_TYPE_TOP
);
399 st_insert(type_map
, ID2SYM(rb_intern("method")), ISEQ_TYPE_METHOD
);
400 st_insert(type_map
, ID2SYM(rb_intern("block")), ISEQ_TYPE_BLOCK
);
401 st_insert(type_map
, ID2SYM(rb_intern("class")), ISEQ_TYPE_CLASS
);
402 st_insert(type_map
, ID2SYM(rb_intern("rescue")), ISEQ_TYPE_RESCUE
);
403 st_insert(type_map
, ID2SYM(rb_intern("ensure")), ISEQ_TYPE_ENSURE
);
404 st_insert(type_map
, ID2SYM(rb_intern("eval")), ISEQ_TYPE_EVAL
);
405 st_insert(type_map
, ID2SYM(rb_intern("defined_guard")), ISEQ_TYPE_DEFINED_GUARD
);
408 if (st_lookup(type_map
, type
, &iseq_type
) == 0) {
409 const char *typename
= rb_id2name(type
);
411 rb_raise(rb_eTypeError
, "unsupport type: :%s", typename
);
413 rb_raise(rb_eTypeError
, "unsupport type: %p", (void *)type
);
416 if (parent
== Qnil
) {
420 make_compile_option(&option
, opt
);
421 prepare_iseq_build(iseq
, name
, filename
,
422 parent
, iseq_type
, 0, &option
);
424 iseq_build_from_ary(iseq
, locals
, args
, exception
, body
);
426 cleanup_iseq_build(iseq
);
431 iseq_s_load(int argc
, VALUE
*argv
, VALUE self
)
433 VALUE data
, opt
=Qnil
;
434 rb_scan_args(argc
, argv
, "11", &data
, &opt
);
436 return iseq_load(self
, data
, 0, opt
);
440 compile_string(VALUE str
, VALUE file
, VALUE line
)
442 VALUE parser
= rb_parser_new();
443 NODE
*node
= rb_parser_compile_string(parser
, StringValueCStr(file
),
447 rb_exc_raise(GET_THREAD()->errinfo
); /* TODO: check err */
453 rb_iseq_compile_with_option(VALUE src
, VALUE file
, VALUE line
, VALUE opt
)
455 rb_compile_option_t option
;
456 NODE
*node
= compile_string(StringValue(src
), file
, line
);
457 rb_thread_t
*th
= GET_THREAD();
458 make_compile_option(&option
, opt
);
460 if (th
->base_block
&& th
->base_block
->iseq
) {
461 return rb_iseq_new_with_opt(node
, th
->base_block
->iseq
->name
,
462 file
, th
->base_block
->iseq
->self
,
463 ISEQ_TYPE_EVAL
, &option
);
466 return rb_iseq_new_with_opt(node
, rb_str_new2("<compiled>"), file
, Qfalse
,
467 ISEQ_TYPE_TOP
, &option
);
472 rb_iseq_compile(VALUE src
, VALUE file
, VALUE line
)
474 return rb_iseq_compile_with_option(src
, file
, line
, Qnil
);
478 iseq_s_compile(int argc
, VALUE
*argv
, VALUE self
)
480 VALUE src
, file
= Qnil
, line
= INT2FIX(1), opt
= Qnil
;
484 rb_scan_args(argc
, argv
, "13", &src
, &file
, &line
, &opt
);
485 file
= file
== Qnil
? rb_str_new2("<compiled>") : file
;
486 line
= line
== Qnil
? INT2FIX(1) : line
;
488 return rb_iseq_compile_with_option(src
, file
, line
, opt
);
492 iseq_s_compile_file(int argc
, VALUE
*argv
, VALUE self
)
494 VALUE file
, line
= INT2FIX(1), opt
= Qnil
;
499 rb_compile_option_t option
;
502 rb_scan_args(argc
, argv
, "11", &file
, &opt
);
503 fname
= StringValueCStr(file
);
505 f
= rb_file_open(fname
, "r");
507 parser
= rb_parser_new();
508 node
= rb_parser_compile_file(parser
, fname
, f
, NUM2INT(line
));
509 make_compile_option(&option
, opt
);
510 return rb_iseq_new_with_opt(node
, rb_str_new2("<main>"), file
, Qfalse
,
511 ISEQ_TYPE_TOP
, &option
);
515 iseq_s_compile_option_set(VALUE self
, VALUE opt
)
517 rb_compile_option_t option
;
519 make_compile_option(&option
, opt
);
520 COMPILE_OPTION_DEFAULT
= option
;
525 iseq_s_compile_option_get(VALUE self
)
527 return make_compile_option_value(&COMPILE_OPTION_DEFAULT
);
531 iseq_check(VALUE val
)
534 GetISeqPtr(val
, iseq
);
536 rb_raise(rb_eTypeError
, "uninitialized InstructionSequence");
542 iseq_eval(VALUE self
)
545 return rb_iseq_eval(self
);
549 iseq_inspect(VALUE self
)
551 rb_iseq_t
*iseq
= iseq_check(self
);
553 return rb_sprintf("<ISeq:%s@%s>",
554 RSTRING_PTR(iseq
->name
), RSTRING_PTR(iseq
->filename
));
557 VALUE
iseq_data_to_ary(rb_iseq_t
*iseq
);
560 iseq_to_a(VALUE self
)
562 rb_iseq_t
*iseq
= iseq_check(self
);
564 return iseq_data_to_ary(iseq
);
567 /* TODO: search algorithm is brute force.
568 this should be binary search or so. */
570 static struct iseq_insn_info_entry
*
571 get_insn_info(const rb_iseq_t
*iseq
, const unsigned long pos
)
573 unsigned long i
, size
= iseq
->insn_info_size
;
574 struct iseq_insn_info_entry
*table
= iseq
->insn_info_table
;
576 for (i
= 0; i
< size
; i
++) {
577 if (table
[i
].position
== pos
) {
585 static unsigned short
586 find_line_no(rb_iseq_t
*iseq
, unsigned long pos
)
588 struct iseq_insn_info_entry
*entry
= get_insn_info(iseq
, pos
);
590 return entry
->line_no
;
597 static unsigned short
598 find_prev_line_no(rb_iseq_t
*iseqdat
, unsigned long pos
)
600 unsigned long i
, size
= iseqdat
->insn_info_size
;
601 struct iseq_insn_info_entry
*iiary
= iseqdat
->insn_info_table
;
603 for (i
= 0; i
< size
; i
++) {
604 if (iiary
[i
].position
== pos
) {
606 return iiary
[i
- 1].line_no
;
618 insn_operand_intern(rb_iseq_t
*iseq
,
619 int insn
, int op_no
, VALUE op
,
620 int len
, int pos
, VALUE
*pnop
, VALUE child
)
622 const char *types
= insn_op_types(insn
);
623 char type
= types
[op_no
];
627 case TS_OFFSET
: /* LONG */
628 ret
= rb_sprintf("%ld", pos
+ len
+ op
);
631 case TS_NUM
: /* ULONG */
632 ret
= rb_sprintf("%lu", op
);
637 rb_iseq_t
*ip
= iseq
->local_iseq
;
638 int lidx
= ip
->local_size
- op
;
639 const char *name
= rb_id2name(ip
->local_table
[lidx
]);
642 ret
= rb_str_new2(name
);
645 ret
= rb_str_new2("*");
650 if (insn
== BIN(getdynamic
) || insn
== BIN(setdynamic
)) {
651 rb_iseq_t
*ip
= iseq
;
652 int level
= *pnop
, i
;
654 for (i
= 0; i
< level
; i
++) {
655 ip
= ip
->parent_iseq
;
657 name
= rb_id2name(ip
->local_table
[ip
->local_size
- op
]);
662 ret
= rb_str_new2(name
);
665 ret
= rb_inspect(INT2FIX(op
));
669 case TS_ID
: /* ID (symbol) */
672 case TS_VALUE
: /* VALUE */
673 ret
= rb_inspect(op
);
674 if (CLASS_OF(op
) == rb_cISeq
) {
675 rb_ary_push(child
, op
);
679 case TS_ISEQ
: /* iseq */
681 rb_iseq_t
*iseq
= (rb_iseq_t
*)op
;
685 rb_ary_push(child
, iseq
->self
);
689 ret
= rb_str_new2("nil");
695 struct global_entry
*entry
= (struct global_entry
*)op
;
696 ret
= rb_str_dup(rb_id2str(entry
->id
));
701 ret
= rb_str_new2("<ic>");
705 ret
= rb_str_new2("<cdhash>");
709 ret
= rb_str_new2("<funcptr>");
713 rb_bug("ruby_iseq_disasm: unknown operand type: %c", type
);
719 * Disassemble a instruction
720 * Iseq -> Iseq inspect object
723 ruby_iseq_disasm_insn(VALUE ret
, VALUE
*iseq
, int pos
,
724 rb_iseq_t
*iseqdat
, VALUE child
)
726 int insn
= iseq
[pos
];
727 int len
= insn_len(insn
);
729 const char *types
= insn_op_types(insn
);
730 VALUE str
= rb_str_new(0, 0);
731 const char *insn_name_buff
;
733 insn_name_buff
= insn_name(insn
);
735 rb_str_catf(str
, "%04d %-16s ", pos
, insn_name_buff
);
738 rb_str_catf(str
, "%04d %-16.*s ", pos
,
739 (int)strcspn(insn_name_buff
, "_"), insn_name_buff
);
742 for (j
= 0; types
[j
]; j
++) {
743 const char *types
= insn_op_types(insn
);
744 VALUE opstr
= insn_operand_intern(iseqdat
, insn
, j
, iseq
[pos
+ j
+ 1],
745 len
, pos
, &iseq
[pos
+ j
+ 2],
747 rb_str_concat(str
, opstr
);
750 rb_str_cat2(str
, ", ");
755 int line_no
= find_line_no(iseqdat
, pos
);
756 int prev
= find_prev_line_no(iseqdat
, pos
);
757 if (line_no
&& line_no
!= prev
) {
758 long slen
= RSTRING_LEN(str
);
759 slen
= (slen
> 70) ? 0 : (70 - slen
);
760 str
= rb_str_catf(str
, "%*s(%4d)", (int)slen
, "", line_no
);
765 struct iseq_insn_info_entry
*entry
= get_insn_info(iseqdat
, pos
);
766 long slen
= RSTRING_LEN(str
);
767 slen
= (slen
> 60) ? 0 : (60 - slen
);
768 str
= rb_str_catf(str
, "%*s(line: %d, sp: %d)",
769 (int)slen
, "", entry
->line_no
, entry
->sp
);
773 rb_str_cat2(str
, "\n");
774 rb_str_concat(ret
, str
);
777 printf("%s\n", RSTRING_PTR(str
));
786 case CATCH_TYPE_RESCUE
:
788 case CATCH_TYPE_ENSURE
:
790 case CATCH_TYPE_RETRY
:
792 case CATCH_TYPE_BREAK
:
794 case CATCH_TYPE_REDO
:
796 case CATCH_TYPE_NEXT
:
799 rb_bug("unknown catch type (%d)", type
);
805 ruby_iseq_disasm(VALUE self
)
807 rb_iseq_t
*iseqdat
= iseq_check(self
);
809 VALUE str
= rb_str_new(0, 0);
810 VALUE child
= rb_ary_new();
814 enum {header_minlen
= 72};
818 iseq
= iseqdat
->iseq
;
819 size
= iseqdat
->iseq_size
;
821 rb_str_cat2(str
, "== disasm: ");
823 rb_str_concat(str
, iseq_inspect(iseqdat
->self
));
824 if ((i
= RSTRING_LEN(str
)) < header_minlen
) {
825 rb_str_resize(str
, header_minlen
);
826 memset(RSTRING_PTR(str
) + i
, '=', header_minlen
- i
);
828 rb_str_cat2(str
, "\n");
830 /* show catch table information */
831 if (iseqdat
->catch_table_size
!= 0) {
832 rb_str_cat2(str
, "== catch table\n");
834 for (i
= 0; i
< iseqdat
->catch_table_size
; i
++) {
835 struct iseq_catch_table_entry
*entry
= &iseqdat
->catch_table
[i
];
837 "| catch type: %-6s st: %04d ed: %04d sp: %04d cont: %04d\n",
838 catch_type((int)entry
->type
), (int)entry
->start
,
839 (int)entry
->end
, (int)entry
->sp
, (int)entry
->cont
);
841 rb_str_concat(str
, ruby_iseq_disasm(entry
->iseq
));
844 if (iseqdat
->catch_table_size
!= 0) {
845 rb_str_cat2(str
, "|-------------------------------------"
846 "-----------------------------------\n");
849 /* show local table information */
850 tbl
= iseqdat
->local_table
;
854 "local table (size: %d, argc: %d "
855 "[opts: %d, rest: %d, post: %d, block: %d] s%d)\n",
856 iseqdat
->local_size
, iseqdat
->argc
,
857 iseqdat
->arg_opts
, iseqdat
->arg_rest
,
858 iseqdat
->arg_post_len
, iseqdat
->arg_block
,
859 iseqdat
->arg_simple
);
861 for (i
= 0; i
< iseqdat
->local_table_size
; i
++) {
862 const char *name
= rb_id2name(tbl
[i
]);
864 char argi
[0x100] = "";
865 char opti
[0x100] = "";
867 if (iseqdat
->arg_opts
) {
868 int argc
= iseqdat
->argc
;
869 int opts
= iseqdat
->arg_opts
;
870 if (i
>= argc
&& i
< argc
+ opts
- 1) {
871 snprintf(opti
, sizeof(opti
), "Opt=%ld",
872 iseqdat
->arg_opt_table
[i
- argc
]);
876 snprintf(argi
, sizeof(argi
), "%s%s%s%s%s", /* arg, opts, rest, post block */
877 iseqdat
->argc
> i
? "Arg" : "",
879 iseqdat
->arg_rest
== i
? "Rest" : "",
880 (iseqdat
->arg_post_start
<= i
&&
881 i
< iseqdat
->arg_post_start
+ iseqdat
->arg_post_len
) ? "Post" : "",
882 iseqdat
->arg_block
== i
? "Block" : "");
884 snprintf(info
, sizeof(info
), "%s%s%s%s", name
? name
: "?",
885 *argi
? "<" : "", argi
, *argi
? ">" : "");
887 rb_str_catf(str
, "[%2d] %-11s", iseqdat
->local_size
- i
, info
);
889 rb_str_cat2(str
, "\n");
893 for (i
= 0; i
< size
;) {
894 i
+= ruby_iseq_disasm_insn(str
, iseq
, i
, iseqdat
, child
);
897 for (i
= 0; i
< RARRAY_LEN(child
); i
++) {
898 VALUE isv
= rb_ary_entry(child
, i
);
899 rb_str_concat(str
, ruby_iseq_disasm(isv
));
906 iseq_s_disasm(VALUE klass
, VALUE body
)
908 extern NODE
*rb_method_body(VALUE body
);
914 if ((node
= rb_method_body(body
)) != 0) {
915 if (nd_type(node
) == RUBY_VM_METHOD_NODE
) {
916 VALUE iseqval
= (VALUE
)node
->nd_body
;
917 ret
= ruby_iseq_disasm(iseqval
);
925 ruby_node_name(int node
)
928 #include "node_name.inc"
930 rb_bug("unknown node (%d)", node
);
935 #define DECL_SYMBOL(name) \
936 static VALUE sym_##name
938 #define INIT_SYMBOL(name) \
939 sym_##name = ID2SYM(rb_intern(#name))
942 register_label(struct st_table
*table
, int idx
)
945 char buff
[8 + (sizeof(idx
) * CHAR_BIT
* 32 / 100)];
947 snprintf(buff
, sizeof(buff
), "label_%u", idx
);
948 sym
= ID2SYM(rb_intern(buff
));
949 st_insert(table
, idx
, sym
);
954 exception_type2symbol(VALUE type
)
958 case CATCH_TYPE_RESCUE
: CONST_ID(id
, "rescue"); break;
959 case CATCH_TYPE_ENSURE
: CONST_ID(id
, "ensure"); break;
960 case CATCH_TYPE_RETRY
: CONST_ID(id
, "retry"); break;
961 case CATCH_TYPE_BREAK
: CONST_ID(id
, "break"); break;
962 case CATCH_TYPE_REDO
: CONST_ID(id
, "redo"); break;
963 case CATCH_TYPE_NEXT
: CONST_ID(id
, "next"); break;
971 cdhash_each(VALUE key
, VALUE value
, VALUE ary
)
973 rb_ary_push(ary
, key
);
974 rb_ary_push(ary
, value
);
979 iseq_data_to_ary(rb_iseq_t
*iseq
)
981 int i
, pos
, line
= 0;
984 VALUE val
= rb_ary_new();
985 VALUE type
; /* Symbol */
986 VALUE locals
= rb_ary_new();
987 VALUE args
= rb_ary_new();
988 VALUE body
= rb_ary_new(); /* [[:insn1, ...], ...] */
990 VALUE exception
= rb_ary_new(); /* [[....]] */
991 VALUE misc
= rb_hash_new();
993 static VALUE insn_syms
[VM_INSTRUCTION_SIZE
];
994 struct st_table
*labels_table
= st_init_numtable();
1000 DECL_SYMBOL(rescue
);
1001 DECL_SYMBOL(ensure
);
1003 DECL_SYMBOL(defined_guard
);
1007 for (i
=0; i
<VM_INSTRUCTION_SIZE
; i
++) {
1008 insn_syms
[i
] = ID2SYM(rb_intern(insn_name(i
)));
1011 INIT_SYMBOL(method
);
1014 INIT_SYMBOL(rescue
);
1015 INIT_SYMBOL(ensure
);
1017 INIT_SYMBOL(defined_guard
);
1021 switch(iseq
->type
) {
1022 case ISEQ_TYPE_TOP
: type
= sym_top
; break;
1023 case ISEQ_TYPE_METHOD
: type
= sym_method
; break;
1024 case ISEQ_TYPE_BLOCK
: type
= sym_block
; break;
1025 case ISEQ_TYPE_CLASS
: type
= sym_class
; break;
1026 case ISEQ_TYPE_RESCUE
: type
= sym_rescue
; break;
1027 case ISEQ_TYPE_ENSURE
: type
= sym_ensure
; break;
1028 case ISEQ_TYPE_EVAL
: type
= sym_eval
; break;
1029 case ISEQ_TYPE_DEFINED_GUARD
: type
= sym_defined_guard
; break;
1030 default: rb_bug("unsupported iseq type");
1034 for (i
=0; i
<iseq
->local_table_size
; i
++) {
1035 ID lid
= iseq
->local_table
[i
];
1037 if (rb_id2str(lid
)) rb_ary_push(locals
, ID2SYM(lid
));
1040 rb_ary_push(locals
, ID2SYM(rb_intern("#arg_rest")));
1048 * [label1, label2, ...] # opts
1056 VALUE arg_opt_labels
= rb_ary_new();
1059 for (j
=0; j
<iseq
->arg_opts
; j
++) {
1060 rb_ary_push(arg_opt_labels
,
1061 register_label(labels_table
, iseq
->arg_opt_table
[j
]));
1065 if (iseq
->arg_simple
== 1) {
1066 args
= INT2FIX(iseq
->argc
);
1069 rb_ary_push(args
, INT2FIX(iseq
->argc
));
1070 rb_ary_push(args
, arg_opt_labels
);
1071 rb_ary_push(args
, INT2FIX(iseq
->arg_post_len
));
1072 rb_ary_push(args
, INT2FIX(iseq
->arg_post_start
));
1073 rb_ary_push(args
, INT2FIX(iseq
->arg_rest
));
1074 rb_ary_push(args
, INT2FIX(iseq
->arg_block
));
1075 rb_ary_push(args
, INT2FIX(iseq
->arg_simple
));
1080 for (seq
= iseq
->iseq
; seq
< iseq
->iseq
+ iseq
->iseq_size
; ) {
1081 VALUE insn
= *seq
++;
1082 int j
, len
= insn_len(insn
);
1083 VALUE
*nseq
= seq
+ len
- 1;
1084 VALUE ary
= rb_ary_new2(len
);
1086 rb_ary_push(ary
, insn_syms
[insn
]);
1087 for (j
=0; j
<len
-1; j
++, seq
++) {
1088 switch (insn_op_type(insn
, j
)) {
1090 unsigned int idx
= nseq
- iseq
->iseq
+ *seq
;
1091 rb_ary_push(ary
, register_label(labels_table
, idx
));
1097 rb_ary_push(ary
, INT2FIX(*seq
));
1100 rb_ary_push(ary
, *seq
);
1104 rb_iseq_t
*iseq
= (rb_iseq_t
*)*seq
;
1106 VALUE val
= iseq_data_to_ary(iseq
);
1107 rb_ary_push(ary
, val
);
1110 rb_ary_push(ary
, Qnil
);
1116 struct global_entry
*entry
= (struct global_entry
*)*seq
;
1117 rb_ary_push(ary
, ID2SYM(entry
->id
));
1121 rb_ary_push(ary
, Qnil
);
1124 rb_ary_push(ary
, ID2SYM(*seq
));
1129 VALUE val
= rb_ary_new();
1132 rb_hash_foreach(hash
, cdhash_each
, val
);
1134 for (i
=0; i
<RARRAY_LEN(val
); i
+=2) {
1135 VALUE pos
= FIX2INT(rb_ary_entry(val
, i
+1));
1136 unsigned int idx
= nseq
- iseq
->iseq
+ pos
;
1138 rb_ary_store(val
, i
+1,
1139 register_label(labels_table
, idx
));
1141 rb_ary_push(ary
, val
);
1145 rb_bug("unknown operand: %c", insn_op_type(insn
, j
));
1148 rb_ary_push(body
, ary
);
1154 for (i
=0; i
<iseq
->catch_table_size
; i
++) {
1155 VALUE ary
= rb_ary_new();
1156 struct iseq_catch_table_entry
*entry
= &iseq
->catch_table
[i
];
1157 rb_ary_push(ary
, exception_type2symbol(entry
->type
));
1160 GetISeqPtr(entry
->iseq
, eiseq
);
1161 rb_ary_push(ary
, iseq_data_to_ary(eiseq
));
1164 rb_ary_push(ary
, Qnil
);
1166 rb_ary_push(ary
, register_label(labels_table
, entry
->start
));
1167 rb_ary_push(ary
, register_label(labels_table
, entry
->end
));
1168 rb_ary_push(ary
, register_label(labels_table
, entry
->cont
));
1169 rb_ary_push(ary
, INT2FIX(entry
->sp
));
1170 rb_ary_push(exception
, ary
);
1173 /* make body with labels and insert line number */
1174 body
= rb_ary_new();
1176 for (i
=0, pos
=0; i
<RARRAY_LEN(nbody
); i
++) {
1177 VALUE ary
= RARRAY_PTR(nbody
)[i
];
1180 if (st_lookup(labels_table
, pos
, &label
)) {
1181 rb_ary_push(body
, label
);
1184 if (iseq
->insn_info_table
[i
].line_no
!= line
) {
1185 line
= iseq
->insn_info_table
[i
].line_no
;
1186 rb_ary_push(body
, INT2FIX(line
));
1189 rb_ary_push(body
, ary
);
1190 pos
+= RARRAY_LEN(ary
);
1193 st_free_table(labels_table
);
1195 rb_hash_aset(misc
, ID2SYM(rb_intern("arg_size")), INT2FIX(iseq
->arg_size
));
1196 rb_hash_aset(misc
, ID2SYM(rb_intern("local_size")), INT2FIX(iseq
->local_size
));
1197 rb_hash_aset(misc
, ID2SYM(rb_intern("stack_max")), INT2FIX(iseq
->stack_max
));
1200 * [:magic, :major_version, :minor_version, :format_type, :misc,
1201 * :name, :filename, :type, :locals, :args,
1202 * :catch_table, :bytecode]
1204 rb_ary_push(val
, rb_str_new2("YARVInstructionSequence/SimpleDataFormat"));
1205 rb_ary_push(val
, INT2FIX(1));
1206 rb_ary_push(val
, INT2FIX(1));
1207 rb_ary_push(val
, INT2FIX(1));
1208 rb_ary_push(val
, misc
);
1209 rb_ary_push(val
, iseq
->name
);
1210 rb_ary_push(val
, iseq
->filename
);
1211 rb_ary_push(val
, type
);
1212 rb_ary_push(val
, locals
);
1213 rb_ary_push(val
, args
);
1214 rb_ary_push(val
, exception
);
1215 rb_ary_push(val
, body
);
1220 insn_make_insn_table(void)
1222 struct st_table
*table
;
1224 table
= st_init_numtable();
1226 for (i
=0; i
<VM_INSTRUCTION_SIZE
; i
++) {
1227 st_insert(table
, ID2SYM(rb_intern(insn_name(i
))), i
);
1234 rb_iseq_clone(VALUE iseqval
, VALUE newcbase
)
1236 VALUE newiseq
= iseq_alloc(rb_cISeq
);
1237 rb_iseq_t
*iseq0
, *iseq1
;
1239 GetISeqPtr(iseqval
, iseq0
);
1240 GetISeqPtr(newiseq
, iseq1
);
1243 iseq1
->self
= newiseq
;
1245 iseq1
->orig
= iseqval
;
1248 iseq1
->cref_stack
= NEW_BLOCK(newcbase
);
1249 if (iseq0
->cref_stack
->nd_next
) {
1250 iseq1
->cref_stack
->nd_next
= iseq0
->cref_stack
->nd_next
;
1260 rb_iseq_build_for_ruby2cext(
1261 const rb_iseq_t
*iseq_template
,
1262 const rb_insn_func_t
*func
,
1263 const struct iseq_insn_info_entry
*insn_info_table
,
1264 const char **local_table
,
1265 const VALUE
*arg_opt_table
,
1266 const struct iseq_catch_table_entry
*catch_table
,
1268 const char *filename
)
1271 VALUE iseqval
= iseq_alloc(rb_cISeq
);
1273 GetISeqPtr(iseqval
, iseq
);
1276 *iseq
= *iseq_template
;
1277 iseq
->name
= rb_str_new2(name
);
1278 iseq
->filename
= rb_str_new2(filename
);
1279 iseq
->mark_ary
= rb_ary_new();
1280 iseq
->self
= iseqval
;
1282 iseq
->iseq
= ALLOC_N(VALUE
, iseq
->iseq_size
);
1284 for (i
=0; i
<iseq
->iseq_size
; i
+=2) {
1285 iseq
->iseq
[i
] = BIN(opt_call_c_function
);
1286 iseq
->iseq
[i
+1] = (VALUE
)func
;
1289 iseq_translate_threaded_code(iseq
);
1291 #define ALLOC_AND_COPY(dst, src, type, size) do { \
1293 (dst) = ALLOC_N(type, (size)); \
1294 MEMCPY((dst), (src), type, (size)); \
1298 ALLOC_AND_COPY(iseq
->insn_info_table
, insn_info_table
,
1299 struct iseq_insn_info_entry
, iseq
->insn_info_size
);
1301 ALLOC_AND_COPY(iseq
->catch_table
, catch_table
,
1302 struct iseq_catch_table_entry
, iseq
->catch_table_size
);
1304 ALLOC_AND_COPY(iseq
->arg_opt_table
, arg_opt_table
,
1305 VALUE
, iseq
->arg_opts
);
1307 set_relation(iseq
, 0);
1315 /* declare ::VM::InstructionSequence */
1316 rb_cISeq
= rb_define_class_under(rb_cRubyVM
, "InstructionSequence", rb_cObject
);
1317 rb_define_alloc_func(rb_cISeq
, iseq_alloc
);
1318 rb_define_method(rb_cISeq
, "inspect", iseq_inspect
, 0);
1319 rb_define_method(rb_cISeq
, "disasm", ruby_iseq_disasm
, 0);
1320 rb_define_method(rb_cISeq
, "disassemble", ruby_iseq_disasm
, 0);
1321 rb_define_method(rb_cISeq
, "to_a", iseq_to_a
, 0);
1322 rb_define_method(rb_cISeq
, "eval", iseq_eval
, 0);
1324 /* disable this feature because there is no verifier. */
1325 /* rb_define_singleton_method(rb_cISeq, "load", iseq_s_load, -1); */
1328 rb_define_singleton_method(rb_cISeq
, "compile", iseq_s_compile
, -1);
1329 rb_define_singleton_method(rb_cISeq
, "new", iseq_s_compile
, -1);
1330 rb_define_singleton_method(rb_cISeq
, "compile_file", iseq_s_compile_file
, -1);
1331 rb_define_singleton_method(rb_cISeq
, "compile_option", iseq_s_compile_option_get
, 0);
1332 rb_define_singleton_method(rb_cISeq
, "compile_option=", iseq_s_compile_option_set
, 1);
1333 rb_define_singleton_method(rb_cISeq
, "disasm", iseq_s_disasm
, 1);
1334 rb_define_singleton_method(rb_cISeq
, "disassemble", iseq_s_disasm
, 1);