1 /**********************************************************************
6 created at: 2006-07-11(Tue) 09:00:03 +0900
8 Copyright (C) 2006 Koichi Sasada
10 **********************************************************************/
12 #define RUBY_VM_INSNS_INFO 1
13 /* #define RUBY_MARK_FREE_DEBUG 1 */
15 #include "ruby/internal/config.h"
21 #include "eval_intern.h"
24 #include "internal/bits.h"
25 #include "internal/class.h"
26 #include "internal/compile.h"
27 #include "internal/error.h"
28 #include "internal/file.h"
29 #include "internal/gc.h"
30 #include "internal/hash.h"
31 #include "internal/parse.h"
32 #include "internal/sanitizers.h"
33 #include "internal/symbol.h"
34 #include "internal/thread.h"
35 #include "internal/variable.h"
38 #include "ruby/util.h"
40 #include "vm_callinfo.h"
42 #include "ruby/ractor.h"
45 #include "insns_info.inc"
48 static VALUE
iseqw_new(const rb_iseq_t
*iseq
);
49 static const rb_iseq_t
*iseqw_check(VALUE iseqw
);
51 #if VM_INSN_INFO_TABLE_IMPL == 2
52 static struct succ_index_table
*succ_index_table_create(int max_pos
, int *data
, int size
);
53 static unsigned int *succ_index_table_invert(int max_pos
, struct succ_index_table
*sd
, int size
);
54 static int succ_index_lookup(const struct succ_index_table
*sd
, int x
);
57 #define hidden_obj_p(obj) (!SPECIAL_CONST_P(obj) && !RBASIC(obj)->klass)
60 obj_resurrect(VALUE obj
)
62 if (hidden_obj_p(obj
)) {
63 switch (BUILTIN_TYPE(obj
)) {
65 obj
= rb_str_resurrect(obj
);
68 obj
= rb_ary_resurrect(obj
);
71 obj
= rb_hash_resurrect(obj
);
81 free_arena(struct iseq_compile_data_storage
*cur
)
83 struct iseq_compile_data_storage
*next
;
93 compile_data_free(struct iseq_compile_data
*compile_data
)
96 free_arena(compile_data
->node
.storage_head
);
97 free_arena(compile_data
->insn
.storage_head
);
98 if (compile_data
->ivar_cache_table
) {
99 rb_id_table_free(compile_data
->ivar_cache_table
);
101 ruby_xfree(compile_data
);
106 remove_from_constant_cache(ID id
, IC ic
)
108 rb_vm_t
*vm
= GET_VM();
110 st_data_t ic_data
= (st_data_t
)ic
;
112 if (rb_id_table_lookup(vm
->constant_cache
, id
, &lookup_result
)) {
113 st_table
*ics
= (st_table
*)lookup_result
;
114 st_delete(ics
, &ic_data
, NULL
);
116 if (ics
->num_entries
== 0) {
117 rb_id_table_delete(vm
->constant_cache
, id
);
123 // When an ISEQ is being freed, all of its associated ICs are going to go away
124 // as well. Because of this, we need to iterate over the ICs, and clear them
125 // from the VM's constant cache.
127 iseq_clear_ic_references(const rb_iseq_t
*iseq
)
129 // In some cases (when there is a compilation error), we end up with
130 // ic_size greater than 0, but no allocated is_entries buffer.
131 // If there's no is_entries buffer to loop through, return early.
133 if (!ISEQ_BODY(iseq
)->is_entries
) {
137 for (unsigned int ic_idx
= 0; ic_idx
< ISEQ_BODY(iseq
)->ic_size
; ic_idx
++) {
138 IC ic
= &ISEQ_IS_IC_ENTRY(ISEQ_BODY(iseq
), ic_idx
);
140 // Iterate over the IC's constant path's segments and clean any references to
141 // the ICs out of the VM's constant cache table.
142 const ID
*segments
= ic
->segments
;
144 // It's possible that segments is NULL if we overallocated an IC but
145 // optimizations removed the instruction using it
146 if (segments
== NULL
)
149 for (int i
= 0; segments
[i
]; i
++) {
151 if (id
== idNULL
) continue;
152 remove_from_constant_cache(id
, ic
);
155 ruby_xfree((void *)segments
);
160 rb_iseq_free(const rb_iseq_t
*iseq
)
162 RUBY_FREE_ENTER("iseq");
164 if (iseq
&& ISEQ_BODY(iseq
)) {
165 iseq_clear_ic_references(iseq
);
166 struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
167 mjit_free_iseq(iseq
); /* Notify MJIT */
169 rb_yjit_iseq_free(body
->yjit_payload
);
171 ruby_xfree((void *)body
->iseq_encoded
);
172 ruby_xfree((void *)body
->insns_info
.body
);
173 if (body
->insns_info
.positions
) ruby_xfree((void *)body
->insns_info
.positions
);
174 #if VM_INSN_INFO_TABLE_IMPL == 2
175 if (body
->insns_info
.succ_index_table
) ruby_xfree(body
->insns_info
.succ_index_table
);
177 if (LIKELY(body
->local_table
!= rb_iseq_shared_exc_local_tbl
))
178 ruby_xfree((void *)body
->local_table
);
179 ruby_xfree((void *)body
->is_entries
);
181 if (body
->call_data
) {
182 ruby_xfree(body
->call_data
);
184 ruby_xfree((void *)body
->catch_table
);
185 ruby_xfree((void *)body
->param
.opt_table
);
186 if (ISEQ_MBITS_BUFLEN(body
->iseq_size
) > 1 && body
->mark_bits
.list
) {
187 ruby_xfree((void *)body
->mark_bits
.list
);
190 if (body
->param
.keyword
!= NULL
) {
191 ruby_xfree((void *)body
->param
.keyword
->default_values
);
192 ruby_xfree((void *)body
->param
.keyword
);
194 compile_data_free(ISEQ_COMPILE_DATA(iseq
));
195 if (body
->outer_variables
) rb_id_table_free(body
->outer_variables
);
199 if (iseq
&& ISEQ_EXECUTABLE_P(iseq
) && iseq
->aux
.exec
.local_hooks
) {
200 rb_hook_list_free(iseq
->aux
.exec
.local_hooks
);
203 RUBY_FREE_LEAVE("iseq");
206 typedef VALUE
iseq_value_itr_t(void *ctx
, VALUE obj
);
209 iseq_scan_bits(unsigned int page
, iseq_bits_t bits
, VALUE
*code
, VALUE
*original_iseq
)
212 unsigned int page_offset
= (page
* ISEQ_MBITS_BITLENGTH
);
215 offset
= ntz_intptr(bits
);
216 VALUE op
= code
[page_offset
+ offset
];
217 rb_gc_mark_and_move(&code
[page_offset
+ offset
]);
218 VALUE newop
= code
[page_offset
+ offset
];
219 if (original_iseq
&& newop
!= op
) {
220 original_iseq
[page_offset
+ offset
] = newop
;
222 bits
&= bits
- 1; // Reset Lowest Set Bit (BLSR)
227 rb_iseq_mark_and_move_each_value(const rb_iseq_t
*iseq
, VALUE
*original_iseq
)
231 const struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
233 size
= body
->iseq_size
;
234 code
= body
->iseq_encoded
;
236 union iseq_inline_storage_entry
*is_entries
= body
->is_entries
;
238 if (body
->is_entries
) {
239 // Skip iterating over ivc caches
240 is_entries
+= body
->ivc_size
;
243 for (unsigned int i
= 0; i
< body
->icvarc_size
; i
++, is_entries
++) {
244 ICVARC icvarc
= (ICVARC
)is_entries
;
246 RUBY_ASSERT(!RB_TYPE_P(icvarc
->entry
->class_value
, T_NONE
));
248 rb_gc_mark_and_move(&icvarc
->entry
->class_value
);
253 for (unsigned int i
= 0; i
< body
->ise_size
; i
++, is_entries
++) {
254 union iseq_inline_storage_entry
*const is
= (union iseq_inline_storage_entry
*)is_entries
;
255 if (is
->once
.value
) {
256 rb_gc_mark_and_move(&is
->once
.value
);
261 for (unsigned int i
= 0; i
< body
->ic_size
; i
++, is_entries
++) {
262 IC ic
= (IC
)is_entries
;
264 rb_gc_mark_and_move_ptr(&ic
->entry
);
270 if (body
->mark_bits
.list
) {
271 if (ISEQ_MBITS_BUFLEN(size
) == 1) {
272 iseq_scan_bits(0, body
->mark_bits
.single
, code
, original_iseq
);
275 if (body
->mark_bits
.list
) {
276 for (unsigned int i
= 0; i
< ISEQ_MBITS_BUFLEN(size
); i
++) {
277 iseq_bits_t bits
= body
->mark_bits
.list
[i
];
278 iseq_scan_bits(i
, bits
, code
, original_iseq
);
286 rb_iseq_mark_and_move(rb_iseq_t
*iseq
, bool reference_updating
)
288 RUBY_MARK_ENTER("iseq");
290 rb_gc_mark_and_move(&iseq
->wrapper
);
292 if (ISEQ_BODY(iseq
)) {
293 struct rb_iseq_constant_body
*body
= ISEQ_BODY(iseq
);
295 rb_iseq_mark_and_move_each_value(iseq
, reference_updating
? ISEQ_ORIGINAL_ISEQ(iseq
) : NULL
);
297 rb_gc_mark_and_move(&body
->variable
.coverage
);
298 rb_gc_mark_and_move(&body
->variable
.pc2branchindex
);
299 rb_gc_mark_and_move(&body
->variable
.script_lines
);
300 rb_gc_mark_and_move(&body
->location
.label
);
301 rb_gc_mark_and_move(&body
->location
.base_label
);
302 rb_gc_mark_and_move(&body
->location
.pathobj
);
303 if (body
->local_iseq
) rb_gc_mark_and_move_ptr(&body
->local_iseq
);
304 if (body
->parent_iseq
) rb_gc_mark_and_move_ptr(&body
->parent_iseq
);
305 if (body
->mandatory_only_iseq
) rb_gc_mark_and_move_ptr(&body
->mandatory_only_iseq
);
307 if (body
->call_data
) {
308 for (unsigned int i
= 0; i
< body
->ci_size
; i
++) {
309 struct rb_call_data
*cds
= body
->call_data
;
311 if (cds
[i
].ci
) rb_gc_mark_and_move_ptr(&cds
[i
].ci
);
313 const struct rb_callcache
*cc
= cds
[i
].cc
;
315 if (reference_updating
) {
316 cc
= (const struct rb_callcache
*)rb_gc_location((VALUE
)cc
);
319 if (vm_cc_markable(cc
)) {
320 VM_ASSERT((cc
->flags
& VM_CALLCACHE_ON_STACK
) == 0);
322 const struct rb_callable_method_entry_struct
*cme
= vm_cc_cme(cc
);
323 if (reference_updating
) {
324 cme
= (const struct rb_callable_method_entry_struct
*)rb_gc_location((VALUE
)cme
);
327 if (cc
->klass
&& !METHOD_ENTRY_INVALIDATED(cme
)) {
328 rb_gc_mark_and_move_ptr(&cds
[i
].cc
);
331 cds
[i
].cc
= rb_vm_empty_cc();
338 if (body
->param
.flags
.has_kw
&& ISEQ_COMPILE_DATA(iseq
) == NULL
) {
339 const struct rb_iseq_param_keyword
*const keyword
= body
->param
.keyword
;
341 for (int j
= 0, i
= keyword
->required_num
; i
< keyword
->num
; i
++, j
++) {
342 rb_gc_mark_and_move(&keyword
->default_values
[j
]);
346 if (body
->catch_table
) {
347 struct iseq_catch_table
*table
= body
->catch_table
;
349 for (unsigned int i
= 0; i
< table
->size
; i
++) {
350 struct iseq_catch_table_entry
*entry
;
351 entry
= UNALIGNED_MEMBER_PTR(table
, entries
[i
]);
353 rb_gc_mark_and_move_ptr(&entry
->iseq
);
358 if (reference_updating
) {
360 rb_mjit_iseq_update_references(body
);
363 rb_yjit_iseq_update_references(body
->yjit_payload
);
368 rb_mjit_iseq_mark(body
->mjit_blocks
);
371 rb_yjit_iseq_mark(body
->yjit_payload
);
376 if (FL_TEST_RAW((VALUE
)iseq
, ISEQ_NOT_LOADED_YET
)) {
377 rb_gc_mark_and_move(&iseq
->aux
.loader
.obj
);
379 else if (FL_TEST_RAW((VALUE
)iseq
, ISEQ_USE_COMPILE_DATA
)) {
380 const struct iseq_compile_data
*const compile_data
= ISEQ_COMPILE_DATA(iseq
);
382 rb_iseq_mark_and_move_insn_storage(compile_data
->insn
.storage_head
);
384 rb_gc_mark_and_move((VALUE
*)&compile_data
->err_info
);
385 rb_gc_mark_and_move((VALUE
*)&compile_data
->catch_table_ary
);
389 VM_ASSERT(ISEQ_EXECUTABLE_P(iseq
));
391 if (iseq
->aux
.exec
.local_hooks
) {
392 rb_hook_list_mark_and_update(iseq
->aux
.exec
.local_hooks
);
396 RUBY_MARK_LEAVE("iseq");
400 param_keyword_size(const struct rb_iseq_param_keyword
*pkw
)
404 if (!pkw
) return size
;
406 size
+= sizeof(struct rb_iseq_param_keyword
);
407 size
+= sizeof(VALUE
) * (pkw
->num
- pkw
->required_num
);
413 rb_iseq_memsize(const rb_iseq_t
*iseq
)
415 size_t size
= 0; /* struct already counted as RVALUE size */
416 const struct rb_iseq_constant_body
*body
= ISEQ_BODY(iseq
);
417 const struct iseq_compile_data
*compile_data
;
419 /* TODO: should we count original_iseq? */
421 if (ISEQ_EXECUTABLE_P(iseq
) && body
) {
422 size
+= sizeof(struct rb_iseq_constant_body
);
423 size
+= body
->iseq_size
* sizeof(VALUE
);
424 size
+= body
->insns_info
.size
* (sizeof(struct iseq_insn_info_entry
) + sizeof(unsigned int));
425 size
+= body
->local_table_size
* sizeof(ID
);
426 size
+= ISEQ_MBITS_BUFLEN(body
->iseq_size
) * ISEQ_MBITS_SIZE
;
427 if (body
->catch_table
) {
428 size
+= iseq_catch_table_bytes(body
->catch_table
->size
);
430 size
+= (body
->param
.opt_num
+ 1) * sizeof(VALUE
);
431 size
+= param_keyword_size(body
->param
.keyword
);
433 /* body->is_entries */
434 size
+= ISEQ_IS_SIZE(body
) * sizeof(union iseq_inline_storage_entry
);
436 if (ISEQ_BODY(iseq
)->is_entries
) {
437 /* IC entries constant segments */
438 for (unsigned int ic_idx
= 0; ic_idx
< body
->ic_size
; ic_idx
++) {
439 IC ic
= &ISEQ_IS_IC_ENTRY(body
, ic_idx
);
440 const ID
*ids
= ic
->segments
;
445 size
+= sizeof(ID
); // null terminator
449 /* body->call_data */
450 size
+= body
->ci_size
* sizeof(struct rb_call_data
);
451 // TODO: should we count imemo_callinfo?
454 compile_data
= ISEQ_COMPILE_DATA(iseq
);
456 struct iseq_compile_data_storage
*cur
;
458 size
+= sizeof(struct iseq_compile_data
);
460 cur
= compile_data
->node
.storage_head
;
462 size
+= cur
->size
+ offsetof(struct iseq_compile_data_storage
, buff
);
470 struct rb_iseq_constant_body
*
471 rb_iseq_constant_body_alloc(void)
473 struct rb_iseq_constant_body
*iseq_body
;
474 iseq_body
= ZALLOC(struct rb_iseq_constant_body
);
481 rb_iseq_t
*iseq
= iseq_imemo_alloc();
482 ISEQ_BODY(iseq
) = rb_iseq_constant_body_alloc();
487 rb_iseq_pathobj_new(VALUE path
, VALUE realpath
)
490 VM_ASSERT(RB_TYPE_P(path
, T_STRING
));
491 VM_ASSERT(NIL_P(realpath
) || RB_TYPE_P(realpath
, T_STRING
));
493 if (path
== realpath
||
494 (!NIL_P(realpath
) && rb_str_cmp(path
, realpath
) == 0)) {
495 pathobj
= rb_fstring(path
);
498 if (!NIL_P(realpath
)) realpath
= rb_fstring(realpath
);
499 pathobj
= rb_ary_new_from_args(2, rb_fstring(path
), realpath
);
500 rb_obj_freeze(pathobj
);
506 rb_iseq_pathobj_set(const rb_iseq_t
*iseq
, VALUE path
, VALUE realpath
)
508 RB_OBJ_WRITE(iseq
, &ISEQ_BODY(iseq
)->location
.pathobj
,
509 rb_iseq_pathobj_new(path
, realpath
));
512 static rb_iseq_location_t
*
513 iseq_location_setup(rb_iseq_t
*iseq
, VALUE name
, VALUE path
, VALUE realpath
, int first_lineno
, const rb_code_location_t
*code_location
, const int node_id
)
515 rb_iseq_location_t
*loc
= &ISEQ_BODY(iseq
)->location
;
517 rb_iseq_pathobj_set(iseq
, path
, realpath
);
518 RB_OBJ_WRITE(iseq
, &loc
->label
, name
);
519 RB_OBJ_WRITE(iseq
, &loc
->base_label
, name
);
520 loc
->first_lineno
= first_lineno
;
522 loc
->node_id
= node_id
;
523 loc
->code_location
= *code_location
;
526 loc
->code_location
.beg_pos
.lineno
= 0;
527 loc
->code_location
.beg_pos
.column
= 0;
528 loc
->code_location
.end_pos
.lineno
= -1;
529 loc
->code_location
.end_pos
.column
= -1;
536 set_relation(rb_iseq_t
*iseq
, const rb_iseq_t
*piseq
)
538 struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
539 const VALUE type
= body
->type
;
541 /* set class nest stack */
542 if (type
== ISEQ_TYPE_TOP
) {
543 body
->local_iseq
= iseq
;
545 else if (type
== ISEQ_TYPE_METHOD
|| type
== ISEQ_TYPE_CLASS
) {
546 body
->local_iseq
= iseq
;
549 body
->local_iseq
= ISEQ_BODY(piseq
)->local_iseq
;
553 body
->parent_iseq
= piseq
;
556 if (type
== ISEQ_TYPE_MAIN
) {
557 body
->local_iseq
= iseq
;
561 static struct iseq_compile_data_storage
*
564 struct iseq_compile_data_storage
* new_arena
=
565 (struct iseq_compile_data_storage
*)
566 ALLOC_N(char, INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE
+
567 offsetof(struct iseq_compile_data_storage
, buff
));
571 new_arena
->size
= INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE
;
577 prepare_iseq_build(rb_iseq_t
*iseq
,
578 VALUE name
, VALUE path
, VALUE realpath
, int first_lineno
, const rb_code_location_t
*code_location
, const int node_id
,
579 const rb_iseq_t
*parent
, int isolated_depth
, enum rb_iseq_type type
,
580 VALUE script_lines
, const rb_compile_option_t
*option
)
582 VALUE coverage
= Qfalse
;
583 VALUE err_info
= Qnil
;
584 struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
586 if (parent
&& (type
== ISEQ_TYPE_MAIN
|| type
== ISEQ_TYPE_TOP
))
590 set_relation(iseq
, parent
);
592 name
= rb_fstring(name
);
593 iseq_location_setup(iseq
, name
, path
, realpath
, first_lineno
, code_location
, node_id
);
594 if (iseq
!= body
->local_iseq
) {
595 RB_OBJ_WRITE(iseq
, &body
->location
.base_label
, ISEQ_BODY(body
->local_iseq
)->location
.label
);
597 ISEQ_COVERAGE_SET(iseq
, Qnil
);
598 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq
);
599 body
->variable
.flip_count
= 0;
601 if (NIL_P(script_lines
)) {
602 RB_OBJ_WRITE(iseq
, &body
->variable
.script_lines
, Qnil
);
605 RB_OBJ_WRITE(iseq
, &body
->variable
.script_lines
, rb_ractor_make_shareable(script_lines
));
608 ISEQ_COMPILE_DATA_ALLOC(iseq
);
609 RB_OBJ_WRITE(iseq
, &ISEQ_COMPILE_DATA(iseq
)->err_info
, err_info
);
610 RB_OBJ_WRITE(iseq
, &ISEQ_COMPILE_DATA(iseq
)->catch_table_ary
, Qnil
);
612 ISEQ_COMPILE_DATA(iseq
)->node
.storage_head
= ISEQ_COMPILE_DATA(iseq
)->node
.storage_current
= new_arena();
613 ISEQ_COMPILE_DATA(iseq
)->insn
.storage_head
= ISEQ_COMPILE_DATA(iseq
)->insn
.storage_current
= new_arena();
614 ISEQ_COMPILE_DATA(iseq
)->isolated_depth
= isolated_depth
;
615 ISEQ_COMPILE_DATA(iseq
)->option
= option
;
616 ISEQ_COMPILE_DATA(iseq
)->ivar_cache_table
= NULL
;
617 ISEQ_COMPILE_DATA(iseq
)->builtin_function_table
= GET_VM()->builtin_function_table
;
619 if (option
->coverage_enabled
) {
620 VALUE coverages
= rb_get_coverages();
621 if (RTEST(coverages
)) {
622 coverage
= rb_hash_lookup(coverages
, rb_iseq_path(iseq
));
623 if (NIL_P(coverage
)) coverage
= Qfalse
;
626 ISEQ_COVERAGE_SET(iseq
, coverage
);
627 if (coverage
&& ISEQ_BRANCH_COVERAGE(iseq
))
628 ISEQ_PC2BRANCHINDEX_SET(iseq
, rb_ary_hidden_new(0));
633 #if VM_CHECK_MODE > 0 && VM_INSN_INFO_TABLE_IMPL > 0
634 static void validate_get_insn_info(const rb_iseq_t
*iseq
);
638 rb_iseq_insns_info_encode_positions(const rb_iseq_t
*iseq
)
640 #if VM_INSN_INFO_TABLE_IMPL == 2
641 /* create succ_index_table */
642 struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
643 int size
= body
->insns_info
.size
;
644 int max_pos
= body
->iseq_size
;
645 int *data
= (int *)body
->insns_info
.positions
;
646 if (body
->insns_info
.succ_index_table
) ruby_xfree(body
->insns_info
.succ_index_table
);
647 body
->insns_info
.succ_index_table
= succ_index_table_create(max_pos
, data
, size
);
648 #if VM_CHECK_MODE == 0
649 ruby_xfree(body
->insns_info
.positions
);
650 body
->insns_info
.positions
= NULL
;
655 #if VM_INSN_INFO_TABLE_IMPL == 2
657 rb_iseq_insns_info_decode_positions(const struct rb_iseq_constant_body
*body
)
659 int size
= body
->insns_info
.size
;
660 int max_pos
= body
->iseq_size
;
661 struct succ_index_table
*sd
= body
->insns_info
.succ_index_table
;
662 return succ_index_table_invert(max_pos
, sd
, size
);
667 rb_iseq_init_trace(rb_iseq_t
*iseq
)
669 iseq
->aux
.exec
.global_trace_events
= 0;
670 if (ruby_vm_event_enabled_global_flags
& ISEQ_TRACE_EVENTS
) {
671 rb_iseq_trace_set(iseq
, ruby_vm_event_enabled_global_flags
& ISEQ_TRACE_EVENTS
);
676 finish_iseq_build(rb_iseq_t
*iseq
)
678 struct iseq_compile_data
*data
= ISEQ_COMPILE_DATA(iseq
);
679 const struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
680 VALUE err
= data
->err_info
;
681 ISEQ_COMPILE_DATA_CLEAR(iseq
);
682 compile_data_free(data
);
684 #if VM_CHECK_MODE > 0 && VM_INSN_INFO_TABLE_IMPL > 0
685 validate_get_insn_info(iseq
);
689 VALUE path
= pathobj_path(body
->location
.pathobj
);
690 if (err
== Qtrue
) err
= rb_exc_new_cstr(rb_eSyntaxError
, "compile error");
691 rb_funcallv(err
, rb_intern("set_backtrace"), 1, &path
);
695 RB_DEBUG_COUNTER_INC(iseq_num
);
696 RB_DEBUG_COUNTER_ADD(iseq_cd_num
, ISEQ_BODY(iseq
)->ci_size
);
698 rb_iseq_init_trace(iseq
);
702 static rb_compile_option_t COMPILE_OPTION_DEFAULT
= {
703 OPT_INLINE_CONST_CACHE
, /* int inline_const_cache; */
704 OPT_PEEPHOLE_OPTIMIZATION
, /* int peephole_optimization; */
705 OPT_TAILCALL_OPTIMIZATION
, /* int tailcall_optimization */
706 OPT_SPECIALISED_INSTRUCTION
, /* int specialized_instruction; */
707 OPT_OPERANDS_UNIFICATION
, /* int operands_unification; */
708 OPT_INSTRUCTIONS_UNIFICATION
, /* int instructions_unification; */
709 OPT_STACK_CACHING
, /* int stack_caching; */
710 OPT_FROZEN_STRING_LITERAL
,
711 OPT_DEBUG_FROZEN_STRING_LITERAL
,
712 TRUE
, /* coverage_enabled */
715 static const rb_compile_option_t COMPILE_OPTION_FALSE
= {0};
718 set_compile_option_from_hash(rb_compile_option_t
*option
, VALUE opt
)
720 #define SET_COMPILE_OPTION(o, h, mem) \
721 { VALUE flag = rb_hash_aref((h), ID2SYM(rb_intern(#mem))); \
722 if (flag == Qtrue) { (o)->mem = 1; } \
723 else if (flag == Qfalse) { (o)->mem = 0; } \
725 #define SET_COMPILE_OPTION_NUM(o, h, mem) \
726 { VALUE num = rb_hash_aref(opt, ID2SYM(rb_intern(#mem))); \
727 if (!NIL_P(num)) (o)->mem = NUM2INT(num); \
729 SET_COMPILE_OPTION(option
, opt
, inline_const_cache
);
730 SET_COMPILE_OPTION(option
, opt
, peephole_optimization
);
731 SET_COMPILE_OPTION(option
, opt
, tailcall_optimization
);
732 SET_COMPILE_OPTION(option
, opt
, specialized_instruction
);
733 SET_COMPILE_OPTION(option
, opt
, operands_unification
);
734 SET_COMPILE_OPTION(option
, opt
, instructions_unification
);
735 SET_COMPILE_OPTION(option
, opt
, stack_caching
);
736 SET_COMPILE_OPTION(option
, opt
, frozen_string_literal
);
737 SET_COMPILE_OPTION(option
, opt
, debug_frozen_string_literal
);
738 SET_COMPILE_OPTION(option
, opt
, coverage_enabled
);
739 SET_COMPILE_OPTION_NUM(option
, opt
, debug_level
);
740 #undef SET_COMPILE_OPTION
741 #undef SET_COMPILE_OPTION_NUM
745 rb_iseq_make_compile_option(rb_compile_option_t
*option
, VALUE opt
)
747 Check_Type(opt
, T_HASH
);
748 set_compile_option_from_hash(option
, opt
);
752 make_compile_option(rb_compile_option_t
*option
, VALUE opt
)
755 *option
= COMPILE_OPTION_DEFAULT
;
757 else if (opt
== Qfalse
) {
758 *option
= COMPILE_OPTION_FALSE
;
760 else if (opt
== Qtrue
) {
762 for (i
= 0; i
< (int)(sizeof(rb_compile_option_t
) / sizeof(int)); ++i
)
763 ((int *)option
)[i
] = 1;
765 else if (RB_TYPE_P(opt
, T_HASH
)) {
766 *option
= COMPILE_OPTION_DEFAULT
;
767 set_compile_option_from_hash(option
, opt
);
770 rb_raise(rb_eTypeError
, "Compile option must be Hash/true/false/nil");
775 make_compile_option_value(rb_compile_option_t
*option
)
777 VALUE opt
= rb_hash_new_with_size(11);
778 #define SET_COMPILE_OPTION(o, h, mem) \
779 rb_hash_aset((h), ID2SYM(rb_intern(#mem)), RBOOL((o)->mem))
780 #define SET_COMPILE_OPTION_NUM(o, h, mem) \
781 rb_hash_aset((h), ID2SYM(rb_intern(#mem)), INT2NUM((o)->mem))
783 SET_COMPILE_OPTION(option
, opt
, inline_const_cache
);
784 SET_COMPILE_OPTION(option
, opt
, peephole_optimization
);
785 SET_COMPILE_OPTION(option
, opt
, tailcall_optimization
);
786 SET_COMPILE_OPTION(option
, opt
, specialized_instruction
);
787 SET_COMPILE_OPTION(option
, opt
, operands_unification
);
788 SET_COMPILE_OPTION(option
, opt
, instructions_unification
);
789 SET_COMPILE_OPTION(option
, opt
, stack_caching
);
790 SET_COMPILE_OPTION(option
, opt
, frozen_string_literal
);
791 SET_COMPILE_OPTION(option
, opt
, debug_frozen_string_literal
);
792 SET_COMPILE_OPTION(option
, opt
, coverage_enabled
);
793 SET_COMPILE_OPTION_NUM(option
, opt
, debug_level
);
795 #undef SET_COMPILE_OPTION
796 #undef SET_COMPILE_OPTION_NUM
801 rb_iseq_new(const rb_ast_body_t
*ast
, VALUE name
, VALUE path
, VALUE realpath
,
802 const rb_iseq_t
*parent
, enum rb_iseq_type type
)
804 return rb_iseq_new_with_opt(ast
, name
, path
, realpath
, 0, parent
,
805 0, type
, &COMPILE_OPTION_DEFAULT
);
809 ast_line_count(const rb_ast_body_t
*ast
)
811 if (ast
->script_lines
== Qfalse
) {
812 // this occurs when failed to parse the source code with a syntax error
815 if (RB_TYPE_P(ast
->script_lines
, T_ARRAY
)){
816 return (int)RARRAY_LEN(ast
->script_lines
);
818 return FIX2INT(ast
->script_lines
);
822 iseq_setup_coverage(VALUE coverages
, VALUE path
, const rb_ast_body_t
*ast
, int line_offset
)
824 int line_count
= line_offset
+ ast_line_count(ast
);
826 if (line_count
>= 0) {
827 int len
= (rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES
) ? 0 : line_count
;
829 VALUE coverage
= rb_default_coverage(len
);
830 rb_hash_aset(coverages
, path
, coverage
);
839 iseq_new_setup_coverage(VALUE path
, const rb_ast_body_t
*ast
, int line_offset
)
841 VALUE coverages
= rb_get_coverages();
843 if (RTEST(coverages
)) {
844 iseq_setup_coverage(coverages
, path
, ast
, line_offset
);
849 rb_iseq_new_top(const rb_ast_body_t
*ast
, VALUE name
, VALUE path
, VALUE realpath
, const rb_iseq_t
*parent
)
851 iseq_new_setup_coverage(path
, ast
, 0);
853 return rb_iseq_new_with_opt(ast
, name
, path
, realpath
, 0, parent
, 0,
854 ISEQ_TYPE_TOP
, &COMPILE_OPTION_DEFAULT
);
858 rb_iseq_new_main(const rb_ast_body_t
*ast
, VALUE path
, VALUE realpath
, const rb_iseq_t
*parent
, int opt
)
860 iseq_new_setup_coverage(path
, ast
, 0);
862 return rb_iseq_new_with_opt(ast
, rb_fstring_lit("<main>"),
864 parent
, 0, ISEQ_TYPE_MAIN
, opt
? &COMPILE_OPTION_DEFAULT
: &COMPILE_OPTION_FALSE
);
868 rb_iseq_new_eval(const rb_ast_body_t
*ast
, VALUE name
, VALUE path
, VALUE realpath
, int first_lineno
, const rb_iseq_t
*parent
, int isolated_depth
)
870 if (rb_get_coverage_mode() & COVERAGE_TARGET_EVAL
) {
871 VALUE coverages
= rb_get_coverages();
872 if (RTEST(coverages
) && RTEST(path
) && !RTEST(rb_hash_has_key(coverages
, path
))) {
873 iseq_setup_coverage(coverages
, path
, ast
, first_lineno
- 1);
877 return rb_iseq_new_with_opt(ast
, name
, path
, realpath
, first_lineno
,
878 parent
, isolated_depth
, ISEQ_TYPE_EVAL
, &COMPILE_OPTION_DEFAULT
);
881 static inline rb_iseq_t
*
882 iseq_translate(rb_iseq_t
*iseq
)
884 if (rb_respond_to(rb_cISeq
, rb_intern("translate"))) {
885 VALUE v1
= iseqw_new(iseq
);
886 VALUE v2
= rb_funcall(rb_cISeq
, rb_intern("translate"), 1, v1
);
887 if (v1
!= v2
&& CLASS_OF(v2
) == rb_cISeq
) {
888 iseq
= (rb_iseq_t
*)iseqw_check(v2
);
896 rb_iseq_new_with_opt(const rb_ast_body_t
*ast
, VALUE name
, VALUE path
, VALUE realpath
,
897 int first_lineno
, const rb_iseq_t
*parent
, int isolated_depth
,
898 enum rb_iseq_type type
, const rb_compile_option_t
*option
)
900 const NODE
*node
= ast
? ast
->root
: 0;
901 /* TODO: argument check */
902 rb_iseq_t
*iseq
= iseq_alloc();
903 rb_compile_option_t new_opt
;
909 new_opt
= COMPILE_OPTION_DEFAULT
;
911 if (ast
&& ast
->compile_option
) rb_iseq_make_compile_option(&new_opt
, ast
->compile_option
);
913 VALUE script_lines
= Qnil
;
915 if (ast
&& !FIXNUM_P(ast
->script_lines
) && ast
->script_lines
) {
916 script_lines
= ast
->script_lines
;
919 script_lines
= ISEQ_BODY(parent
)->variable
.script_lines
;
922 prepare_iseq_build(iseq
, name
, path
, realpath
, first_lineno
, node
? &node
->nd_loc
: NULL
, node
? nd_node_id(node
) : -1,
923 parent
, isolated_depth
, type
, script_lines
, &new_opt
);
925 rb_iseq_compile_node(iseq
, node
);
926 finish_iseq_build(iseq
);
928 return iseq_translate(iseq
);
932 rb_iseq_new_with_callback(
933 const struct rb_iseq_new_with_callback_callback_func
* ifunc
,
934 VALUE name
, VALUE path
, VALUE realpath
,
935 int first_lineno
, const rb_iseq_t
*parent
,
936 enum rb_iseq_type type
, const rb_compile_option_t
*option
)
938 /* TODO: argument check */
939 rb_iseq_t
*iseq
= iseq_alloc();
941 if (!option
) option
= &COMPILE_OPTION_DEFAULT
;
942 prepare_iseq_build(iseq
, name
, path
, realpath
, first_lineno
, NULL
, -1, parent
, 0, type
, Qnil
, option
);
944 rb_iseq_compile_callback(iseq
, ifunc
);
945 finish_iseq_build(iseq
);
951 rb_iseq_load_iseq(VALUE fname
)
953 VALUE iseqv
= rb_check_funcall(rb_cISeq
, rb_intern("load_iseq"), 1, &fname
);
955 if (!SPECIAL_CONST_P(iseqv
) && RBASIC_CLASS(iseqv
) == rb_cISeq
) {
956 return iseqw_check(iseqv
);
962 #define CHECK_ARRAY(v) rb_to_array_type(v)
963 #define CHECK_HASH(v) rb_to_hash_type(v)
964 #define CHECK_STRING(v) rb_str_to_str(v)
965 #define CHECK_SYMBOL(v) rb_to_symbol_type(v)
966 static inline VALUE
CHECK_INTEGER(VALUE v
) {(void)NUM2LONG(v
); return v
;}
968 static enum rb_iseq_type
969 iseq_type_from_sym(VALUE type
)
971 const ID id_top
= rb_intern("top");
972 const ID id_method
= rb_intern("method");
973 const ID id_block
= rb_intern("block");
974 const ID id_class
= rb_intern("class");
975 const ID id_rescue
= rb_intern("rescue");
976 const ID id_ensure
= rb_intern("ensure");
977 const ID id_eval
= rb_intern("eval");
978 const ID id_main
= rb_intern("main");
979 const ID id_plain
= rb_intern("plain");
980 /* ensure all symbols are static or pinned down before
982 const ID
typeid = rb_check_id(&type
);
983 if (typeid == id_top
) return ISEQ_TYPE_TOP
;
984 if (typeid == id_method
) return ISEQ_TYPE_METHOD
;
985 if (typeid == id_block
) return ISEQ_TYPE_BLOCK
;
986 if (typeid == id_class
) return ISEQ_TYPE_CLASS
;
987 if (typeid == id_rescue
) return ISEQ_TYPE_RESCUE
;
988 if (typeid == id_ensure
) return ISEQ_TYPE_ENSURE
;
989 if (typeid == id_eval
) return ISEQ_TYPE_EVAL
;
990 if (typeid == id_main
) return ISEQ_TYPE_MAIN
;
991 if (typeid == id_plain
) return ISEQ_TYPE_PLAIN
;
992 return (enum rb_iseq_type
)-1;
996 iseq_load(VALUE data
, const rb_iseq_t
*parent
, VALUE opt
)
998 rb_iseq_t
*iseq
= iseq_alloc();
1000 VALUE magic
, version1
, version2
, format_type
, misc
;
1001 VALUE name
, path
, realpath
, code_location
, node_id
;
1002 VALUE type
, body
, locals
, params
, exception
;
1004 st_data_t iseq_type
;
1005 rb_compile_option_t option
;
1007 rb_code_location_t tmp_loc
= { {0, 0}, {-1, -1} };
1009 /* [magic, major_version, minor_version, format_type, misc,
1010 * label, path, first_lineno,
1011 * type, locals, args, exception_table, body]
1014 data
= CHECK_ARRAY(data
);
1016 magic
= CHECK_STRING(rb_ary_entry(data
, i
++));
1017 version1
= CHECK_INTEGER(rb_ary_entry(data
, i
++));
1018 version2
= CHECK_INTEGER(rb_ary_entry(data
, i
++));
1019 format_type
= CHECK_INTEGER(rb_ary_entry(data
, i
++));
1020 misc
= CHECK_HASH(rb_ary_entry(data
, i
++));
1021 ((void)magic
, (void)version1
, (void)version2
, (void)format_type
);
1023 name
= CHECK_STRING(rb_ary_entry(data
, i
++));
1024 path
= CHECK_STRING(rb_ary_entry(data
, i
++));
1025 realpath
= rb_ary_entry(data
, i
++);
1026 realpath
= NIL_P(realpath
) ? Qnil
: CHECK_STRING(realpath
);
1027 int first_lineno
= RB_NUM2INT(rb_ary_entry(data
, i
++));
1029 type
= CHECK_SYMBOL(rb_ary_entry(data
, i
++));
1030 locals
= CHECK_ARRAY(rb_ary_entry(data
, i
++));
1031 params
= CHECK_HASH(rb_ary_entry(data
, i
++));
1032 exception
= CHECK_ARRAY(rb_ary_entry(data
, i
++));
1033 body
= CHECK_ARRAY(rb_ary_entry(data
, i
++));
1035 ISEQ_BODY(iseq
)->local_iseq
= iseq
;
1037 iseq_type
= iseq_type_from_sym(type
);
1038 if (iseq_type
== (enum rb_iseq_type
)-1) {
1039 rb_raise(rb_eTypeError
, "unsupported type: :%"PRIsVALUE
, rb_sym2str(type
));
1042 node_id
= rb_hash_aref(misc
, ID2SYM(rb_intern("node_id")));
1044 code_location
= rb_hash_aref(misc
, ID2SYM(rb_intern("code_location")));
1045 if (RB_TYPE_P(code_location
, T_ARRAY
) && RARRAY_LEN(code_location
) == 4) {
1046 tmp_loc
.beg_pos
.lineno
= NUM2INT(rb_ary_entry(code_location
, 0));
1047 tmp_loc
.beg_pos
.column
= NUM2INT(rb_ary_entry(code_location
, 1));
1048 tmp_loc
.end_pos
.lineno
= NUM2INT(rb_ary_entry(code_location
, 2));
1049 tmp_loc
.end_pos
.column
= NUM2INT(rb_ary_entry(code_location
, 3));
1052 make_compile_option(&option
, opt
);
1053 option
.peephole_optimization
= FALSE
; /* because peephole optimization can modify original iseq */
1054 prepare_iseq_build(iseq
, name
, path
, realpath
, first_lineno
, &tmp_loc
, NUM2INT(node_id
),
1055 parent
, 0, (enum rb_iseq_type
)iseq_type
, Qnil
, &option
);
1057 rb_iseq_build_from_ary(iseq
, misc
, locals
, params
, exception
, body
);
1059 finish_iseq_build(iseq
);
1061 return iseqw_new(iseq
);
1068 iseq_s_load(int argc
, VALUE
*argv
, VALUE self
)
1070 VALUE data
, opt
=Qnil
;
1071 rb_scan_args(argc
, argv
, "11", &data
, &opt
);
1072 return iseq_load(data
, NULL
, opt
);
1076 rb_iseq_load(VALUE data
, VALUE parent
, VALUE opt
)
1078 return iseq_load(data
, RTEST(parent
) ? (rb_iseq_t
*)parent
: NULL
, opt
);
1082 rb_iseq_compile_with_option(VALUE src
, VALUE file
, VALUE realpath
, VALUE line
, VALUE opt
)
1084 rb_iseq_t
*iseq
= NULL
;
1085 rb_compile_option_t option
;
1086 #if !defined(__GNUC__) || (__GNUC__ == 4 && __GNUC_MINOR__ == 8)
1087 # define INITIALIZED volatile /* suppress warnings by gcc 4.8 */
1089 # define INITIALIZED /* volatile */
1091 rb_ast_t
*(*parse
)(VALUE vparser
, VALUE fname
, VALUE file
, int start
);
1093 rb_ast_t
*INITIALIZED ast
;
1094 VALUE name
= rb_fstring_lit("<compiled>");
1096 /* safe results first */
1097 make_compile_option(&option
, opt
);
1099 StringValueCStr(file
);
1100 if (RB_TYPE_P(src
, T_FILE
)) {
1101 parse
= rb_parser_compile_file_path
;
1104 parse
= rb_parser_compile_string_path
;
1108 const VALUE parser
= rb_parser_new();
1109 const rb_iseq_t
*outer_scope
= rb_iseq_new(NULL
, name
, name
, Qnil
, 0, ISEQ_TYPE_TOP
);
1110 VALUE outer_scope_v
= (VALUE
)outer_scope
;
1111 rb_parser_set_context(parser
, outer_scope
, FALSE
);
1112 RB_GC_GUARD(outer_scope_v
);
1113 ast
= (*parse
)(parser
, file
, src
, ln
);
1116 if (!ast
->body
.root
) {
1117 rb_ast_dispose(ast
);
1118 rb_exc_raise(GET_EC()->errinfo
);
1121 iseq
= rb_iseq_new_with_opt(&ast
->body
, name
, file
, realpath
, ln
,
1122 NULL
, 0, ISEQ_TYPE_TOP
, &option
);
1123 rb_ast_dispose(ast
);
1130 rb_iseq_path(const rb_iseq_t
*iseq
)
1132 return pathobj_path(ISEQ_BODY(iseq
)->location
.pathobj
);
1136 rb_iseq_realpath(const rb_iseq_t
*iseq
)
1138 return pathobj_realpath(ISEQ_BODY(iseq
)->location
.pathobj
);
1142 rb_iseq_absolute_path(const rb_iseq_t
*iseq
)
1144 return rb_iseq_realpath(iseq
);
1148 rb_iseq_from_eval_p(const rb_iseq_t
*iseq
)
1150 return NIL_P(rb_iseq_realpath(iseq
));
1154 rb_iseq_label(const rb_iseq_t
*iseq
)
1156 return ISEQ_BODY(iseq
)->location
.label
;
1160 rb_iseq_base_label(const rb_iseq_t
*iseq
)
1162 return ISEQ_BODY(iseq
)->location
.base_label
;
1166 rb_iseq_first_lineno(const rb_iseq_t
*iseq
)
1168 return RB_INT2NUM(ISEQ_BODY(iseq
)->location
.first_lineno
);
1172 rb_iseq_method_name(const rb_iseq_t
*iseq
)
1174 struct rb_iseq_constant_body
*const body
= ISEQ_BODY(ISEQ_BODY(iseq
)->local_iseq
);
1176 if (body
->type
== ISEQ_TYPE_METHOD
) {
1177 return body
->location
.base_label
;
1185 rb_iseq_code_location(const rb_iseq_t
*iseq
, int *beg_pos_lineno
, int *beg_pos_column
, int *end_pos_lineno
, int *end_pos_column
)
1187 const rb_code_location_t
*loc
= &ISEQ_BODY(iseq
)->location
.code_location
;
1188 if (beg_pos_lineno
) *beg_pos_lineno
= loc
->beg_pos
.lineno
;
1189 if (beg_pos_column
) *beg_pos_column
= loc
->beg_pos
.column
;
1190 if (end_pos_lineno
) *end_pos_lineno
= loc
->end_pos
.lineno
;
1191 if (end_pos_column
) *end_pos_column
= loc
->end_pos
.column
;
1194 static ID
iseq_type_id(enum rb_iseq_type type
);
1197 rb_iseq_type(const rb_iseq_t
*iseq
)
1199 return ID2SYM(iseq_type_id(ISEQ_BODY(iseq
)->type
));
1203 rb_iseq_coverage(const rb_iseq_t
*iseq
)
1205 return ISEQ_COVERAGE(iseq
);
1209 remove_coverage_i(void *vstart
, void *vend
, size_t stride
, void *data
)
1211 VALUE v
= (VALUE
)vstart
;
1212 for (; v
!= (VALUE
)vend
; v
+= stride
) {
1213 void *ptr
= asan_poisoned_object_p(v
);
1214 asan_unpoison_object(v
, false);
1216 if (rb_obj_is_iseq(v
)) {
1217 rb_iseq_t
*iseq
= (rb_iseq_t
*)v
;
1218 ISEQ_COVERAGE_SET(iseq
, Qnil
);
1221 asan_poison_object_if(ptr
, v
);
1227 rb_iseq_remove_coverage_all(void)
1229 rb_objspace_each_objects(remove_coverage_i
, NULL
);
1232 /* define wrapper class methods (RubyVM::InstructionSequence) */
1235 iseqw_mark(void *ptr
)
1237 rb_gc_mark((VALUE
)ptr
);
1241 iseqw_memsize(const void *ptr
)
1243 return rb_iseq_memsize((const rb_iseq_t
*)ptr
);
1246 static const rb_data_type_t iseqw_data_type
= {
1248 {iseqw_mark
, NULL
, iseqw_memsize
,},
1249 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|RUBY_TYPED_WB_PROTECTED
1253 iseqw_new(const rb_iseq_t
*iseq
)
1255 if (iseq
->wrapper
) {
1256 return iseq
->wrapper
;
1259 union { const rb_iseq_t
*in
; void *out
; } deconst
;
1262 obj
= TypedData_Wrap_Struct(rb_cISeq
, &iseqw_data_type
, deconst
.out
);
1263 RB_OBJ_WRITTEN(obj
, Qundef
, iseq
);
1265 /* cache a wrapper object */
1266 RB_OBJ_WRITE((VALUE
)iseq
, &iseq
->wrapper
, obj
);
1267 RB_OBJ_FREEZE((VALUE
)iseq
);
1274 rb_iseqw_new(const rb_iseq_t
*iseq
)
1276 return iseqw_new(iseq
);
1281 * InstructionSequence.compile(source[, file[, path[, line[, options]]]]) -> iseq
1282 * InstructionSequence.new(source[, file[, path[, line[, options]]]]) -> iseq
1284 * Takes +source+, a String of Ruby code and compiles it to an
1285 * InstructionSequence.
1287 * Optionally takes +file+, +path+, and +line+ which describe the file path,
1288 * real path and first line number of the ruby code in +source+ which are
1289 * metadata attached to the returned +iseq+.
1291 * +file+ is used for `__FILE__` and exception backtrace. +path+ is used for
1292 * +require_relative+ base. It is recommended these should be the same full
1295 * +options+, which can be +true+, +false+ or a +Hash+, is used to
1296 * modify the default behavior of the Ruby iseq compiler.
1298 * For details regarding valid compile options see ::compile_option=.
1300 * RubyVM::InstructionSequence.compile("a = 1 + 2")
1301 * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
1304 * RubyVM::InstructionSequence.compile(File.read(path), path, File.expand_path(path))
1305 * #=> <RubyVM::InstructionSequence:<compiled>@test.rb:1>
1307 * path = File.expand_path("test.rb")
1308 * RubyVM::InstructionSequence.compile(File.read(path), path, path)
1309 * #=> <RubyVM::InstructionSequence:<compiled>@/absolute/path/to/test.rb:1>
1313 iseqw_s_compile(int argc
, VALUE
*argv
, VALUE self
)
1315 VALUE src
, file
= Qnil
, path
= Qnil
, line
= INT2FIX(1), opt
= Qnil
;
1318 i
= rb_scan_args(argc
, argv
, "1*:", &src
, NULL
, &opt
);
1319 if (i
> 4+NIL_P(opt
)) rb_error_arity(argc
, 1, 5);
1321 case 5: opt
= argv
[--i
];
1322 case 4: line
= argv
[--i
];
1323 case 3: path
= argv
[--i
];
1324 case 2: file
= argv
[--i
];
1327 if (NIL_P(file
)) file
= rb_fstring_lit("<compiled>");
1328 if (NIL_P(path
)) path
= file
;
1329 if (NIL_P(line
)) line
= INT2FIX(1);
1331 Check_Type(path
, T_STRING
);
1332 Check_Type(file
, T_STRING
);
1334 return iseqw_new(rb_iseq_compile_with_option(src
, file
, path
, line
, opt
));
1339 * InstructionSequence.compile_file(file[, options]) -> iseq
1341 * Takes +file+, a String with the location of a Ruby source file, reads,
1342 * parses and compiles the file, and returns +iseq+, the compiled
1343 * InstructionSequence with source location metadata set.
1345 * Optionally takes +options+, which can be +true+, +false+ or a +Hash+, to
1346 * modify the default behavior of the Ruby iseq compiler.
1348 * For details regarding valid compile options see ::compile_option=.
1351 * puts "Hello, world!"
1354 * RubyVM::InstructionSequence.compile_file("/tmp/hello.rb")
1355 * #=> <RubyVM::InstructionSequence:<main>@/tmp/hello.rb>
1358 iseqw_s_compile_file(int argc
, VALUE
*argv
, VALUE self
)
1360 VALUE file
, opt
= Qnil
;
1361 VALUE parser
, f
, exc
= Qnil
, ret
;
1363 rb_compile_option_t option
;
1366 i
= rb_scan_args(argc
, argv
, "1*:", &file
, NULL
, &opt
);
1367 if (i
> 1+NIL_P(opt
)) rb_error_arity(argc
, 1, 2);
1369 case 2: opt
= argv
[--i
];
1371 FilePathValue(file
);
1372 file
= rb_fstring(file
); /* rb_io_t->pathv gets frozen anyways */
1374 f
= rb_file_open_str(file
, "r");
1376 rb_execution_context_t
*ec
= GET_EC();
1377 VALUE v
= rb_vm_push_frame_fname(ec
, file
);
1379 parser
= rb_parser_new();
1380 rb_parser_set_context(parser
, NULL
, FALSE
);
1381 ast
= (rb_ast_t
*)rb_parser_load_file(parser
, file
);
1382 if (!ast
->body
.root
) exc
= GET_EC()->errinfo
;
1385 if (!ast
->body
.root
) {
1386 rb_ast_dispose(ast
);
1390 make_compile_option(&option
, opt
);
1392 ret
= iseqw_new(rb_iseq_new_with_opt(&ast
->body
, rb_fstring_lit("<main>"),
1394 rb_realpath_internal(Qnil
, file
, 1),
1395 1, NULL
, 0, ISEQ_TYPE_TOP
, &option
));
1396 rb_ast_dispose(ast
);
1398 rb_vm_pop_frame(ec
);
1405 * InstructionSequence.compile_option = options
1407 * Sets the default values for various optimizations in the Ruby iseq
1410 * Possible values for +options+ include +true+, which enables all options,
1411 * +false+ which disables all options, and +nil+ which leaves all options
1414 * You can also pass a +Hash+ of +options+ that you want to change, any
1415 * options not present in the hash will be left unchanged.
1417 * Possible option names (which are keys in +options+) which can be set to
1418 * +true+ or +false+ include:
1420 * * +:inline_const_cache+
1421 * * +:instructions_unification+
1422 * * +:operands_unification+
1423 * * +:peephole_optimization+
1424 * * +:specialized_instruction+
1425 * * +:stack_caching+
1426 * * +:tailcall_optimization+
1428 * Additionally, +:debug_level+ can be set to an integer.
1430 * These default options can be overwritten for a single run of the iseq
1431 * compiler by passing any of the above values as the +options+ parameter to
1432 * ::new, ::compile and ::compile_file.
1435 iseqw_s_compile_option_set(VALUE self
, VALUE opt
)
1437 rb_compile_option_t option
;
1438 make_compile_option(&option
, opt
);
1439 COMPILE_OPTION_DEFAULT
= option
;
1445 * InstructionSequence.compile_option -> options
1447 * Returns a hash of default options used by the Ruby iseq compiler.
1449 * For details, see InstructionSequence.compile_option=.
1452 iseqw_s_compile_option_get(VALUE self
)
1454 return make_compile_option_value(&COMPILE_OPTION_DEFAULT
);
1457 static const rb_iseq_t
*
1458 iseqw_check(VALUE iseqw
)
1460 rb_iseq_t
*iseq
= DATA_PTR(iseqw
);
1462 if (!ISEQ_BODY(iseq
)) {
1463 rb_ibf_load_iseq_complete(iseq
);
1466 if (!ISEQ_BODY(iseq
)->location
.label
) {
1467 rb_raise(rb_eTypeError
, "uninitialized InstructionSequence");
1473 rb_iseqw_to_iseq(VALUE iseqw
)
1475 return iseqw_check(iseqw
);
1482 * Evaluates the instruction sequence and returns the result.
1484 * RubyVM::InstructionSequence.compile("1 + 2").eval #=> 3
1487 iseqw_eval(VALUE self
)
1489 return rb_iseq_eval(iseqw_check(self
));
1493 * Returns a human-readable string representation of this instruction
1494 * sequence, including the #label and #path.
1497 iseqw_inspect(VALUE self
)
1499 const rb_iseq_t
*iseq
= iseqw_check(self
);
1500 const struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
1501 VALUE klass
= rb_class_name(rb_obj_class(self
));
1503 if (!body
->location
.label
) {
1504 return rb_sprintf("#<%"PRIsVALUE
": uninitialized>", klass
);
1507 return rb_sprintf("<%"PRIsVALUE
":%"PRIsVALUE
"@%"PRIsVALUE
":%d>",
1509 body
->location
.label
, rb_iseq_path(iseq
),
1510 FIX2INT(rb_iseq_first_lineno(iseq
)));
1515 * Returns the path of this instruction sequence.
1517 * <code><compiled></code> if the iseq was evaluated from a string.
1519 * For example, using irb:
1521 * iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
1522 * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
1526 * Using ::compile_file:
1530 * puts "hello, world"
1534 * > iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
1535 * > iseq.path #=> /tmp/method.rb
1538 iseqw_path(VALUE self
)
1540 return rb_iseq_path(iseqw_check(self
));
1544 * Returns the absolute path of this instruction sequence.
1546 * +nil+ if the iseq was evaluated from a string.
1548 * For example, using ::compile_file:
1552 * puts "hello, world"
1556 * > iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
1557 * > iseq.absolute_path #=> /tmp/method.rb
1560 iseqw_absolute_path(VALUE self
)
1562 return rb_iseq_realpath(iseqw_check(self
));
1565 /* Returns the label of this instruction sequence.
1567 * <code><main></code> if it's at the top level, <code><compiled></code> if it
1568 * was evaluated from a string.
1570 * For example, using irb:
1572 * iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
1573 * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
1577 * Using ::compile_file:
1581 * puts "hello, world"
1585 * > iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
1586 * > iseq.label #=> <main>
1589 iseqw_label(VALUE self
)
1591 return rb_iseq_label(iseqw_check(self
));
1594 /* Returns the base label of this instruction sequence.
1596 * For example, using irb:
1598 * iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
1599 * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
1603 * Using ::compile_file:
1607 * puts "hello, world"
1611 * > iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
1612 * > iseq.base_label #=> <main>
1615 iseqw_base_label(VALUE self
)
1617 return rb_iseq_base_label(iseqw_check(self
));
1620 /* Returns the number of the first source line where the instruction sequence
1623 * For example, using irb:
1625 * iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
1626 * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
1631 iseqw_first_lineno(VALUE self
)
1633 return rb_iseq_first_lineno(iseqw_check(self
));
1636 static VALUE
iseq_data_to_ary(const rb_iseq_t
*iseq
);
1642 * Returns an Array with 14 elements representing the instruction sequence
1643 * with the following data:
1646 * A string identifying the data format. <b>Always
1647 * +YARVInstructionSequence/SimpleDataFormat+.</b>
1650 * The major version of the instruction sequence.
1653 * The minor version of the instruction sequence.
1656 * A number identifying the data format. <b>Always 1</b>.
1659 * A hash containing:
1662 * the total number of arguments taken by the method or the block (0 if
1663 * _iseq_ doesn't represent a method or block)
1665 * the number of local variables + 1
1667 * used in calculating the stack depth at which a SystemStackError is
1671 * The name of the context (block, method, class, module, etc.) that this
1672 * instruction sequence belongs to.
1674 * <code><main></code> if it's at the top level, <code><compiled></code> if
1675 * it was evaluated from a string.
1678 * The relative path to the Ruby file where the instruction sequence was
1681 * <code><compiled></code> if the iseq was evaluated from a string.
1684 * The absolute path to the Ruby file where the instruction sequence was
1687 * +nil+ if the iseq was evaluated from a string.
1690 * The number of the first source line where the instruction sequence was
1694 * The type of the instruction sequence.
1696 * Valid values are +:top+, +:method+, +:block+, +:class+, +:rescue+,
1697 * +:ensure+, +:eval+, +:main+, and +plain+.
1700 * An array containing the names of all arguments and local variables as
1704 * An Hash object containing parameter information.
1706 * More info about these values can be found in +vm_core.h+.
1709 * A list of exceptions and control flow operators (rescue, next, redo,
1713 * An array of arrays containing the instruction names and operands that
1714 * make up the body of the instruction sequence.
1716 * Note that this format is MRI specific and version dependent.
1720 iseqw_to_a(VALUE self
)
1722 const rb_iseq_t
*iseq
= iseqw_check(self
);
1723 return iseq_data_to_ary(iseq
);
1726 #if VM_INSN_INFO_TABLE_IMPL == 1 /* binary search */
1727 static const struct iseq_insn_info_entry
*
1728 get_insn_info_binary_search(const rb_iseq_t
*iseq
, size_t pos
)
1730 const struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
1731 size_t size
= body
->insns_info
.size
;
1732 const struct iseq_insn_info_entry
*insns_info
= body
->insns_info
.body
;
1733 const unsigned int *positions
= body
->insns_info
.positions
;
1734 const int debug
= 0;
1737 printf("size: %"PRIuSIZE
"\n", size
);
1738 printf("insns_info[%"PRIuSIZE
"]: position: %d, line: %d, pos: %"PRIuSIZE
"\n",
1739 (size_t)0, positions
[0], insns_info
[0].line_no
, pos
);
1745 else if (size
== 1) {
1746 return &insns_info
[0];
1749 size_t l
= 1, r
= size
- 1;
1751 size_t m
= l
+ (r
- l
) / 2;
1752 if (positions
[m
] == pos
) {
1753 return &insns_info
[m
];
1755 if (positions
[m
] < pos
) {
1763 return &insns_info
[size
-1];
1765 if (positions
[l
] > pos
) {
1766 return &insns_info
[l
-1];
1768 return &insns_info
[l
];
1772 static const struct iseq_insn_info_entry
*
1773 get_insn_info(const rb_iseq_t
*iseq
, size_t pos
)
1775 return get_insn_info_binary_search(iseq
, pos
);
1779 #if VM_INSN_INFO_TABLE_IMPL == 2 /* succinct bitvector */
1780 static const struct iseq_insn_info_entry
*
1781 get_insn_info_succinct_bitvector(const rb_iseq_t
*iseq
, size_t pos
)
1783 const struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
1784 size_t size
= body
->insns_info
.size
;
1785 const struct iseq_insn_info_entry
*insns_info
= body
->insns_info
.body
;
1786 const int debug
= 0;
1789 #if VM_CHECK_MODE > 0
1790 const unsigned int *positions
= body
->insns_info
.positions
;
1791 printf("size: %"PRIuSIZE
"\n", size
);
1792 printf("insns_info[%"PRIuSIZE
"]: position: %d, line: %d, pos: %"PRIuSIZE
"\n",
1793 (size_t)0, positions
[0], insns_info
[0].line_no
, pos
);
1795 printf("size: %"PRIuSIZE
"\n", size
);
1796 printf("insns_info[%"PRIuSIZE
"]: line: %d, pos: %"PRIuSIZE
"\n",
1797 (size_t)0, insns_info
[0].line_no
, pos
);
1804 else if (size
== 1) {
1805 return &insns_info
[0];
1809 VM_ASSERT(body
->insns_info
.succ_index_table
!= NULL
);
1810 index
= succ_index_lookup(body
->insns_info
.succ_index_table
, (int)pos
);
1811 return &insns_info
[index
-1];
1815 static const struct iseq_insn_info_entry
*
1816 get_insn_info(const rb_iseq_t
*iseq
, size_t pos
)
1818 return get_insn_info_succinct_bitvector(iseq
, pos
);
1822 #if VM_CHECK_MODE > 0 || VM_INSN_INFO_TABLE_IMPL == 0
1823 static const struct iseq_insn_info_entry
*
1824 get_insn_info_linear_search(const rb_iseq_t
*iseq
, size_t pos
)
1826 const struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
1827 size_t i
= 0, size
= body
->insns_info
.size
;
1828 const struct iseq_insn_info_entry
*insns_info
= body
->insns_info
.body
;
1829 const unsigned int *positions
= body
->insns_info
.positions
;
1830 const int debug
= 0;
1833 printf("size: %"PRIuSIZE
"\n", size
);
1834 printf("insns_info[%"PRIuSIZE
"]: position: %d, line: %d, pos: %"PRIuSIZE
"\n",
1835 i
, positions
[i
], insns_info
[i
].line_no
, pos
);
1841 else if (size
== 1) {
1842 return &insns_info
[0];
1845 for (i
=1; i
<size
; i
++) {
1846 if (debug
) printf("insns_info[%"PRIuSIZE
"]: position: %d, line: %d, pos: %"PRIuSIZE
"\n",
1847 i
, positions
[i
], insns_info
[i
].line_no
, pos
);
1849 if (positions
[i
] == pos
) {
1850 return &insns_info
[i
];
1852 if (positions
[i
] > pos
) {
1853 return &insns_info
[i
-1];
1857 return &insns_info
[i
-1];
1861 #if VM_INSN_INFO_TABLE_IMPL == 0 /* linear search */
1862 static const struct iseq_insn_info_entry
*
1863 get_insn_info(const rb_iseq_t
*iseq
, size_t pos
)
1865 return get_insn_info_linear_search(iseq
, pos
);
1869 #if VM_CHECK_MODE > 0 && VM_INSN_INFO_TABLE_IMPL > 0
1871 validate_get_insn_info(const rb_iseq_t
*iseq
)
1873 const struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
1875 for (i
= 0; i
< body
->iseq_size
; i
++) {
1876 if (get_insn_info_linear_search(iseq
, i
) != get_insn_info(iseq
, i
)) {
1877 rb_bug("validate_get_insn_info: get_insn_info_linear_search(iseq, %"PRIuSIZE
") != get_insn_info(iseq, %"PRIuSIZE
")", i
, i
);
1884 rb_iseq_line_no(const rb_iseq_t
*iseq
, size_t pos
)
1886 const struct iseq_insn_info_entry
*entry
= get_insn_info(iseq
, pos
);
1889 return entry
->line_no
;
1896 #ifdef USE_ISEQ_NODE_ID
1898 rb_iseq_node_id(const rb_iseq_t
*iseq
, size_t pos
)
1900 const struct iseq_insn_info_entry
*entry
= get_insn_info(iseq
, pos
);
1903 return entry
->node_id
;
1912 rb_iseq_event_flags(const rb_iseq_t
*iseq
, size_t pos
)
1914 const struct iseq_insn_info_entry
*entry
= get_insn_info(iseq
, pos
);
1916 return entry
->events
;
1924 rb_iseq_clear_event_flags(const rb_iseq_t
*iseq
, size_t pos
, rb_event_flag_t reset
)
1926 struct iseq_insn_info_entry
*entry
= (struct iseq_insn_info_entry
*)get_insn_info(iseq
, pos
);
1928 entry
->events
&= ~reset
;
1929 if (!(entry
->events
& iseq
->aux
.exec
.global_trace_events
)) {
1930 void rb_iseq_trace_flag_cleared(const rb_iseq_t
*iseq
, size_t pos
);
1931 rb_iseq_trace_flag_cleared(iseq
, pos
);
1937 local_var_name(const rb_iseq_t
*diseq
, VALUE level
, VALUE op
)
1944 for (i
= 0; i
< level
; i
++) {
1945 diseq
= ISEQ_BODY(diseq
)->parent_iseq
;
1947 idx
= ISEQ_BODY(diseq
)->local_table_size
- (int)op
- 1;
1948 lid
= ISEQ_BODY(diseq
)->local_table
[idx
];
1949 name
= rb_id2str(lid
);
1951 name
= rb_str_new_cstr("?");
1953 else if (!rb_str_symname_p(name
)) {
1954 name
= rb_str_inspect(name
);
1957 name
= rb_str_dup(name
);
1959 rb_str_catf(name
, "@%d", idx
);
1963 int rb_insn_unified_local_var_level(VALUE
);
1964 VALUE
rb_dump_literal(VALUE lit
);
1967 rb_insn_operand_intern(const rb_iseq_t
*iseq
,
1968 VALUE insn
, int op_no
, VALUE op
,
1969 int len
, size_t pos
, const VALUE
*pnop
, VALUE child
)
1971 const char *types
= insn_op_types(insn
);
1972 char type
= types
[op_no
];
1976 case TS_OFFSET
: /* LONG */
1977 ret
= rb_sprintf("%"PRIdVALUE
, (VALUE
)(pos
+ len
+ op
));
1980 case TS_NUM
: /* ULONG */
1981 if (insn
== BIN(defined
) && op_no
== 0) {
1982 enum defined_type deftype
= (enum defined_type
)op
;
1985 ret
= rb_fstring_lit("func");
1988 ret
= rb_fstring_lit("ref");
1990 case DEFINED_CONST_FROM
:
1991 ret
= rb_fstring_lit("constant-from");
1994 ret
= rb_iseq_defined_string(deftype
);
1999 else if (insn
== BIN(checktype
) && op_no
== 0) {
2000 const char *type_str
= rb_type_str((enum ruby_value_type
)op
);
2002 ret
= rb_str_new_cstr(type_str
); break;
2005 ret
= rb_sprintf("%"PRIuVALUE
, op
);
2010 if (types
[op_no
+1] == TS_NUM
&& pnop
) {
2011 ret
= local_var_name(iseq
, *pnop
, op
- VM_ENV_DATA_SIZE
);
2013 else if ((level
= rb_insn_unified_local_var_level(insn
)) >= 0) {
2014 ret
= local_var_name(iseq
, (VALUE
)level
, op
- VM_ENV_DATA_SIZE
);
2017 ret
= rb_inspect(INT2FIX(op
));
2021 case TS_ID
: /* ID (symbol) */
2022 ret
= rb_inspect(ID2SYM(op
));
2025 case TS_VALUE
: /* VALUE */
2026 op
= obj_resurrect(op
);
2027 if (insn
== BIN(defined
) && op_no
== 1 && FIXNUM_P(op
)) {
2028 /* should be DEFINED_REF */
2029 int type
= NUM2INT(op
);
2032 ret
= rb_sprintf(":$%c", (type
>> 1));
2035 ret
= rb_sprintf(":$%d", (type
>> 1));
2040 ret
= rb_dump_literal(op
);
2041 if (CLASS_OF(op
) == rb_cISeq
) {
2043 rb_ary_push(child
, op
);
2048 case TS_ISEQ
: /* iseq */
2051 const rb_iseq_t
*iseq
= rb_iseq_check((rb_iseq_t
*)op
);
2052 ret
= ISEQ_BODY(iseq
)->location
.label
;
2054 rb_ary_push(child
, (VALUE
)iseq
);
2058 ret
= rb_str_new2("nil");
2065 ret
= rb_sprintf("<ic:%"PRIdPTRDIFF
" ", (union iseq_inline_storage_entry
*)op
- ISEQ_BODY(iseq
)->is_entries
);
2066 const ID
*segments
= ((IC
)op
)->segments
;
2067 rb_str_cat2(ret
, rb_id2name(*segments
++));
2069 rb_str_catf(ret
, "::%s", rb_id2name(*segments
++));
2071 rb_str_cat2(ret
, ">");
2077 ret
= rb_sprintf("<is:%"PRIdPTRDIFF
">", (union iseq_inline_storage_entry
*)op
- ISEQ_BODY(iseq
)->is_entries
);
2082 struct rb_call_data
*cd
= (struct rb_call_data
*)op
;
2083 const struct rb_callinfo
*ci
= cd
->ci
;
2084 VALUE ary
= rb_ary_new();
2085 ID mid
= vm_ci_mid(ci
);
2088 rb_ary_push(ary
, rb_sprintf("mid:%"PRIsVALUE
, rb_id2str(mid
)));
2091 rb_ary_push(ary
, rb_sprintf("argc:%d", vm_ci_argc(ci
)));
2093 if (vm_ci_flag(ci
) & VM_CALL_KWARG
) {
2094 const struct rb_callinfo_kwarg
*kw_args
= vm_ci_kwarg(ci
);
2095 VALUE kw_ary
= rb_ary_new_from_values(kw_args
->keyword_len
, kw_args
->keywords
);
2096 rb_ary_push(ary
, rb_sprintf("kw:[%"PRIsVALUE
"]", rb_ary_join(kw_ary
, rb_str_new2(","))));
2099 if (vm_ci_flag(ci
)) {
2100 VALUE flags
= rb_ary_new();
2101 # define CALL_FLAG(n) if (vm_ci_flag(ci) & VM_CALL_##n) rb_ary_push(flags, rb_str_new2(#n))
2102 CALL_FLAG(ARGS_SPLAT
);
2103 CALL_FLAG(ARGS_BLOCKARG
);
2106 CALL_FLAG(ARGS_SIMPLE
);
2107 CALL_FLAG(BLOCKISEQ
);
2108 CALL_FLAG(TAILCALL
);
2112 CALL_FLAG(KW_SPLAT
);
2113 CALL_FLAG(KW_SPLAT_MUT
);
2114 CALL_FLAG(OPT_SEND
); /* maybe not reachable */
2115 rb_ary_push(ary
, rb_ary_join(flags
, rb_str_new2("|")));
2118 ret
= rb_sprintf("<calldata!%"PRIsVALUE
">", rb_ary_join(ary
, rb_str_new2(", ")));
2123 ret
= rb_str_new2("<cdhash>");
2130 if (dladdr((void *)op
, &info
) && info
.dli_sname
) {
2131 ret
= rb_str_new_cstr(info
.dli_sname
);
2135 ret
= rb_str_new2("<funcptr>");
2141 const struct rb_builtin_function
*bf
= (const struct rb_builtin_function
*)op
;
2142 ret
= rb_sprintf("<builtin!%s/%d>",
2143 bf
->name
, bf
->argc
);