Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)
iseq.c
Go to the documentation of this file.
1/**********************************************************************
2
3 iseq.c -
4
5 $Author$
6 created at: 2006-07-11(Tue) 09:00:03 +0900
7
8 Copyright (C) 2006 Koichi Sasada
9
10**********************************************************************/
11
12#define RUBY_VM_INSNS_INFO 1
13/* #define RUBY_MARK_FREE_DEBUG 1 */
14
16
17#ifdef HAVE_DLADDR
18# include <dlfcn.h>
19#endif
20
21#include "eval_intern.h"
22#include "gc.h"
23#include "id_table.h"
24#include "internal.h"
25#include "internal/bits.h"
26#include "internal/class.h"
27#include "internal/compile.h"
28#include "internal/error.h"
29#include "internal/file.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"
36#include "iseq.h"
37#include "mjit.h"
38#include "ruby/util.h"
39#include "vm_core.h"
40#include "vm_callinfo.h"
41
42#include "builtin.h"
43#include "insns.inc"
44#include "insns_info.inc"
45
47static VALUE iseqw_new(const rb_iseq_t *iseq);
48static const rb_iseq_t *iseqw_check(VALUE iseqw);
49
50#if VM_INSN_INFO_TABLE_IMPL == 2
51static struct succ_index_table *succ_index_table_create(int max_pos, int *data, int size);
52static unsigned int *succ_index_table_invert(int max_pos, struct succ_index_table *sd, int size);
53static int succ_index_lookup(const struct succ_index_table *sd, int x);
54#endif
55
56#define hidden_obj_p(obj) (!SPECIAL_CONST_P(obj) && !RBASIC(obj)->klass)
57
58static inline VALUE
59obj_resurrect(VALUE obj)
60{
61 if (hidden_obj_p(obj)) {
62 switch (BUILTIN_TYPE(obj)) {
63 case T_STRING:
64 obj = rb_str_resurrect(obj);
65 break;
66 case T_ARRAY:
67 obj = rb_ary_resurrect(obj);
68 break;
69 case T_HASH:
70 obj = rb_hash_resurrect(obj);
71 break;
72 default:
73 break;
74 }
75 }
76 return obj;
77}
78
79static void
80free_arena(struct iseq_compile_data_storage *cur)
81{
83
84 while (cur) {
85 next = cur->next;
86 ruby_xfree(cur);
87 cur = next;
88 }
89}
90
91static void
92compile_data_free(struct iseq_compile_data *compile_data)
93{
94 if (compile_data) {
95 free_arena(compile_data->node.storage_head);
96 free_arena(compile_data->insn.storage_head);
97 if (compile_data->ivar_cache_table) {
99 }
100 ruby_xfree(compile_data);
101 }
102}
103
104void
106{
107 RUBY_FREE_ENTER("iseq");
108
109 if (iseq && iseq->body) {
110 struct rb_iseq_constant_body *const body = iseq->body;
111 mjit_free_iseq(iseq); /* Notify MJIT */
112 ruby_xfree((void *)body->iseq_encoded);
113 ruby_xfree((void *)body->insns_info.body);
114 if (body->insns_info.positions) ruby_xfree((void *)body->insns_info.positions);
115#if VM_INSN_INFO_TABLE_IMPL == 2
116 if (body->insns_info.succ_index_table) ruby_xfree(body->insns_info.succ_index_table);
117#endif
119 ruby_xfree((void *)body->local_table);
120 ruby_xfree((void *)body->is_entries);
121
122 if (body->call_data) {
123 ruby_xfree(body->call_data);
124 }
125 ruby_xfree((void *)body->catch_table);
126 ruby_xfree((void *)body->param.opt_table);
127
128 if (body->param.keyword != NULL) {
129 ruby_xfree((void *)body->param.keyword->default_values);
130 ruby_xfree((void *)body->param.keyword);
131 }
132 compile_data_free(ISEQ_COMPILE_DATA(iseq));
134 ruby_xfree(body);
135 }
136
137 if (iseq && ISEQ_EXECUTABLE_P(iseq) && iseq->aux.exec.local_hooks) {
139 }
140
141 RUBY_FREE_LEAVE("iseq");
142}
143
144#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
145static VALUE
146rb_vm_insn_addr2insn2(const void *addr)
147{
148 return (VALUE)rb_vm_insn_addr2insn(addr);
149}
150#endif
151
152static VALUE
153rb_vm_insn_null_translator(const void *addr)
154{
155 return (VALUE)addr;
156}
157
158typedef VALUE iseq_value_itr_t(void *ctx, VALUE obj);
159typedef VALUE rb_vm_insns_translator_t(const void *addr);
160
161static int
162iseq_extract_values(VALUE *code, size_t pos, iseq_value_itr_t * func, void *data, rb_vm_insns_translator_t * translator)
163{
164 VALUE insn = translator((void *)code[pos]);
165 int len = insn_len(insn);
166 int op_no;
167 const char *types = insn_op_types(insn);
168
169 for (op_no = 0; types[op_no]; op_no++) {
170 char type = types[op_no];
171 switch (type) {
172 case TS_CDHASH:
173 case TS_ISEQ:
174 case TS_VALUE:
175 {
176 VALUE op = code[pos + op_no + 1];
177 if (!SPECIAL_CONST_P(op)) {
178 VALUE newop = func(data, op);
179 if (newop != op) {
180 code[pos + op_no + 1] = newop;
181 }
182 }
183 }
184 break;
185 case TS_IC:
186 {
187 IC ic = (IC)code[pos + op_no + 1];
188 if (ic->entry) {
189 VALUE nv = func(data, (VALUE)ic->entry);
190 if ((VALUE)ic->entry != nv) {
191 ic->entry = (void *)nv;
192 }
193 }
194 }
195 break;
196 case TS_IVC:
197 {
198 IVC ivc = (IVC)code[pos + op_no + 1];
199 if (ivc->entry) {
200 if (RB_TYPE_P(ivc->entry->class_value, T_NONE)) {
201 rb_bug("!! %u", ivc->entry->index);
202 }
203 VALUE nv = func(data, ivc->entry->class_value);
204 if (ivc->entry->class_value != nv) {
205 ivc->entry->class_value = nv;
206 }
207 }
208 }
209 break;
210 case TS_ISE:
211 {
212 union iseq_inline_storage_entry *const is = (union iseq_inline_storage_entry *)code[pos + op_no + 1];
213 if (is->once.value) {
214 VALUE nv = func(data, is->once.value);
215 if (is->once.value != nv) {
216 is->once.value = nv;
217 }
218 }
219 }
220 break;
221 default:
222 break;
223 }
224 }
225
226 return len;
227}
228
229static void
230rb_iseq_each_value(const rb_iseq_t *iseq, iseq_value_itr_t * func, void *data)
231{
232 unsigned int size;
233 VALUE *code;
234 size_t n;
235 rb_vm_insns_translator_t *const translator =
236#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
237 (FL_TEST((VALUE)iseq, ISEQ_TRANSLATED)) ? rb_vm_insn_addr2insn2 :
238#endif
239 rb_vm_insn_null_translator;
240 const struct rb_iseq_constant_body *const body = iseq->body;
241
242 size = body->iseq_size;
243 code = body->iseq_encoded;
244
245 for (n = 0; n < size;) {
246 n += iseq_extract_values(code, n, func, data, translator);
247 }
248}
249
250static VALUE
251update_each_insn_value(void *ctx, VALUE obj)
252{
253 return rb_gc_location(obj);
254}
255
256void
258{
259 if (iseq->body) {
260 struct rb_iseq_constant_body *body = iseq->body;
261
267 if (body->local_iseq) {
269 }
270 if (body->parent_iseq) {
272 }
273 if (body->call_data) {
274 for (unsigned int i=0; i<body->ci_size; i++) {
275 struct rb_call_data *cds = body->call_data;
276 if (!SPECIAL_CONST_P((VALUE)cds[i].ci)) {
277 cds[i].ci = (struct rb_callinfo *)rb_gc_location((VALUE)cds[i].ci);
278 }
279 cds[i].cc = (struct rb_callcache *)rb_gc_location((VALUE)cds[i].cc);
280 }
281 }
282 if (FL_TEST((VALUE)iseq, ISEQ_MARKABLE_ISEQ)) {
283 rb_iseq_each_value(iseq, update_each_insn_value, NULL);
284 VALUE *original_iseq = ISEQ_ORIGINAL_ISEQ(iseq);
285 if (original_iseq) {
286 size_t n = 0;
287 const unsigned int size = body->iseq_size;
288 while (n < size) {
289 n += iseq_extract_values(original_iseq, n, update_each_insn_value, NULL, rb_vm_insn_null_translator);
290 }
291 }
292 }
293
294 if (body->param.flags.has_kw && ISEQ_COMPILE_DATA(iseq) == NULL) {
295 int i, j;
296
297 i = body->param.keyword->required_num;
298
299 for (j = 0; i < body->param.keyword->num; i++, j++) {
300 VALUE obj = body->param.keyword->default_values[j];
301 if (obj != Qundef) {
302 body->param.keyword->default_values[j] = rb_gc_location(obj);
303 }
304 }
305 }
306
307 if (body->catch_table) {
308 struct iseq_catch_table *table = body->catch_table;
309 unsigned int i;
310 for (i = 0; i < table->size; i++) {
311 struct iseq_catch_table_entry *entry;
312 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
313 if (entry->iseq) {
314 entry->iseq = (rb_iseq_t *)rb_gc_location((VALUE)entry->iseq);
315 }
316 }
317 }
318#if USE_MJIT
319 mjit_update_references(iseq);
320#endif
321 }
322}
323
324static VALUE
325each_insn_value(void *ctx, VALUE obj)
326{
328 return obj;
329}
330
331void
333{
334 RUBY_MARK_ENTER("iseq");
335
337
338 if (iseq->body) {
339 const struct rb_iseq_constant_body *const body = iseq->body;
340
341 if (FL_TEST((VALUE)iseq, ISEQ_MARKABLE_ISEQ)) {
342 rb_iseq_each_value(iseq, each_insn_value, NULL);
343 }
344
351
352 if (body->call_data) {
353 struct rb_call_data *cds = (struct rb_call_data *)body->call_data;
354 for (unsigned int i=0; i<body->ci_size; i++) {
355 const struct rb_callinfo *ci = cds[i].ci;
356 const struct rb_callcache *cc = cds[i].cc;
357
358 if (vm_ci_markable(ci)) {
360 }
361 if (cc && vm_cc_markable(cc)) {
362 if (!vm_cc_invalidated_p(cc)) {
364 }
365 else {
366 cds[i].cc = rb_vm_empty_cc();
367 }
368 }
369 }
370 }
371
372 if (body->param.flags.has_kw && ISEQ_COMPILE_DATA(iseq) == NULL) {
373 const struct rb_iseq_param_keyword *const keyword = body->param.keyword;
374 int i, j;
375
376 i = keyword->required_num;
377
378 for (j = 0; i < keyword->num; i++, j++) {
379 VALUE obj = keyword->default_values[j];
380 if (!SPECIAL_CONST_P(obj)) {
382 }
383 }
384 }
385
386 if (body->catch_table) {
387 const struct iseq_catch_table *table = body->catch_table;
388 unsigned int i;
389 for (i = 0; i < table->size; i++) {
390 const struct iseq_catch_table_entry *entry;
391 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
392 if (entry->iseq) {
394 }
395 }
396 }
397
398#if USE_MJIT
399 mjit_mark_cc_entries(body);
400#endif
401 }
402
405 }
407 const struct iseq_compile_data *const compile_data = ISEQ_COMPILE_DATA(iseq);
408
410
411 RUBY_MARK_UNLESS_NULL(compile_data->err_info);
412 if (RTEST(compile_data->catch_table_ary)) {
413 rb_gc_mark(compile_data->catch_table_ary);
414 }
415 VM_ASSERT(compile_data != NULL);
416 }
417 else {
418 /* executable */
420 if (iseq->aux.exec.local_hooks) {
422 }
423 }
424
425 RUBY_MARK_LEAVE("iseq");
426}
427
428static size_t
429param_keyword_size(const struct rb_iseq_param_keyword *pkw)
430{
431 size_t size = 0;
432
433 if (!pkw) return size;
434
435 size += sizeof(struct rb_iseq_param_keyword);
436 size += sizeof(VALUE) * (pkw->num - pkw->required_num);
437
438 return size;
439}
440
441size_t
443{
444 size_t size = 0; /* struct already counted as RVALUE size */
445 const struct rb_iseq_constant_body *body = iseq->body;
446 const struct iseq_compile_data *compile_data;
447
448 /* TODO: should we count original_iseq? */
449
450 if (ISEQ_EXECUTABLE_P(iseq) && body) {
451 size += sizeof(struct rb_iseq_constant_body);
452 size += body->iseq_size * sizeof(VALUE);
453 size += body->insns_info.size * (sizeof(struct iseq_insn_info_entry) + sizeof(unsigned int));
454 size += body->local_table_size * sizeof(ID);
455 if (body->catch_table) {
456 size += iseq_catch_table_bytes(body->catch_table->size);
457 }
458 size += (body->param.opt_num + 1) * sizeof(VALUE);
459 size += param_keyword_size(body->param.keyword);
460
461 /* body->is_entries */
462 size += body->is_size * sizeof(union iseq_inline_storage_entry);
463
464 /* body->call_data */
465 size += body->ci_size * sizeof(struct rb_call_data);
466 // TODO: should we count imemo_callinfo?
467 }
468
469 compile_data = ISEQ_COMPILE_DATA(iseq);
470 if (compile_data) {
471 struct iseq_compile_data_storage *cur;
472
473 size += sizeof(struct iseq_compile_data);
474
475 cur = compile_data->node.storage_head;
476 while (cur) {
477 size += cur->size + offsetof(struct iseq_compile_data_storage, buff);
478 cur = cur->next;
479 }
480 }
481
482 return size;
483}
484
487{
488 struct rb_iseq_constant_body *iseq_body;
489 iseq_body = ZALLOC(struct rb_iseq_constant_body);
490 return iseq_body;
491}
492
493static rb_iseq_t *
494iseq_alloc(void)
495{
496 rb_iseq_t *iseq = iseq_imemo_alloc();
498 return iseq;
499}
500
501VALUE
503{
504 VALUE pathobj;
505 VM_ASSERT(RB_TYPE_P(path, T_STRING));
506 VM_ASSERT(realpath == Qnil || RB_TYPE_P(realpath, T_STRING));
507
508 if (path == realpath ||
509 (!NIL_P(realpath) && rb_str_cmp(path, realpath) == 0)) {
510 pathobj = rb_fstring(path);
511 }
512 else {
513 if (!NIL_P(realpath)) realpath = rb_fstring(realpath);
514 pathobj = rb_ary_new_from_args(2, rb_fstring(path), realpath);
515 rb_obj_freeze(pathobj);
516 }
517 return pathobj;
518}
519
520void
521rb_iseq_pathobj_set(const rb_iseq_t *iseq, VALUE path, VALUE realpath)
522{
523 RB_OBJ_WRITE(iseq, &iseq->body->location.pathobj,
524 rb_iseq_pathobj_new(path, realpath));
525}
526
527static rb_iseq_location_t *
528iseq_location_setup(rb_iseq_t *iseq, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_code_location_t *code_location, const int node_id)
529{
530 rb_iseq_location_t *loc = &iseq->body->location;
531
532 rb_iseq_pathobj_set(iseq, path, realpath);
533 RB_OBJ_WRITE(iseq, &loc->label, name);
534 RB_OBJ_WRITE(iseq, &loc->base_label, name);
535 loc->first_lineno = first_lineno;
536 if (code_location) {
537 loc->node_id = node_id;
538 loc->code_location = *code_location;
539 }
540 else {
543 loc->code_location.end_pos.lineno = -1;
544 loc->code_location.end_pos.column = -1;
545 }
546
547 return loc;
548}
549
550static void
551set_relation(rb_iseq_t *iseq, const rb_iseq_t *piseq)
552{
553 struct rb_iseq_constant_body *const body = iseq->body;
554 const VALUE type = body->type;
555
556 /* set class nest stack */
557 if (type == ISEQ_TYPE_TOP) {
558 body->local_iseq = iseq;
559 }
560 else if (type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) {
561 body->local_iseq = iseq;
562 }
563 else if (piseq) {
564 body->local_iseq = piseq->body->local_iseq;
565 }
566
567 if (piseq) {
568 body->parent_iseq = piseq;
569 }
570
571 if (type == ISEQ_TYPE_MAIN) {
572 body->local_iseq = iseq;
573 }
574}
575
576static struct iseq_compile_data_storage *
577new_arena(void)
578{
579 struct iseq_compile_data_storage * new_arena =
583
584 new_arena->pos = 0;
585 new_arena->next = 0;
587
588 return new_arena;
589}
590
591static VALUE
592prepare_iseq_build(rb_iseq_t *iseq,
593 VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_code_location_t *code_location, const int node_id,
594 const rb_iseq_t *parent, int isolated_depth, enum iseq_type type, const rb_compile_option_t *option)
595{
596 VALUE coverage = Qfalse;
597 VALUE err_info = Qnil;
598 struct rb_iseq_constant_body *const body = iseq->body;
599
600 if (parent && (type == ISEQ_TYPE_MAIN || type == ISEQ_TYPE_TOP))
601 err_info = Qfalse;
602
603 body->type = type;
604 set_relation(iseq, parent);
605
607 iseq_location_setup(iseq, name, path, realpath, first_lineno, code_location, node_id);
608 if (iseq != body->local_iseq) {
610 }
611 ISEQ_COVERAGE_SET(iseq, Qnil);
612 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
613 body->variable.flip_count = 0;
614
615 ISEQ_COMPILE_DATA_ALLOC(iseq);
616 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err_info);
617 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, Qnil);
618
619 ISEQ_COMPILE_DATA(iseq)->node.storage_head = ISEQ_COMPILE_DATA(iseq)->node.storage_current = new_arena();
620 ISEQ_COMPILE_DATA(iseq)->insn.storage_head = ISEQ_COMPILE_DATA(iseq)->insn.storage_current = new_arena();
621 ISEQ_COMPILE_DATA(iseq)->isolated_depth = isolated_depth;
622 ISEQ_COMPILE_DATA(iseq)->option = option;
623 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = NULL;
624 ISEQ_COMPILE_DATA(iseq)->builtin_function_table = GET_VM()->builtin_function_table;
625
626
627 if (option->coverage_enabled) {
628 VALUE coverages = rb_get_coverages();
629 if (RTEST(coverages)) {
630 coverage = rb_hash_lookup(coverages, rb_iseq_path(iseq));
632 }
633 }
635 if (coverage && ISEQ_BRANCH_COVERAGE(iseq))
637
638 return Qtrue;
639}
640
641#if VM_CHECK_MODE > 0 && VM_INSN_INFO_TABLE_IMPL > 0
642static void validate_get_insn_info(const rb_iseq_t *iseq);
643#endif
644
645void
647{
648#if VM_INSN_INFO_TABLE_IMPL == 2
649 /* create succ_index_table */
650 struct rb_iseq_constant_body *const body = iseq->body;
651 int size = body->insns_info.size;
652 int max_pos = body->iseq_size;
653 int *data = (int *)body->insns_info.positions;
654 if (body->insns_info.succ_index_table) ruby_xfree(body->insns_info.succ_index_table);
655 body->insns_info.succ_index_table = succ_index_table_create(max_pos, data, size);
656#if VM_CHECK_MODE == 0
658 body->insns_info.positions = NULL;
659#endif
660#endif
661}
662
663#if VM_INSN_INFO_TABLE_IMPL == 2
664unsigned int *
665rb_iseq_insns_info_decode_positions(const struct rb_iseq_constant_body *body)
666{
667 int size = body->insns_info.size;
668 int max_pos = body->iseq_size;
669 struct succ_index_table *sd = body->insns_info.succ_index_table;
670 return succ_index_table_invert(max_pos, sd, size);
671}
672#endif
673
674void
676{
677 iseq->aux.exec.global_trace_events = 0;
680 }
681}
682
683static VALUE
684finish_iseq_build(rb_iseq_t *iseq)
685{
686 struct iseq_compile_data *data = ISEQ_COMPILE_DATA(iseq);
687 const struct rb_iseq_constant_body *const body = iseq->body;
688 VALUE err = data->err_info;
689 ISEQ_COMPILE_DATA_CLEAR(iseq);
690 compile_data_free(data);
691
692#if VM_CHECK_MODE > 0 && VM_INSN_INFO_TABLE_IMPL > 0
693 validate_get_insn_info(iseq);
694#endif
695
696 if (RTEST(err)) {
697 VALUE path = pathobj_path(body->location.pathobj);
698 if (err == Qtrue) err = rb_exc_new_cstr(rb_eSyntaxError, "compile error");
699 rb_funcallv(err, rb_intern("set_backtrace"), 1, &path);
701 }
702
703 RB_DEBUG_COUNTER_INC(iseq_num);
704 RB_DEBUG_COUNTER_ADD(iseq_cd_num, iseq->body->ci_size);
705
706 rb_iseq_init_trace(iseq);
707 return Qtrue;
708}
709
710static rb_compile_option_t COMPILE_OPTION_DEFAULT = {
711 OPT_INLINE_CONST_CACHE, /* int inline_const_cache; */
712 OPT_PEEPHOLE_OPTIMIZATION, /* int peephole_optimization; */
713 OPT_TAILCALL_OPTIMIZATION, /* int tailcall_optimization */
714 OPT_SPECIALISED_INSTRUCTION, /* int specialized_instruction; */
715 OPT_OPERANDS_UNIFICATION, /* int operands_unification; */
716 OPT_INSTRUCTIONS_UNIFICATION, /* int instructions_unification; */
717 OPT_STACK_CACHING, /* int stack_caching; */
720 TRUE, /* coverage_enabled */
721};
722
723static const rb_compile_option_t COMPILE_OPTION_FALSE = {0};
724
725static void
726set_compile_option_from_hash(rb_compile_option_t *option, VALUE opt)
727{
728#define SET_COMPILE_OPTION(o, h, mem) \
729 { VALUE flag = rb_hash_aref((h), ID2SYM(rb_intern(#mem))); \
730 if (flag == Qtrue) { (o)->mem = 1; } \
731 else if (flag == Qfalse) { (o)->mem = 0; } \
732 }
733#define SET_COMPILE_OPTION_NUM(o, h, mem) \
734 { VALUE num = rb_hash_aref(opt, ID2SYM(rb_intern(#mem))); \
735 if (!NIL_P(num)) (o)->mem = NUM2INT(num); \
736 }
737 SET_COMPILE_OPTION(option, opt, inline_const_cache);
738 SET_COMPILE_OPTION(option, opt, peephole_optimization);
739 SET_COMPILE_OPTION(option, opt, tailcall_optimization);
740 SET_COMPILE_OPTION(option, opt, specialized_instruction);
741 SET_COMPILE_OPTION(option, opt, operands_unification);
742 SET_COMPILE_OPTION(option, opt, instructions_unification);
743 SET_COMPILE_OPTION(option, opt, stack_caching);
744 SET_COMPILE_OPTION(option, opt, frozen_string_literal);
745 SET_COMPILE_OPTION(option, opt, debug_frozen_string_literal);
746 SET_COMPILE_OPTION(option, opt, coverage_enabled);
747 SET_COMPILE_OPTION_NUM(option, opt, debug_level);
748#undef SET_COMPILE_OPTION
749#undef SET_COMPILE_OPTION_NUM
750}
751
752static void
753rb_iseq_make_compile_option(rb_compile_option_t *option, VALUE opt)
754{
755 Check_Type(opt, T_HASH);
756 set_compile_option_from_hash(option, opt);
757}
758
759static void
760make_compile_option(rb_compile_option_t *option, VALUE opt)
761{
762 if (opt == Qnil) {
763 *option = COMPILE_OPTION_DEFAULT;
764 }
765 else if (opt == Qfalse) {
766 *option = COMPILE_OPTION_FALSE;
767 }
768 else if (opt == Qtrue) {
769 int i;
770 for (i = 0; i < (int)(sizeof(rb_compile_option_t) / sizeof(int)); ++i)
771 ((int *)option)[i] = 1;
772 }
773 else if (RB_TYPE_P(opt, T_HASH)) {
774 *option = COMPILE_OPTION_DEFAULT;
775 set_compile_option_from_hash(option, opt);
776 }
777 else {
778 rb_raise(rb_eTypeError, "Compile option must be Hash/true/false/nil");
779 }
780}
781
782static VALUE
783make_compile_option_value(rb_compile_option_t *option)
784{
786#define SET_COMPILE_OPTION(o, h, mem) \
787 rb_hash_aset((h), ID2SYM(rb_intern(#mem)), (o)->mem ? Qtrue : Qfalse)
788#define SET_COMPILE_OPTION_NUM(o, h, mem) \
789 rb_hash_aset((h), ID2SYM(rb_intern(#mem)), INT2NUM((o)->mem))
790 {
791 SET_COMPILE_OPTION(option, opt, inline_const_cache);
792 SET_COMPILE_OPTION(option, opt, peephole_optimization);
793 SET_COMPILE_OPTION(option, opt, tailcall_optimization);
794 SET_COMPILE_OPTION(option, opt, specialized_instruction);
795 SET_COMPILE_OPTION(option, opt, operands_unification);
796 SET_COMPILE_OPTION(option, opt, instructions_unification);
797 SET_COMPILE_OPTION(option, opt, stack_caching);
798 SET_COMPILE_OPTION(option, opt, frozen_string_literal);
799 SET_COMPILE_OPTION(option, opt, debug_frozen_string_literal);
800 SET_COMPILE_OPTION(option, opt, coverage_enabled);
801 SET_COMPILE_OPTION_NUM(option, opt, debug_level);
802 }
803#undef SET_COMPILE_OPTION
804#undef SET_COMPILE_OPTION_NUM
805 return opt;
806}
807
808rb_iseq_t *
809rb_iseq_new(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath,
810 const rb_iseq_t *parent, enum iseq_type type)
811{
812 return rb_iseq_new_with_opt(ast, name, path, realpath, INT2FIX(0), parent,
813 0, type, &COMPILE_OPTION_DEFAULT);
814}
815
816rb_iseq_t *
817rb_iseq_new_top(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent)
818{
819 VALUE coverages = rb_get_coverages();
820 if (RTEST(coverages)) {
821 if (ast->line_count >= 0) {
824 rb_hash_aset(coverages, path, coverage);
825 }
826 }
827
828 return rb_iseq_new_with_opt(ast, name, path, realpath, INT2FIX(0), parent, 0,
829 ISEQ_TYPE_TOP, &COMPILE_OPTION_DEFAULT);
830}
831
832rb_iseq_t *
833rb_iseq_new_main(const rb_ast_body_t *ast, VALUE path, VALUE realpath, const rb_iseq_t *parent)
834{
835 return rb_iseq_new_with_opt(ast, rb_fstring_lit("<main>"),
836 path, realpath, INT2FIX(0),
837 parent, 0, ISEQ_TYPE_MAIN, &COMPILE_OPTION_DEFAULT);
838}
839
840rb_iseq_t *
841rb_iseq_new_eval(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_iseq_t *parent, int isolated_depth)
842{
843 return rb_iseq_new_with_opt(ast, name, path, realpath, first_lineno,
844 parent, isolated_depth, ISEQ_TYPE_EVAL, &COMPILE_OPTION_DEFAULT);
845}
846
847static inline rb_iseq_t *
848iseq_translate(rb_iseq_t *iseq)
849{
850 if (rb_respond_to(rb_cISeq, rb_intern("translate"))) {
851 VALUE v1 = iseqw_new(iseq);
852 VALUE v2 = rb_funcall(rb_cISeq, rb_intern("translate"), 1, v1);
853 if (v1 != v2 && CLASS_OF(v2) == rb_cISeq) {
854 iseq = (rb_iseq_t *)iseqw_check(v2);
855 }
856 }
857
858 return iseq;
859}
860
861rb_iseq_t *
863 VALUE first_lineno, const rb_iseq_t *parent, int isolated_depth,
864 enum iseq_type type, const rb_compile_option_t *option)
865{
866 const NODE *node = ast ? ast->root : 0;
867 /* TODO: argument check */
868 rb_iseq_t *iseq = iseq_alloc();
869 rb_compile_option_t new_opt;
870
871 if (option) {
872 new_opt = *option;
873 }
874 else {
875 new_opt = COMPILE_OPTION_DEFAULT;
876 }
877 if (ast && ast->compile_option) rb_iseq_make_compile_option(&new_opt, ast->compile_option);
878
879 prepare_iseq_build(iseq, name, path, realpath, first_lineno, node ? &node->nd_loc : NULL, node ? nd_node_id(node) : -1, parent, isolated_depth, type, &new_opt);
880
881 rb_iseq_compile_node(iseq, node);
882 finish_iseq_build(iseq);
883
884 return iseq_translate(iseq);
885}
886
887rb_iseq_t *
889 const struct rb_iseq_new_with_callback_callback_func * ifunc,
890 VALUE name, VALUE path, VALUE realpath,
891 VALUE first_lineno, const rb_iseq_t *parent,
892 enum iseq_type type, const rb_compile_option_t *option)
893{
894 /* TODO: argument check */
895 rb_iseq_t *iseq = iseq_alloc();
896
897 if (!option) option = &COMPILE_OPTION_DEFAULT;
898 prepare_iseq_build(iseq, name, path, realpath, first_lineno, NULL, -1, parent, 0, type, option);
899
900 rb_iseq_compile_callback(iseq, ifunc);
901 finish_iseq_build(iseq);
902
903 return iseq;
904}
905
906const rb_iseq_t *
908{
909 VALUE iseqv = rb_check_funcall(rb_cISeq, rb_intern("load_iseq"), 1, &fname);
910
911 if (!SPECIAL_CONST_P(iseqv) && RBASIC_CLASS(iseqv) == rb_cISeq) {
912 return iseqw_check(iseqv);
913 }
914
915 return NULL;
916}
917
918#define CHECK_ARRAY(v) rb_to_array_type(v)
919#define CHECK_HASH(v) rb_to_hash_type(v)
920#define CHECK_STRING(v) rb_str_to_str(v)
921#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
922static inline VALUE CHECK_INTEGER(VALUE v) {(void)NUM2LONG(v); return v;}
923
924static enum iseq_type
925iseq_type_from_sym(VALUE type)
926{
927 const ID id_top = rb_intern("top");
928 const ID id_method = rb_intern("method");
929 const ID id_block = rb_intern("block");
930 const ID id_class = rb_intern("class");
931 const ID id_rescue = rb_intern("rescue");
932 const ID id_ensure = rb_intern("ensure");
933 const ID id_eval = rb_intern("eval");
934 const ID id_main = rb_intern("main");
935 const ID id_plain = rb_intern("plain");
936 /* ensure all symbols are static or pinned down before
937 * conversion */
938 const ID typeid = rb_check_id(&type);
939 if (typeid == id_top) return ISEQ_TYPE_TOP;
940 if (typeid == id_method) return ISEQ_TYPE_METHOD;
941 if (typeid == id_block) return ISEQ_TYPE_BLOCK;
942 if (typeid == id_class) return ISEQ_TYPE_CLASS;
943 if (typeid == id_rescue) return ISEQ_TYPE_RESCUE;
944 if (typeid == id_ensure) return ISEQ_TYPE_ENSURE;
945 if (typeid == id_eval) return ISEQ_TYPE_EVAL;
946 if (typeid == id_main) return ISEQ_TYPE_MAIN;
947 if (typeid == id_plain) return ISEQ_TYPE_PLAIN;
948 return (enum iseq_type)-1;
949}
950
951static VALUE
952iseq_load(VALUE data, const rb_iseq_t *parent, VALUE opt)
953{
954 rb_iseq_t *iseq = iseq_alloc();
955
956 VALUE magic, version1, version2, format_type, misc;
957 VALUE name, path, realpath, first_lineno, code_location, node_id;
958 VALUE type, body, locals, params, exception;
959
961 rb_compile_option_t option;
962 int i = 0;
963 rb_code_location_t tmp_loc = { {0, 0}, {-1, -1} };
964
965 /* [magic, major_version, minor_version, format_type, misc,
966 * label, path, first_lineno,
967 * type, locals, args, exception_table, body]
968 */
969
970 data = CHECK_ARRAY(data);
971
972 magic = CHECK_STRING(rb_ary_entry(data, i++));
973 version1 = CHECK_INTEGER(rb_ary_entry(data, i++));
974 version2 = CHECK_INTEGER(rb_ary_entry(data, i++));
975 format_type = CHECK_INTEGER(rb_ary_entry(data, i++));
976 misc = CHECK_HASH(rb_ary_entry(data, i++));
977 ((void)magic, (void)version1, (void)version2, (void)format_type);
978
979 name = CHECK_STRING(rb_ary_entry(data, i++));
980 path = CHECK_STRING(rb_ary_entry(data, i++));
981 realpath = rb_ary_entry(data, i++);
982 realpath = NIL_P(realpath) ? Qnil : CHECK_STRING(realpath);
983 first_lineno = CHECK_INTEGER(rb_ary_entry(data, i++));
984
985 type = CHECK_SYMBOL(rb_ary_entry(data, i++));
986 locals = CHECK_ARRAY(rb_ary_entry(data, i++));
987 params = CHECK_HASH(rb_ary_entry(data, i++));
988 exception = CHECK_ARRAY(rb_ary_entry(data, i++));
989 body = CHECK_ARRAY(rb_ary_entry(data, i++));
990
991 iseq->body->local_iseq = iseq;
992
993 iseq_type = iseq_type_from_sym(type);
994 if (iseq_type == (enum iseq_type)-1) {
995 rb_raise(rb_eTypeError, "unsupported type: :%"PRIsVALUE, rb_sym2str(type));
996 }
997
998 node_id = rb_hash_aref(misc, ID2SYM(rb_intern("node_id")));
999
1000 code_location = rb_hash_aref(misc, ID2SYM(rb_intern("code_location")));
1001 if (RB_TYPE_P(code_location, T_ARRAY) && RARRAY_LEN(code_location) == 4) {
1002 tmp_loc.beg_pos.lineno = NUM2INT(rb_ary_entry(code_location, 0));
1003 tmp_loc.beg_pos.column = NUM2INT(rb_ary_entry(code_location, 1));
1004 tmp_loc.end_pos.lineno = NUM2INT(rb_ary_entry(code_location, 2));
1005 tmp_loc.end_pos.column = NUM2INT(rb_ary_entry(code_location, 3));
1006 }
1007
1008 make_compile_option(&option, opt);
1009 option.peephole_optimization = FALSE; /* because peephole optimization can modify original iseq */
1010 prepare_iseq_build(iseq, name, path, realpath, first_lineno, &tmp_loc, NUM2INT(node_id),
1011 parent, 0, (enum iseq_type)iseq_type, &option);
1012
1013 rb_iseq_build_from_ary(iseq, misc, locals, params, exception, body);
1014
1015 finish_iseq_build(iseq);
1016
1017 return iseqw_new(iseq);
1018}
1019
1020/*
1021 * :nodoc:
1022 */
1023static VALUE
1024iseq_s_load(int argc, VALUE *argv, VALUE self)
1025{
1026 VALUE data, opt=Qnil;
1027 rb_scan_args(argc, argv, "11", &data, &opt);
1028 return iseq_load(data, NULL, opt);
1029}
1030
1031VALUE
1032rb_iseq_load(VALUE data, VALUE parent, VALUE opt)
1033{
1034 return iseq_load(data, RTEST(parent) ? (rb_iseq_t *)parent : NULL, opt);
1035}
1036
1037static rb_iseq_t *
1038rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, VALUE opt)
1039{
1040 rb_iseq_t *iseq = NULL;
1041 rb_compile_option_t option;
1042#if !defined(__GNUC__) || (__GNUC__ == 4 && __GNUC_MINOR__ == 8)
1043# define INITIALIZED volatile /* suppress warnings by gcc 4.8 */
1044#else
1045# define INITIALIZED /* volatile */
1046#endif
1047 rb_ast_t *(*parse)(VALUE vparser, VALUE fname, VALUE file, int start);
1048 int ln;
1049 rb_ast_t *INITIALIZED ast;
1050
1051 /* safe results first */
1052 make_compile_option(&option, opt);
1053 ln = NUM2INT(line);
1055 if (RB_TYPE_P(src, T_FILE)) {
1057 }
1058 else {
1060 StringValue(src);
1061 }
1062 {
1063 const VALUE parser = rb_parser_new();
1064 VALUE name = rb_fstring_lit("<compiled>");
1065 const rb_iseq_t *outer_scope = rb_iseq_new(NULL, name, name, Qnil, 0, ISEQ_TYPE_TOP);
1066 VALUE outer_scope_v = (VALUE)outer_scope;
1067 rb_parser_set_context(parser, outer_scope, FALSE);
1068 RB_GC_GUARD(outer_scope_v);
1069 ast = (*parse)(parser, file, src, ln);
1070 }
1071
1072 if (!ast->body.root) {
1073 rb_ast_dispose(ast);
1074 rb_exc_raise(GET_EC()->errinfo);
1075 }
1076 else {
1077 INITIALIZED VALUE label = rb_fstring_lit("<compiled>");
1078 iseq = rb_iseq_new_with_opt(&ast->body, label, file, realpath, line,
1079 NULL, 0, ISEQ_TYPE_TOP, &option);
1080 rb_ast_dispose(ast);
1081 }
1082
1083 return iseq;
1084}
1085
1086VALUE
1088{
1089 return pathobj_path(iseq->body->location.pathobj);
1090}
1091
1092VALUE
1094{
1095 return pathobj_realpath(iseq->body->location.pathobj);
1096}
1097
1098VALUE
1100{
1101 return rb_iseq_realpath(iseq);
1102}
1103
1104VALUE
1106{
1107 return iseq->body->location.label;
1108}
1109
1110VALUE
1112{
1113 return iseq->body->location.base_label;
1114}
1115
1116VALUE
1118{
1119 return iseq->body->location.first_lineno;
1120}
1121
1122VALUE
1124{
1125 struct rb_iseq_constant_body *const body = iseq->body->local_iseq->body;
1126
1127 if (body->type == ISEQ_TYPE_METHOD) {
1128 return body->location.base_label;
1129 }
1130 else {
1131 return Qnil;
1132 }
1133}
1134
1135void
1136rb_iseq_code_location(const rb_iseq_t *iseq, int *beg_pos_lineno, int *beg_pos_column, int *end_pos_lineno, int *end_pos_column)
1137{
1138 const rb_code_location_t *loc = &iseq->body->location.code_location;
1139 if (beg_pos_lineno) *beg_pos_lineno = loc->beg_pos.lineno;
1140 if (beg_pos_column) *beg_pos_column = loc->beg_pos.column;
1141 if (end_pos_lineno) *end_pos_lineno = loc->end_pos.lineno;
1142 if (end_pos_column) *end_pos_column = loc->end_pos.column;
1143}
1144
1145VALUE
1147{
1148 return ISEQ_COVERAGE(iseq);
1149}
1150
1151static int
1152remove_coverage_i(void *vstart, void *vend, size_t stride, void *data)
1153{
1154 VALUE v = (VALUE)vstart;
1155 for (; v != (VALUE)vend; v += stride) {
1156 void *ptr = asan_poisoned_object_p(v);
1157 asan_unpoison_object(v, false);
1158
1159 if (rb_obj_is_iseq(v)) {
1160 rb_iseq_t *iseq = (rb_iseq_t *)v;
1161 ISEQ_COVERAGE_SET(iseq, Qnil);
1162 }
1163
1165 }
1166 return 0;
1167}
1168
1169void
1171{
1172 rb_objspace_each_objects(remove_coverage_i, NULL);
1173}
1174
1175/* define wrapper class methods (RubyVM::InstructionSequence) */
1176
1177static void
1178iseqw_mark(void *ptr)
1179{
1181}
1182
1183static size_t
1184iseqw_memsize(const void *ptr)
1185{
1186 return rb_iseq_memsize((const rb_iseq_t *)ptr);
1187}
1188
1189static const rb_data_type_t iseqw_data_type = {
1190 "T_IMEMO/iseq",
1191 {iseqw_mark, NULL, iseqw_memsize,},
1193};
1194
1195static VALUE
1196iseqw_new(const rb_iseq_t *iseq)
1197{
1198 if (iseq->wrapper) {
1199 return iseq->wrapper;
1200 }
1201 else {
1202 union { const rb_iseq_t *in; void *out; } deconst;
1203 VALUE obj;
1204 deconst.in = iseq;
1205 obj = TypedData_Wrap_Struct(rb_cISeq, &iseqw_data_type, deconst.out);
1206 RB_OBJ_WRITTEN(obj, Qundef, iseq);
1207
1208 /* cache a wrapper object */
1209 RB_OBJ_WRITE((VALUE)iseq, &iseq->wrapper, obj);
1210 RB_OBJ_FREEZE((VALUE)iseq);
1211
1212 return obj;
1213 }
1214}
1215
1216VALUE
1218{
1219 return iseqw_new(iseq);
1220}
1221
1222/*
1223 * call-seq:
1224 * InstructionSequence.compile(source[, file[, path[, line[, options]]]]) -> iseq
1225 * InstructionSequence.new(source[, file[, path[, line[, options]]]]) -> iseq
1226 *
1227 * Takes +source+, a String of Ruby code and compiles it to an
1228 * InstructionSequence.
1229 *
1230 * Optionally takes +file+, +path+, and +line+ which describe the file path,
1231 * real path and first line number of the ruby code in +source+ which are
1232 * metadata attached to the returned +iseq+.
1233 *
1234 * +file+ is used for `__FILE__` and exception backtrace. +path+ is used for
1235 * +require_relative+ base. It is recommended these should be the same full
1236 * path.
1237 *
1238 * +options+, which can be +true+, +false+ or a +Hash+, is used to
1239 * modify the default behavior of the Ruby iseq compiler.
1240 *
1241 * For details regarding valid compile options see ::compile_option=.
1242 *
1243 * RubyVM::InstructionSequence.compile("a = 1 + 2")
1244 * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
1245 *
1246 * path = "test.rb"
1247 * RubyVM::InstructionSequence.compile(File.read(path), path, File.expand_path(path))
1248 * #=> <RubyVM::InstructionSequence:<compiled>@test.rb:1>
1249 *
1250 * path = File.expand_path("test.rb")
1251 * RubyVM::InstructionSequence.compile(File.read(path), path, path)
1252 * #=> <RubyVM::InstructionSequence:<compiled>@/absolute/path/to/test.rb:1>
1253 *
1254 */
1255static VALUE
1256iseqw_s_compile(int argc, VALUE *argv, VALUE self)
1257{
1258 VALUE src, file = Qnil, path = Qnil, line = INT2FIX(1), opt = Qnil;
1259 int i;
1260
1261 i = rb_scan_args(argc, argv, "1*:", &src, NULL, &opt);
1262 if (i > 4+NIL_P(opt)) rb_error_arity(argc, 1, 5);
1263 switch (i) {
1264 case 5: opt = argv[--i];
1265 case 4: line = argv[--i];
1266 case 3: path = argv[--i];
1267 case 2: file = argv[--i];
1268 }
1269
1270 if (NIL_P(file)) file = rb_fstring_lit("<compiled>");
1271 if (NIL_P(path)) path = file;
1272 if (NIL_P(line)) line = INT2FIX(1);
1273
1274 Check_Type(path, T_STRING);
1275 Check_Type(file, T_STRING);
1276
1277 return iseqw_new(rb_iseq_compile_with_option(src, file, path, line, opt));
1278}
1279
1280/*
1281 * call-seq:
1282 * InstructionSequence.compile_file(file[, options]) -> iseq
1283 *
1284 * Takes +file+, a String with the location of a Ruby source file, reads,
1285 * parses and compiles the file, and returns +iseq+, the compiled
1286 * InstructionSequence with source location metadata set.
1287 *
1288 * Optionally takes +options+, which can be +true+, +false+ or a +Hash+, to
1289 * modify the default behavior of the Ruby iseq compiler.
1290 *
1291 * For details regarding valid compile options see ::compile_option=.
1292 *
1293 * # /tmp/hello.rb
1294 * puts "Hello, world!"
1295 *
1296 * # elsewhere
1297 * RubyVM::InstructionSequence.compile_file("/tmp/hello.rb")
1298 * #=> <RubyVM::InstructionSequence:<main>@/tmp/hello.rb>
1299 */
1300static VALUE
1301iseqw_s_compile_file(int argc, VALUE *argv, VALUE self)
1302{
1303 VALUE file, line = INT2FIX(1), opt = Qnil;
1304 VALUE parser, f, exc = Qnil, ret;
1305 rb_ast_t *ast;
1306 rb_compile_option_t option;
1307 int i;
1308
1309 i = rb_scan_args(argc, argv, "1*:", &file, NULL, &opt);
1310 if (i > 1+NIL_P(opt)) rb_error_arity(argc, 1, 2);
1311 switch (i) {
1312 case 2: opt = argv[--i];
1313 }
1315 file = rb_fstring(file); /* rb_io_t->pathv gets frozen anyways */
1316
1317 f = rb_file_open_str(file, "r");
1318
1319 parser = rb_parser_new();
1321 ast = (rb_ast_t *)rb_parser_load_file(parser, file);
1322 if (!ast->body.root) exc = GET_EC()->errinfo;
1323
1324 rb_io_close(f);
1325 if (!ast->body.root) {
1326 rb_ast_dispose(ast);
1327 rb_exc_raise(exc);
1328 }
1329
1330 make_compile_option(&option, opt);
1331
1332 ret = iseqw_new(rb_iseq_new_with_opt(&ast->body, rb_fstring_lit("<main>"),
1333 file,
1335 line, NULL, 0, ISEQ_TYPE_TOP, &option));
1336 rb_ast_dispose(ast);
1337 return ret;
1338}
1339
1340/*
1341 * call-seq:
1342 * InstructionSequence.compile_option = options
1343 *
1344 * Sets the default values for various optimizations in the Ruby iseq
1345 * compiler.
1346 *
1347 * Possible values for +options+ include +true+, which enables all options,
1348 * +false+ which disables all options, and +nil+ which leaves all options
1349 * unchanged.
1350 *
1351 * You can also pass a +Hash+ of +options+ that you want to change, any
1352 * options not present in the hash will be left unchanged.
1353 *
1354 * Possible option names (which are keys in +options+) which can be set to
1355 * +true+ or +false+ include:
1356 *
1357 * * +:inline_const_cache+
1358 * * +:instructions_unification+
1359 * * +:operands_unification+
1360 * * +:peephole_optimization+
1361 * * +:specialized_instruction+
1362 * * +:stack_caching+
1363 * * +:tailcall_optimization+
1364 *
1365 * Additionally, +:debug_level+ can be set to an integer.
1366 *
1367 * These default options can be overwritten for a single run of the iseq
1368 * compiler by passing any of the above values as the +options+ parameter to
1369 * ::new, ::compile and ::compile_file.
1370 */
1371static VALUE
1372iseqw_s_compile_option_set(VALUE self, VALUE opt)
1373{
1374 rb_compile_option_t option;
1375 make_compile_option(&option, opt);
1376 COMPILE_OPTION_DEFAULT = option;
1377 return opt;
1378}
1379
1380/*
1381 * call-seq:
1382 * InstructionSequence.compile_option -> options
1383 *
1384 * Returns a hash of default options used by the Ruby iseq compiler.
1385 *
1386 * For details, see InstructionSequence.compile_option=.
1387 */
1388static VALUE
1389iseqw_s_compile_option_get(VALUE self)
1390{
1391 return make_compile_option_value(&COMPILE_OPTION_DEFAULT);
1392}
1393
1394static const rb_iseq_t *
1395iseqw_check(VALUE iseqw)
1396{
1397 rb_iseq_t *iseq = DATA_PTR(iseqw);
1398
1399 if (!iseq->body) {
1401 }
1402
1403 if (!iseq->body->location.label) {
1404 rb_raise(rb_eTypeError, "uninitialized InstructionSequence");
1405 }
1406 return iseq;
1407}
1408
1409const rb_iseq_t *
1411{
1412 return iseqw_check(iseqw);
1413}
1414
1415/*
1416 * call-seq:
1417 * iseq.eval -> obj
1418 *
1419 * Evaluates the instruction sequence and returns the result.
1420 *
1421 * RubyVM::InstructionSequence.compile("1 + 2").eval #=> 3
1422 */
1423static VALUE
1424iseqw_eval(VALUE self)
1425{
1426 return rb_iseq_eval(iseqw_check(self));
1427}
1428
1429/*
1430 * Returns a human-readable string representation of this instruction
1431 * sequence, including the #label and #path.
1432 */
1433static VALUE
1434iseqw_inspect(VALUE self)
1435{
1436 const rb_iseq_t *iseq = iseqw_check(self);
1437 const struct rb_iseq_constant_body *const body = iseq->body;
1438 VALUE klass = rb_class_name(rb_obj_class(self));
1439
1440 if (!body->location.label) {
1441 return rb_sprintf("#<%"PRIsVALUE": uninitialized>", klass);
1442 }
1443 else {
1444 return rb_sprintf("<%"PRIsVALUE":%"PRIsVALUE"@%"PRIsVALUE":%d>",
1445 klass,
1446 body->location.label, rb_iseq_path(iseq),
1448 }
1449}
1450
1451/*
1452 * Returns the path of this instruction sequence.
1453 *
1454 * <code><compiled></code> if the iseq was evaluated from a string.
1455 *
1456 * For example, using irb:
1457 *
1458 * iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
1459 * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
1460 * iseq.path
1461 * #=> "<compiled>"
1462 *
1463 * Using ::compile_file:
1464 *
1465 * # /tmp/method.rb
1466 * def hello
1467 * puts "hello, world"
1468 * end
1469 *
1470 * # in irb
1471 * > iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
1472 * > iseq.path #=> /tmp/method.rb
1473 */
1474static VALUE
1475iseqw_path(VALUE self)
1476{
1477 return rb_iseq_path(iseqw_check(self));
1478}
1479
1480/*
1481 * Returns the absolute path of this instruction sequence.
1482 *
1483 * +nil+ if the iseq was evaluated from a string.
1484 *
1485 * For example, using ::compile_file:
1486 *
1487 * # /tmp/method.rb
1488 * def hello
1489 * puts "hello, world"
1490 * end
1491 *
1492 * # in irb
1493 * > iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
1494 * > iseq.absolute_path #=> /tmp/method.rb
1495 */
1496static VALUE
1497iseqw_absolute_path(VALUE self)
1498{
1499 return rb_iseq_realpath(iseqw_check(self));
1500}
1501
1502/* Returns the label of this instruction sequence.
1503 *
1504 * <code><main></code> if it's at the top level, <code><compiled></code> if it
1505 * was evaluated from a string.
1506 *
1507 * For example, using irb:
1508 *
1509 * iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
1510 * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
1511 * iseq.label
1512 * #=> "<compiled>"
1513 *
1514 * Using ::compile_file:
1515 *
1516 * # /tmp/method.rb
1517 * def hello
1518 * puts "hello, world"
1519 * end
1520 *
1521 * # in irb
1522 * > iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
1523 * > iseq.label #=> <main>
1524 */
1525static VALUE
1526iseqw_label(VALUE self)
1527{
1528 return rb_iseq_label(iseqw_check(self));
1529}
1530
1531/* Returns the base label of this instruction sequence.
1532 *
1533 * For example, using irb:
1534 *
1535 * iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
1536 * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
1537 * iseq.base_label
1538 * #=> "<compiled>"
1539 *
1540 * Using ::compile_file:
1541 *
1542 * # /tmp/method.rb
1543 * def hello
1544 * puts "hello, world"
1545 * end
1546 *
1547 * # in irb
1548 * > iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
1549 * > iseq.base_label #=> <main>
1550 */
1551static VALUE
1552iseqw_base_label(VALUE self)
1553{
1554 return rb_iseq_base_label(iseqw_check(self));
1555}
1556
1557/* Returns the number of the first source line where the instruction sequence
1558 * was loaded from.
1559 *
1560 * For example, using irb:
1561 *
1562 * iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
1563 * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
1564 * iseq.first_lineno
1565 * #=> 1
1566 */
1567static VALUE
1568iseqw_first_lineno(VALUE self)
1569{
1570 return rb_iseq_first_lineno(iseqw_check(self));
1571}
1572
1573static VALUE iseq_data_to_ary(const rb_iseq_t *iseq);
1574
1575/*
1576 * call-seq:
1577 * iseq.to_a -> ary
1578 *
1579 * Returns an Array with 14 elements representing the instruction sequence
1580 * with the following data:
1581 *
1582 * [magic]
1583 * A string identifying the data format. <b>Always
1584 * +YARVInstructionSequence/SimpleDataFormat+.</b>
1585 *
1586 * [major_version]
1587 * The major version of the instruction sequence.
1588 *
1589 * [minor_version]
1590 * The minor version of the instruction sequence.
1591 *
1592 * [format_type]
1593 * A number identifying the data format. <b>Always 1</b>.
1594 *
1595 * [misc]
1596 * A hash containing:
1597 *
1598 * [+:arg_size+]
1599 * the total number of arguments taken by the method or the block (0 if
1600 * _iseq_ doesn't represent a method or block)
1601 * [+:local_size+]
1602 * the number of local variables + 1
1603 * [+:stack_max+]
1604 * used in calculating the stack depth at which a SystemStackError is
1605 * thrown.
1606 *
1607 * [#label]
1608 * The name of the context (block, method, class, module, etc.) that this
1609 * instruction sequence belongs to.
1610 *
1611 * <code><main></code> if it's at the top level, <code><compiled></code> if
1612 * it was evaluated from a string.
1613 *
1614 * [#path]
1615 * The relative path to the Ruby file where the instruction sequence was
1616 * loaded from.
1617 *
1618 * <code><compiled></code> if the iseq was evaluated from a string.
1619 *
1620 * [#absolute_path]
1621 * The absolute path to the Ruby file where the instruction sequence was
1622 * loaded from.
1623 *
1624 * +nil+ if the iseq was evaluated from a string.
1625 *
1626 * [#first_lineno]
1627 * The number of the first source line where the instruction sequence was
1628 * loaded from.
1629 *
1630 * [type]
1631 * The type of the instruction sequence.
1632 *
1633 * Valid values are +:top+, +:method+, +:block+, +:class+, +:rescue+,
1634 * +:ensure+, +:eval+, +:main+, and +plain+.
1635 *
1636 * [locals]
1637 * An array containing the names of all arguments and local variables as
1638 * symbols.
1639 *
1640 * [params]
1641 * An Hash object containing parameter information.
1642 *
1643 * More info about these values can be found in +vm_core.h+.
1644 *
1645 * [catch_table]
1646 * A list of exceptions and control flow operators (rescue, next, redo,
1647 * break, etc.).
1648 *
1649 * [bytecode]
1650 * An array of arrays containing the instruction names and operands that
1651 * make up the body of the instruction sequence.
1652 *
1653 * Note that this format is MRI specific and version dependent.
1654 *
1655 */
1656static VALUE
1657iseqw_to_a(VALUE self)
1658{
1659 const rb_iseq_t *iseq = iseqw_check(self);
1660 return iseq_data_to_ary(iseq);
1661}
1662
1663#if VM_INSN_INFO_TABLE_IMPL == 1 /* binary search */
1664static const struct iseq_insn_info_entry *
1665get_insn_info_binary_search(const rb_iseq_t *iseq, size_t pos)
1666{
1667 const struct rb_iseq_constant_body *const body = iseq->body;
1668 size_t size = body->insns_info.size;
1669 const struct iseq_insn_info_entry *insns_info = body->insns_info.body;
1670 const unsigned int *positions = body->insns_info.positions;
1671 const int debug = 0;
1672
1673 if (debug) {
1674 printf("size: %"PRIuSIZE"\n", size);
1675 printf("insns_info[%"PRIuSIZE"]: position: %d, line: %d, pos: %"PRIuSIZE"\n",
1676 (size_t)0, positions[0], insns_info[0].line_no, pos);
1677 }
1678
1679 if (size == 0) {
1680 return NULL;
1681 }
1682 else if (size == 1) {
1683 return &insns_info[0];
1684 }
1685 else {
1686 size_t l = 1, r = size - 1;
1687 while (l <= r) {
1688 size_t m = l + (r - l) / 2;
1689 if (positions[m] == pos) {
1690 return &insns_info[m];
1691 }
1692 if (positions[m] < pos) {
1693 l = m + 1;
1694 }
1695 else {
1696 r = m - 1;
1697 }
1698 }
1699 if (l >= size) {
1700 return &insns_info[size-1];
1701 }
1702 if (positions[l] > pos) {
1703 return &insns_info[l-1];
1704 }
1705 return &insns_info[l];
1706 }
1707}
1708
1709static const struct iseq_insn_info_entry *
1710get_insn_info(const rb_iseq_t *iseq, size_t pos)
1711{
1712 return get_insn_info_binary_search(iseq, pos);
1713}
1714#endif
1715
1716#if VM_INSN_INFO_TABLE_IMPL == 2 /* succinct bitvector */
1717static const struct iseq_insn_info_entry *
1718get_insn_info_succinct_bitvector(const rb_iseq_t *iseq, size_t pos)
1719{
1720 const struct rb_iseq_constant_body *const body = iseq->body;
1721 size_t size = body->insns_info.size;
1722 const struct iseq_insn_info_entry *insns_info = body->insns_info.body;
1723 const int debug = 0;
1724
1725 if (debug) {
1726#if VM_CHECK_MODE > 0
1727 const unsigned int *positions = body->insns_info.positions;
1728 printf("size: %"PRIuSIZE"\n", size);
1729 printf("insns_info[%"PRIuSIZE"]: position: %d, line: %d, pos: %"PRIuSIZE"\n",
1730 (size_t)0, positions[0], insns_info[0].line_no, pos);
1731#else
1732 printf("size: %"PRIuSIZE"\n", size);
1733 printf("insns_info[%"PRIuSIZE"]: line: %d, pos: %"PRIuSIZE"\n",
1734 (size_t)0, insns_info[0].line_no, pos);
1735#endif
1736 }
1737
1738 if (size == 0) {
1739 return NULL;
1740 }
1741 else if (size == 1) {
1742 return &insns_info[0];
1743 }
1744 else {
1745 int index;
1746 VM_ASSERT(body->insns_info.succ_index_table != NULL);
1747 index = succ_index_lookup(body->insns_info.succ_index_table, (int)pos);
1748 return &insns_info[index-1];
1749 }
1750}
1751
1752static const struct iseq_insn_info_entry *
1753get_insn_info(const rb_iseq_t *iseq, size_t pos)
1754{
1755 return get_insn_info_succinct_bitvector(iseq, pos);
1756}
1757#endif
1758
1759#if VM_CHECK_MODE > 0 || VM_INSN_INFO_TABLE_IMPL == 0
1760static const struct iseq_insn_info_entry *
1761get_insn_info_linear_search(const rb_iseq_t *iseq, size_t pos)
1762{
1763 const struct rb_iseq_constant_body *const body = iseq->body;
1764 size_t i = 0, size = body->insns_info.size;
1765 const struct iseq_insn_info_entry *insns_info = body->insns_info.body;
1766 const unsigned int *positions = body->insns_info.positions;
1767 const int debug = 0;
1768
1769 if (debug) {
1770 printf("size: %"PRIuSIZE"\n", size);
1771 printf("insns_info[%"PRIuSIZE"]: position: %d, line: %d, pos: %"PRIuSIZE"\n",
1772 i, positions[i], insns_info[i].line_no, pos);
1773 }
1774
1775 if (size == 0) {
1776 return NULL;
1777 }
1778 else if (size == 1) {
1779 return &insns_info[0];
1780 }
1781 else {
1782 for (i=1; i<size; i++) {
1783 if (debug) printf("insns_info[%"PRIuSIZE"]: position: %d, line: %d, pos: %"PRIuSIZE"\n",
1784 i, positions[i], insns_info[i].line_no, pos);
1785
1786 if (positions[i] == pos) {
1787 return &insns_info[i];
1788 }
1789 if (positions[i] > pos) {
1790 return &insns_info[i-1];
1791 }
1792 }
1793 }
1794 return &insns_info[i-1];
1795}
1796#endif
1797
1798#if VM_INSN_INFO_TABLE_IMPL == 0 /* linear search */
1799static const struct iseq_insn_info_entry *
1800get_insn_info(const rb_iseq_t *iseq, size_t pos)
1801{
1802 return get_insn_info_linear_search(iseq, pos);
1803}
1804#endif
1805
1806#if VM_CHECK_MODE > 0 && VM_INSN_INFO_TABLE_IMPL > 0
1807static void
1808validate_get_insn_info(const rb_iseq_t *iseq)
1809{
1810 const struct rb_iseq_constant_body *const body = iseq->body;
1811 size_t i;
1812 for (i = 0; i < body->iseq_size; i++) {
1813 if (get_insn_info_linear_search(iseq, i) != get_insn_info(iseq, i)) {
1814 rb_bug("validate_get_insn_info: get_insn_info_linear_search(iseq, %"PRIuSIZE") != get_insn_info(iseq, %"PRIuSIZE")", i, i);
1815 }
1816 }
1817}
1818#endif
1819
1820unsigned int
1821rb_iseq_line_no(const rb_iseq_t *iseq, size_t pos)
1822{
1823 const struct iseq_insn_info_entry *entry = get_insn_info(iseq, pos);
1824
1825 if (entry) {
1826 return entry->line_no;
1827 }
1828 else {
1829 return 0;
1830 }
1831}
1832
1834rb_iseq_event_flags(const rb_iseq_t *iseq, size_t pos)
1835{
1836 const struct iseq_insn_info_entry *entry = get_insn_info(iseq, pos);
1837 if (entry) {
1838 return entry->events;
1839 }
1840 else {
1841 return 0;
1842 }
1843}
1844
1845void
1847{
1848 struct iseq_insn_info_entry *entry = (struct iseq_insn_info_entry *)get_insn_info(iseq, pos);
1849 if (entry) {
1850 entry->events &= ~reset;
1851 if (!(entry->events & iseq->aux.exec.global_trace_events)) {
1852 void rb_iseq_trace_flag_cleared(const rb_iseq_t *iseq, size_t pos);
1853 rb_iseq_trace_flag_cleared(iseq, pos);
1854 }
1855 }
1856}
1857
1858static VALUE
1859local_var_name(const rb_iseq_t *diseq, VALUE level, VALUE op)
1860{
1861 VALUE i;
1862 VALUE name;
1863 ID lid;
1864 int idx;
1865
1866 for (i = 0; i < level; i++) {
1867 diseq = diseq->body->parent_iseq;
1868 }
1869 idx = diseq->body->local_table_size - (int)op - 1;
1870 lid = diseq->body->local_table[idx];
1871 name = rb_id2str(lid);
1872 if (!name) {
1873 name = rb_str_new_cstr("?");
1874 }
1875 else if (!rb_str_symname_p(name)) {
1877 }
1878 else {
1879 name = rb_str_dup(name);
1880 }
1881 rb_str_catf(name, "@%d", idx);
1882 return name;
1883}
1884
1887
1888VALUE
1890 VALUE insn, int op_no, VALUE op,
1891 int len, size_t pos, const VALUE *pnop, VALUE child)
1892{
1893 const char *types = insn_op_types(insn);
1894 char type = types[op_no];
1895 VALUE ret = Qundef;
1896
1897 switch (type) {
1898 case TS_OFFSET: /* LONG */
1899 ret = rb_sprintf("%"PRIdVALUE, (VALUE)(pos + len + op));
1900 break;
1901
1902 case TS_NUM: /* ULONG */
1903 if (insn == BIN(defined) && op_no == 0) {
1904 enum defined_type deftype = (enum defined_type)op;
1905 switch (deftype) {
1906 case DEFINED_FUNC:
1907 ret = rb_fstring_lit("func");
1908 break;
1909 case DEFINED_REF:
1910 ret = rb_fstring_lit("ref");
1911 break;
1912 case DEFINED_CONST_FROM:
1913 ret = rb_fstring_lit("constant-from");
1914 break;
1915 default:
1916 ret = rb_iseq_defined_string(deftype);
1917 break;
1918 }
1919 if (ret) break;
1920 }
1921 else if (insn == BIN(checktype) && op_no == 0) {
1922 const char *type_str = rb_type_str((enum ruby_value_type)op);
1923 if (type_str) {
1924 ret = rb_str_new_cstr(type_str); break;
1925 }
1926 }
1927 ret = rb_sprintf("%"PRIuVALUE, op);
1928 break;
1929
1930 case TS_LINDEX:{
1931 int level;
1932 if (types[op_no+1] == TS_NUM && pnop) {
1933 ret = local_var_name(iseq, *pnop, op - VM_ENV_DATA_SIZE);
1934 }
1935 else if ((level = rb_insn_unified_local_var_level(insn)) >= 0) {
1936 ret = local_var_name(iseq, (VALUE)level, op - VM_ENV_DATA_SIZE);
1937 }
1938 else {
1939 ret = rb_inspect(INT2FIX(op));
1940 }
1941 break;
1942 }
1943 case TS_ID: /* ID (symbol) */
1944 ret = rb_inspect(ID2SYM(op));
1945 break;
1946
1947 case TS_VALUE: /* VALUE */
1948 op = obj_resurrect(op);
1949 if (insn == BIN(defined) && op_no == 1 && FIXNUM_P(op)) {
1950 /* should be DEFINED_REF */
1951 int type = NUM2INT(op);
1952 if (type) {
1953 if (type & 1) {
1954 ret = rb_sprintf(":$%c", (type >> 1));
1955 }
1956 else {
1957 ret = rb_sprintf(":$%d", (type >> 1));
1958 }
1959 break;
1960 }
1961 }
1962 ret = rb_dump_literal(op);
1963 if (CLASS_OF(op) == rb_cISeq) {
1964 if (child) {
1965 rb_ary_push(child, op);
1966 }
1967 }
1968 break;
1969
1970 case TS_ISEQ: /* iseq */
1971 {
1972 if (op) {
1973 const rb_iseq_t *iseq = rb_iseq_check((rb_iseq_t *)op);
1974 ret = iseq->body->location.label;
1975 if (child) {
1976 rb_ary_push(child, (VALUE)iseq);
1977 }
1978 }
1979 else {
1980 ret = rb_str_new2("nil");
1981 }
1982 break;
1983 }
1984
1985 case TS_IC:
1986 case TS_IVC:
1987 case TS_ISE:
1988 ret = rb_sprintf("<is:%"PRIdPTRDIFF">", (union iseq_inline_storage_entry *)op - iseq->body->is_entries);
1989 break;
1990
1991 case TS_CALLDATA:
1992 {
1993 struct rb_call_data *cd = (struct rb_call_data *)op;
1994 const struct rb_callinfo *ci = cd->ci;
1995 VALUE ary = rb_ary_new();
1996 ID mid = vm_ci_mid(ci);
1997
1998 if (mid) {
2000 }
2001
2002 rb_ary_push(ary, rb_sprintf("argc:%d", vm_ci_argc(ci)));
2003
2004 if (vm_ci_flag(ci) & VM_CALL_KWARG) {
2005 const struct rb_callinfo_kwarg *kw_args = vm_ci_kwarg(ci);
2006 VALUE kw_ary = rb_ary_new_from_values(kw_args->keyword_len, kw_args->keywords);
2007 rb_ary_push(ary, rb_sprintf("kw:[%"PRIsVALUE"]", rb_ary_join(kw_ary, rb_str_new2(","))));
2008 }
2009
2010 if (vm_ci_flag(ci)) {
2011 VALUE flags = rb_ary_new();
2012# define CALL_FLAG(n) if (vm_ci_flag(ci) & VM_CALL_##n) rb_ary_push(flags, rb_str_new2(#n))
2013 CALL_FLAG(ARGS_SPLAT);
2014 CALL_FLAG(ARGS_BLOCKARG);
2015 CALL_FLAG(FCALL);
2016 CALL_FLAG(VCALL);
2017 CALL_FLAG(ARGS_SIMPLE);
2018 CALL_FLAG(BLOCKISEQ);
2019 CALL_FLAG(TAILCALL);
2020 CALL_FLAG(SUPER);
2021 CALL_FLAG(ZSUPER);
2022 CALL_FLAG(KWARG);
2023 CALL_FLAG(KW_SPLAT);
2024 CALL_FLAG(KW_SPLAT_MUT);
2025 CALL_FLAG(OPT_SEND); /* maybe not reachable */
2026 rb_ary_push(ary, rb_ary_join(flags, rb_str_new2("|")));
2027 }
2028
2029 ret = rb_sprintf("<calldata!%"PRIsVALUE">", rb_ary_join(ary, rb_str_new2(", ")));
2030 }
2031 break;
2032
2033 case TS_CDHASH:
2034 ret = rb_str_new2("<cdhash>");
2035 break;
2036
2037 case TS_FUNCPTR:
2038 {
2039#ifdef HAVE_DLADDR
2040 Dl_info info;
2041 if (dladdr((void *)op, &info) && info.dli_sname) {
2042 ret = rb_str_new_cstr(info.dli_sname);
2043 break;
2044 }
2045#endif
2046 ret = rb_str_new2("<funcptr>");
2047 }
2048 break;
2049
2050 case TS_BUILTIN:
2051 {
2052 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)op;
2053 ret = rb_sprintf("<builtin!%s/%d>",
2054 bf->name, bf->argc);
2055 }
2056 break;
2057
2058 default:
2059 rb_bug("unknown operand type: %c", type);
2060 }
2061 return ret;
2062}
2063
2064static VALUE
2065right_strip(VALUE str)
2066{
2067 const char *beg = RSTRING_PTR(str), *end = RSTRING_END(str);
2068 while (end-- > beg && *end == ' ');
2069 rb_str_set_len(str, end - beg + 1);
2070 return str;
2071}
2072
2077int
2078rb_iseq_disasm_insn(VALUE ret, const VALUE *code, size_t pos,
2079 const rb_iseq_t *iseq, VALUE child)
2080{
2081 VALUE insn = code[pos];
2082 int len = insn_len(insn);
2083 int j;
2084 const char *types = insn_op_types(insn);
2085 VALUE str = rb_str_new(0, 0);
2086 const char *insn_name_buff;
2087
2088 insn_name_buff = insn_name(insn);
2089 if (1) {
2090 extern const int rb_vm_max_insn_name_size;
2091 rb_str_catf(str, "%04"PRIuSIZE" %-*s ", pos, rb_vm_max_insn_name_size, insn_name_buff);
2092 }
2093 else {
2094 rb_str_catf(str, "%04"PRIuSIZE" %-28.*s ", pos,
2095 (int)strcspn(insn_name_buff, "_"), insn_name_buff);
2096 }
2097
2098 for (j = 0; types[j]; j++) {
2099 VALUE opstr = rb_insn_operand_intern(iseq, insn, j, code[pos + j + 1],
2100 len, pos, &code[pos + j + 2],
2101 child);
2102 rb_str_concat(str, opstr);
2103
2104 if (types[j + 1]) {
2105 rb_str_cat2(str, ", ");
2106 }
2107 }
2108
2109 {
2110 unsigned int line_no = rb_iseq_line_no(iseq, pos);
2111 unsigned int prev = pos == 0 ? 0 : rb_iseq_line_no(iseq, pos - 1);
2112 if (line_no && line_no != prev) {
2113 long slen = RSTRING_LEN(str);
2114 slen = (slen > 70) ? 0 : (70 - slen);
2115 str = rb_str_catf(str, "%*s(%4d)", (int)slen, "", line_no);
2116 }
2117 }
2118
2119 {
2120 rb_event_flag_t events = rb_iseq_event_flags(iseq, pos);
2121 if (events) {
2122 str = rb_str_catf(str, "[%s%s%s%s%s%s%s%s%s%s%s]",
2123 events & RUBY_EVENT_LINE ? "Li" : "",
2124 events & RUBY_EVENT_CLASS ? "Cl" : "",
2125 events & RUBY_EVENT_END ? "En" : "",
2126 events & RUBY_EVENT_CALL ? "Ca" : "",
2127 events & RUBY_EVENT_RETURN ? "Re" : "",
2128 events & RUBY_EVENT_C_CALL ? "Cc" : "",
2129 events & RUBY_EVENT_C_RETURN ? "Cr" : "",
2130 events & RUBY_EVENT_B_CALL ? "Bc" : "",
2131 events & RUBY_EVENT_B_RETURN ? "Br" : "",
2132 events & RUBY_EVENT_COVERAGE_LINE ? "Cli" : "",
2133 events & RUBY_EVENT_COVERAGE_BRANCH ? "Cbr" : "");
2134 }
2135 }
2136
2137 right_strip(str);
2138 if (ret) {
2139 rb_str_cat2(str, "\n");
2140 rb_str_concat(ret, str);
2141 }
2142 else {
2143 printf("%.*s\n", (int)RSTRING_LEN(str), RSTRING_PTR(str));
2144 }
2145 return len;
2146}
2147
2148static const char *
2149catch_type(int type)
2150{
2151 switch (type) {
2152 case CATCH_TYPE_RESCUE:
2153 return "rescue";
2154 case CATCH_TYPE_ENSURE:
2155 return "ensure";
2156 case CATCH_TYPE_RETRY:
2157 return "retry";
2158 case CATCH_TYPE_BREAK:
2159 return "break";
2160 case CATCH_TYPE_REDO:
2161 return "redo";
2162 case CATCH_TYPE_NEXT:
2163 return "next";
2164 default:
2165 rb_bug("unknown catch type: %d", type);
2166 return 0;
2167 }
2168}
2169
2170static VALUE
2171iseq_inspect(const rb_iseq_t *iseq)
2172{
2173 const struct rb_iseq_constant_body *const body = iseq->body;
2174 if (!body->location.label) {
2175 return rb_sprintf("#<ISeq: uninitialized>");
2176 }
2177 else {
2178 const rb_code_location_t *loc = &body->location.code_location;
2179 return rb_sprintf("#<ISeq:%"PRIsVALUE"@%"PRIsVALUE":%d (%d,%d)-(%d,%d)>",
2180 body->location.label, rb_iseq_path(iseq),
2181 loc->beg_pos.lineno,
2182 loc->beg_pos.lineno,
2183 loc->beg_pos.column,
2184 loc->end_pos.lineno,
2185 loc->end_pos.column);
2186 }
2187}
2188
2189static const rb_data_type_t tmp_set = {
2190 "tmpset",
2191 {(void (*)(void *))rb_mark_set, (void (*)(void *))st_free_table, 0, 0,},
2193};
2194
2195static VALUE
2196rb_iseq_disasm_recursive(const rb_iseq_t *iseq, VALUE indent)
2197{
2198 const struct rb_iseq_constant_body *const body = iseq->body;
2199 VALUE *code;
2200 VALUE str = rb_str_new(0, 0);
2201 VALUE child = rb_ary_tmp_new(3);
2202 unsigned int size;
2203 unsigned int i;
2204 long l;
2205 size_t n;
2206 enum {header_minlen = 72};
2207 st_table *done_iseq = 0;
2208 VALUE done_iseq_wrapper = Qnil;
2209 const char *indent_str;
2210 long indent_len;
2211
2212 size = body->iseq_size;
2213
2214 indent_len = RSTRING_LEN(indent);
2215 indent_str = RSTRING_PTR(indent);
2216
2217 rb_str_cat(str, indent_str, indent_len);
2218 rb_str_cat2(str, "== disasm: ");
2219
2220 rb_str_append(str, iseq_inspect(iseq));
2221 rb_str_catf(str, " (catch: %s)", body->catch_except_p ? "TRUE" : "FALSE");
2222 if ((l = RSTRING_LEN(str) - indent_len) < header_minlen) {
2223 rb_str_modify_expand(str, header_minlen - l);
2224 memset(RSTRING_END(str), '=', header_minlen - l);
2225 }
2226 rb_str_cat2(str, "\n");
2227
2228 /* show catch table information */
2229 if (body->catch_table) {
2230 rb_str_cat(str, indent_str, indent_len);
2231 rb_str_cat2(str, "== catch table\n");
2232 }
2233 if (body->catch_table) {
2234 rb_str_cat_cstr(indent, "| ");
2235 indent_str = RSTRING_PTR(indent);
2236 for (i = 0; i < body->catch_table->size; i++) {
2237 const struct iseq_catch_table_entry *entry =
2238 UNALIGNED_MEMBER_PTR(body->catch_table, entries[i]);
2239 rb_str_cat(str, indent_str, indent_len);
2241 "| catch type: %-6s st: %04d ed: %04d sp: %04d cont: %04d\n",
2242 catch_type((int)entry->type), (int)entry->start,
2243 (int)entry->end, (int)entry->sp, (int)entry->cont);
2244 if (entry->iseq && !(done_iseq && st_is_member(done_iseq, (st_data_t)entry->iseq))) {
2245 rb_str_concat(str, rb_iseq_disasm_recursive(rb_iseq_check(entry->iseq), indent));
2246 if (!done_iseq) {
2247 done_iseq = st_init_numtable();
2248 done_iseq_wrapper = TypedData_Wrap_Struct(0, &tmp_set, done_iseq);
2249 }
2250 st_insert(done_iseq, (st_data_t)entry->iseq, (st_data_t)0);
2251 indent_str = RSTRING_PTR(indent);
2252 }
2253 }
2254 rb_str_resize(indent, indent_len);
2255 indent_str = RSTRING_PTR(indent);
2256 }
2257 if (body->catch_table) {
2258 rb_str_cat(str, indent_str, indent_len);
2259 rb_str_cat2(str, "|-------------------------------------"
2260 "-----------------------------------\n");
2261 }
2262
2263 /* show local table information */
2264 if (body->local_table) {
2265 const struct rb_iseq_param_keyword *const keyword = body->param.keyword;
2266 rb_str_cat(str, indent_str, indent_len);
2268 "local table (size: %d, argc: %d "
2269 "[opts: %d, rest: %d, post: %d, block: %d, kw: %d@%d, kwrest: %d])\n",
2270 body->local_table_size,
2271 body->param.lead_num,
2272 body->param.opt_num,
2273 body->param.flags.has_rest ? body->param.rest_start : -1,
2274 body->param.post_num,
2275 body->param.flags.has_block ? body->param.block_start : -1,
2276 body->param.flags.has_kw ? keyword->num : -1,
2277 body->param.flags.has_kw ? keyword->required_num : -1,
2278 body->param.flags.has_kwrest ? keyword->rest_start : -1);
2279
2280 for (i = body->local_table_size; i > 0;) {
2281 int li = body->local_table_size - --i - 1;
2282 long width;
2283 VALUE name = local_var_name(iseq, 0, i);
2284 char argi[0x100];
2285 char opti[0x100];
2286
2287 opti[0] = '\0';
2288 if (body->param.flags.has_opt) {
2289 int argc = body->param.lead_num;
2290 int opts = body->param.opt_num;
2291 if (li >= argc && li < argc + opts) {
2292 snprintf(opti, sizeof(opti), "Opt=%"PRIdVALUE,
2293 body->param.opt_table[li - argc]);
2294 }
2295 }
2296
2297 snprintf(argi, sizeof(argi), "%s%s%s%s%s%s", /* arg, opts, rest, post, kwrest, block */
2298 body->param.lead_num > li ? "Arg" : "",
2299 opti,
2300 (body->param.flags.has_rest && body->param.rest_start == li) ? "Rest" : "",
2301 (body->param.flags.has_post && body->param.post_start <= li && li < body->param.post_start + body->param.post_num) ? "Post" : "",
2302 (body->param.flags.has_kwrest && keyword->rest_start == li) ? "Kwrest" : "",
2303 (body->param.flags.has_block && body->param.block_start == li) ? "Block" : "");
2304
2305 rb_str_cat(str, indent_str, indent_len);
2306 rb_str_catf(str, "[%2d] ", i + 1);
2307 width = RSTRING_LEN(str) + 11;
2309 if (*argi) rb_str_catf(str, "<%s>", argi);
2310 if ((width -= RSTRING_LEN(str)) > 0) rb_str_catf(str, "%*s", (int)width, "");
2311 }
2312 rb_str_cat_cstr(right_strip(str), "\n");
2313 }
2314
2315 /* show each line */
2317 for (n = 0; n < size;) {
2318 rb_str_cat(str, indent_str, indent_len);
2319 n += rb_iseq_disasm_insn(str, code, n, iseq, child);
2320 }
2321
2322 for (l = 0; l < RARRAY_LEN(child); l++) {
2323 VALUE isv = rb_ary_entry(child, l);
2324 if (done_iseq && st_is_member(done_iseq, (st_data_t)isv)) continue;
2325 rb_str_cat_cstr(str, "\n");
2326 rb_str_concat(str, rb_iseq_disasm_recursive(rb_iseq_check((rb_iseq_t *)isv), indent));
2327 indent_str = RSTRING_PTR(indent);
2328 }
2329 RB_GC_GUARD(done_iseq_wrapper);
2330
2331 return str;
2332}
2333
2334VALUE
2336{
2337 VALUE str = rb_iseq_disasm_recursive(iseq, rb_str_new(0, 0));
2339 return str;
2340}
2341
2342/*
2343 * call-seq:
2344 * iseq.disasm -> str
2345 * iseq.disassemble -> str
2346 *
2347 * Returns the instruction sequence as a +String+ in human readable form.
2348 *
2349 * puts RubyVM::InstructionSequence.compile('1 + 2').disasm
2350 *
2351 * Produces:
2352 *
2353 * == disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>==========
2354 * 0000 trace 1 ( 1)
2355 * 0002 putobject 1
2356 * 0004 putobject 2
2357 * 0006 opt_plus <ic:1>
2358 * 0008 leave
2359 */
2360static VALUE
2361iseqw_disasm(VALUE self)
2362{
2363 return rb_iseq_disasm(iseqw_check(self));
2364}
2365
2366static int
2367iseq_iterate_children(const rb_iseq_t *iseq, void (*iter_func)(const rb_iseq_t *child_iseq, void *data), void *data)
2368{
2369 unsigned int i;
2371 const struct rb_iseq_constant_body *const body = iseq->body;
2372 const rb_iseq_t *child;
2373 VALUE all_children = rb_obj_hide(rb_ident_hash_new());
2374
2375 if (body->catch_table) {
2376 for (i = 0; i < body->catch_table->size; i++) {
2377 const struct iseq_catch_table_entry *entry =
2378 UNALIGNED_MEMBER_PTR(body->catch_table, entries[i]);
2379 child = entry->iseq;
2380 if (child) {
2381 if (rb_hash_aref(all_children, (VALUE)child) == Qnil) {
2382 rb_hash_aset(all_children, (VALUE)child, Qtrue);
2383 (*iter_func)(child, data);
2384 }
2385 }
2386 }
2387 }
2388
2389 for (i=0; i<body->iseq_size;) {
2390 VALUE insn = code[i];
2391 int len = insn_len(insn);
2392 const char *types = insn_op_types(insn);
2393 int j;
2394
2395 for (j=0; types[j]; j++) {
2396 switch (types[j]) {
2397 case TS_ISEQ:
2398 child = (const rb_iseq_t *)code[i+j+1];
2399 if (child) {
2400 if (rb_hash_aref(all_children, (VALUE)child) == Qnil) {
2401 rb_hash_aset(all_children, (VALUE)child, Qtrue);
2402 (*iter_func)(child, data);
2403 }
2404 }
2405 break;
2406 default:
2407 break;
2408 }
2409 }
2410 i += len;
2411 }
2412
2413 return (int)RHASH_SIZE(all_children);
2414}
2415
2416static void
2417yield_each_children(const rb_iseq_t *child_iseq, void *data)
2418{
2419 rb_yield(iseqw_new(child_iseq));
2420}
2421
2422/*
2423 * call-seq:
2424 * iseq.each_child{|child_iseq| ...} -> iseq
2425 *
2426 * Iterate all direct child instruction sequences.
2427 * Iteration order is implementation/version defined
2428 * so that people should not rely on the order.
2429 */
2430static VALUE
2431iseqw_each_child(VALUE self)
2432{
2433 const rb_iseq_t *iseq = iseqw_check(self);
2434 iseq_iterate_children(iseq, yield_each_children, NULL);
2435 return self;
2436}
2437
2438static void
2439push_event_info(const rb_iseq_t *iseq, rb_event_flag_t events, int line, VALUE ary)
2440{
2441#define C(ev, cstr, l) if (events & ev) rb_ary_push(ary, rb_ary_new_from_args(2, l, ID2SYM(rb_intern(cstr))));
2445 C(RUBY_EVENT_LINE, "line", INT2FIX(line));
2446 C(RUBY_EVENT_END, "end", INT2FIX(line));
2447 C(RUBY_EVENT_RETURN, "return", INT2FIX(line));
2448 C(RUBY_EVENT_B_RETURN, "b_return", INT2FIX(line));
2449#undef C
2450}
2451
2452/*
2453 * call-seq:
2454 * iseq.trace_points -> ary
2455 *
2456 * Return trace points in the instruction sequence.
2457 * Return an array of [line, event_symbol] pair.
2458 */
2459static VALUE
2460iseqw_trace_points(VALUE self)
2461{
2462 const rb_iseq_t *iseq = iseqw_check(self);
2463 const struct rb_iseq_constant_body *const body = iseq->body;
2464 unsigned int i;
2465 VALUE ary = rb_ary_new();
2466
2467 for (i=0; i<body->insns_info.size; i++) {
2468 const struct iseq_insn_info_entry *entry = &body->insns_info.body[i];
2469 if (entry->events) {
2470 push_event_info(iseq, entry->events, entry->line_no, ary);
2471 }
2472 }
2473 return ary;
2474}
2475
2476/*
2477 * Returns the instruction sequence containing the given proc or method.
2478 *
2479 * For example, using irb:
2480 *
2481 * # a proc
2482 * > p = proc { num = 1 + 2 }
2483 * > RubyVM::InstructionSequence.of(p)
2484 * > #=> <RubyVM::InstructionSequence:block in irb_binding@(irb)>
2485 *
2486 * # for a method
2487 * > def foo(bar); puts bar; end
2488 * > RubyVM::InstructionSequence.of(method(:foo))
2489 * > #=> <RubyVM::InstructionSequence:foo@(irb)>
2490 *
2491 * Using ::compile_file:
2492 *
2493 * # /tmp/iseq_of.rb
2494 * def hello
2495 * puts "hello, world"
2496 * end
2497 *
2498 * $a_global_proc = proc { str = 'a' + 'b' }
2499 *
2500 * # in irb
2501 * > require '/tmp/iseq_of.rb'
2502 *
2503 * # first the method hello
2504 * > RubyVM::InstructionSequence.of(method(:hello))
2505 * > #=> #<RubyVM::InstructionSequence:0x007fb73d7cb1d0>
2506 *
2507 * # then the global proc
2508 * > RubyVM::InstructionSequence.of($a_global_proc)
2509 * > #=> #<RubyVM::InstructionSequence:0x007fb73d7caf78>
2510 */
2511static VALUE
2512iseqw_s_of(VALUE klass, VALUE body)
2513{
2514 const rb_iseq_t *iseq = NULL;
2515
2516 if (rb_obj_is_proc(body)) {
2517 iseq = vm_proc_iseq(body);
2518
2519 if (!rb_obj_is_iseq((VALUE)iseq)) {
2520 iseq = NULL;
2521 }
2522 }
2523 else if (rb_obj_is_method(body)) {
2524 iseq = rb_method_iseq(body);
2525 }
2526 else if (rb_typeddata_is_instance_of(body, &iseqw_data_type)) {
2527 return body;
2528 }
2529
2530 return iseq ? iseqw_new(iseq) : Qnil;
2531}
2532
2533/*
2534 * call-seq:
2535 * InstructionSequence.disasm(body) -> str
2536 * InstructionSequence.disassemble(body) -> str
2537 *
2538 * Takes +body+, a Method or Proc object, and returns a String with the
2539 * human readable instructions for +body+.
2540 *
2541 * For a Method object:
2542 *
2543 * # /tmp/method.rb
2544 * def hello
2545 * puts "hello, world"
2546 * end
2547 *
2548 * puts RubyVM::InstructionSequence.disasm(method(:hello))
2549 *
2550 * Produces:
2551 *
2552 * == disasm: <RubyVM::InstructionSequence:hello@/tmp/method.rb>============
2553 * 0000 trace 8 ( 1)
2554 * 0002 trace 1 ( 2)
2555 * 0004 putself
2556 * 0005 putstring "hello, world"
2557 * 0007 send :puts, 1, nil, 8, <ic:0>
2558 * 0013 trace 16 ( 3)
2559 * 0015 leave ( 2)
2560 *
2561 * For a Proc:
2562 *
2563 * # /tmp/proc.rb
2564 * p = proc { num = 1 + 2 }
2565 * puts RubyVM::InstructionSequence.disasm(p)
2566 *
2567 * Produces:
2568 *
2569 * == disasm: <RubyVM::InstructionSequence:block in <main>@/tmp/proc.rb>===
2570 * == catch table
2571 * | catch type: redo st: 0000 ed: 0012 sp: 0000 cont: 0000
2572 * | catch type: next st: 0000 ed: 0012 sp: 0000 cont: 0012
2573 * |------------------------------------------------------------------------
2574 * local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1] s1)
2575 * [ 2] num
2576 * 0000 trace 1 ( 1)
2577 * 0002 putobject 1
2578 * 0004 putobject 2
2579 * 0006 opt_plus <ic:1>
2580 * 0008 dup
2581 * 0009 setlocal num, 0
2582 * 0012 leave
2583 *
2584 */
2585static VALUE
2586iseqw_s_disasm(VALUE klass, VALUE body)
2587{
2588 VALUE iseqw = iseqw_s_of(klass, body);
2589 return NIL_P(iseqw) ? Qnil : rb_iseq_disasm(iseqw_check(iseqw));
2590}
2591
2592const char *
2594{
2595 switch (node) {
2596#include "node_name.inc"
2597 default:
2598 rb_bug("unknown node: %d", node);
2599 return 0;
2600 }
2601}
2602
2603#define DECL_SYMBOL(name) \
2604 static ID sym_##name
2605
2606#define INIT_SYMBOL(name) \
2607 sym_##name = rb_intern(#name)
2608
2609static VALUE
2610register_label(struct st_table *table, unsigned long idx)
2611{
2612 VALUE sym = rb_str_intern(rb_sprintf("label_%lu", idx));
2613 st_insert(table, idx, sym);
2614 return sym;
2615}
2616
2617static VALUE
2618exception_type2symbol(VALUE type)
2619{
2620 ID id;
2621 switch (type) {
2622 case CATCH_TYPE_RESCUE: CONST_ID(id, "rescue"); break;
2623 case CATCH_TYPE_ENSURE: CONST_ID(id, "ensure"); break;
2624 case CATCH_TYPE_RETRY: CONST_ID(id, "retry"); break;
2625 case CATCH_TYPE_BREAK: CONST_ID(id, "break"); break;
2626 case CATCH_TYPE_REDO: CONST_ID(id, "redo"); break;
2627 case CATCH_TYPE_NEXT: CONST_ID(id, "next"); break;
2628 default:
2629 rb_bug("unknown exception type: %d", (int)type);
2630 }
2631 return ID2SYM(id);
2632}
2633
2634static int
2635cdhash_each(VALUE key, VALUE value, VALUE ary)
2636{
2637 rb_ary_push(ary, obj_resurrect(key));
2638 rb_ary_push(ary, value);
2639 return ST_CONTINUE;
2640}
2641
2642static const rb_data_type_t label_wrapper = {
2643 "label_wrapper",
2644 {(void (*)(void *))rb_mark_tbl, (void (*)(void *))st_free_table, 0, 0,},
2646};
2647
2648static VALUE
2649iseq_data_to_ary(const rb_iseq_t *iseq)
2650{
2651 unsigned int i;
2652 long l;
2653 const struct rb_iseq_constant_body *const iseq_body = iseq->body;
2654 const struct iseq_insn_info_entry *prev_insn_info;
2655 unsigned int pos;
2656 int last_line = 0;
2657 VALUE *seq, *iseq_original;
2658
2659 VALUE val = rb_ary_new();
2660 ID type; /* Symbol */
2661 VALUE locals = rb_ary_new();
2662 VALUE params = rb_hash_new();
2663 VALUE body = rb_ary_new(); /* [[:insn1, ...], ...] */
2664 VALUE nbody;
2665 VALUE exception = rb_ary_new(); /* [[....]] */
2666 VALUE misc = rb_hash_new();
2667
2668 static ID insn_syms[VM_INSTRUCTION_SIZE/2]; /* w/o-trace only */
2669 struct st_table *labels_table = st_init_numtable();
2670 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &label_wrapper, labels_table);
2671
2673 DECL_SYMBOL(method);
2674 DECL_SYMBOL(block);
2675 DECL_SYMBOL(class);
2676 DECL_SYMBOL(rescue);
2677 DECL_SYMBOL(ensure);
2678 DECL_SYMBOL(eval);
2680 DECL_SYMBOL(plain);
2681
2682 if (sym_top == 0) {
2683 int i;
2684 for (i=0; i<numberof(insn_syms); i++) {
2685 insn_syms[i] = rb_intern(insn_name(i));
2686 }
2688 INIT_SYMBOL(method);
2689 INIT_SYMBOL(block);
2690 INIT_SYMBOL(class);
2691 INIT_SYMBOL(rescue);
2692 INIT_SYMBOL(ensure);
2693 INIT_SYMBOL(eval);
2695 INIT_SYMBOL(plain);
2696 }
2697
2698 /* type */
2699 switch (iseq_body->type) {
2700 case ISEQ_TYPE_TOP: type = sym_top; break;
2701 case ISEQ_TYPE_METHOD: type = sym_method; break;
2702 case ISEQ_TYPE_BLOCK: type = sym_block; break;
2703 case ISEQ_TYPE_CLASS: type = sym_class; break;
2704 case ISEQ_TYPE_RESCUE: type = sym_rescue; break;
2705 case ISEQ_TYPE_ENSURE: type = sym_ensure; break;
2706 case ISEQ_TYPE_EVAL: type = sym_eval; break;
2707 case ISEQ_TYPE_MAIN: type = sym_main; break;
2708 case ISEQ_TYPE_PLAIN: type = sym_plain; break;
2709 default: rb_bug("unsupported iseq type: %d", (int)iseq_body->type);
2710 };
2711
2712 /* locals */
2713 for (i=0; i<iseq_body->local_table_size; i++) {
2714 ID lid = iseq_body->local_table[i];
2715 if (lid) {
2716 if (rb_id2str(lid)) {
2717 rb_ary_push(locals, ID2SYM(lid));
2718 }
2719 else { /* hidden variable from id_internal() */
2720 rb_ary_push(locals, ULONG2NUM(iseq_body->local_table_size-i+1));
2721 }
2722 }
2723 else {
2724 rb_ary_push(locals, ID2SYM(rb_intern("#arg_rest")));
2725 }
2726 }
2727
2728 /* params */
2729 {
2730 const struct rb_iseq_param_keyword *const keyword = iseq_body->param.keyword;
2731 int j;
2732
2733 if (iseq_body->param.flags.has_opt) {
2734 int len = iseq_body->param.opt_num + 1;
2735 VALUE arg_opt_labels = rb_ary_new2(len);
2736
2737 for (j = 0; j < len; j++) {
2738 VALUE l = register_label(labels_table, iseq_body->param.opt_table[j]);
2739 rb_ary_push(arg_opt_labels, l);
2740 }
2741 rb_hash_aset(params, ID2SYM(rb_intern("opt")), arg_opt_labels);
2742 }
2743
2744 /* commit */
2745 if (iseq_body->param.flags.has_lead) rb_hash_aset(params, ID2SYM(rb_intern("lead_num")), INT2FIX(iseq_body->param.lead_num));
2746 if (iseq_body->param.flags.has_post) rb_hash_aset(params, ID2SYM(rb_intern("post_num")), INT2FIX(iseq_body->param.post_num));
2747 if (iseq_body->param.flags.has_post) rb_hash_aset(params, ID2SYM(rb_intern("post_start")), INT2FIX(iseq_body->param.post_start));
2748 if (iseq_body->param.flags.has_rest) rb_hash_aset(params, ID2SYM(rb_intern("rest_start")), INT2FIX(iseq_body->param.rest_start));
2749 if (iseq_body->param.flags.has_block) rb_hash_aset(params, ID2SYM(rb_intern("block_start")), INT2FIX(iseq_body->param.block_start));
2750 if (iseq_body->param.flags.has_kw) {
2751 VALUE keywords = rb_ary_new();
2752 int i, j;
2753 for (i=0; i<keyword->required_num; i++) {
2754 rb_ary_push(keywords, ID2SYM(keyword->table[i]));
2755 }
2756 for (j=0; i<keyword->num; i++, j++) {
2757 VALUE key = rb_ary_new_from_args(1, ID2SYM(keyword->table[i]));
2758 if (keyword->default_values[j] != Qundef) {
2759 rb_ary_push(key, keyword->default_values[j]);
2760 }
2761 rb_ary_push(keywords, key);
2762 }
2763
2764 rb_hash_aset(params, ID2SYM(rb_intern("kwbits")),
2765 INT2FIX(keyword->bits_start));
2766 rb_hash_aset(params, ID2SYM(rb_intern("keyword")), keywords);
2767 }
2768 if (iseq_body->param.flags.has_kwrest) rb_hash_aset(params, ID2SYM(rb_intern("kwrest")), INT2FIX(keyword->rest_start));
2769 if (iseq_body->param.flags.ambiguous_param0) rb_hash_aset(params, ID2SYM(rb_intern("ambiguous_param0")), Qtrue);
2770 }
2771
2772 /* body */
2773 iseq_original = rb_iseq_original_iseq((rb_iseq_t *)iseq);
2774
2775 for (seq = iseq_original; seq < iseq_original + iseq_body->iseq_size; ) {
2776 VALUE insn = *seq++;
2777 int j, len = insn_len(insn);
2778 VALUE *nseq = seq + len - 1;
2779 VALUE ary = rb_ary_new2(len);
2780
2781 rb_ary_push(ary, ID2SYM(insn_syms[insn%numberof(insn_syms)]));
2782 for (j=0; j<len-1; j++, seq++) {
2783 switch (insn_op_type(insn, j)) {
2784 case TS_OFFSET: {
2785 unsigned long idx = nseq - iseq_original + *seq;
2786 rb_ary_push(ary, register_label(labels_table, idx));
2787 break;
2788 }
2789 case TS_LINDEX:
2790 case TS_NUM:
2791 rb_ary_push(ary, INT2FIX(*seq));
2792 break;
2793 case TS_VALUE:
2794 rb_ary_push(ary, obj_resurrect(*seq));
2795 break;
2796 case TS_ISEQ:
2797 {
2798 const rb_iseq_t *iseq = (rb_iseq_t *)*seq;
2799 if (iseq) {
2800 VALUE val = iseq_data_to_ary(rb_iseq_check(iseq));
2801 rb_ary_push(ary, val);
2802 }
2803 else {
2804 rb_ary_push(ary, Qnil);
2805 }
2806 }
2807 break;
2808 case TS_IC:
2809 case TS_IVC:
2810 case TS_ISE:
2811 {
2812 union iseq_inline_storage_entry *is = (union iseq_inline_storage_entry *)*seq;
2813 rb_ary_push(ary, INT2FIX(is - iseq_body->is_entries));
2814 }
2815 break;
2816 case TS_CALLDATA:
2817 {
2818 struct rb_call_data *cd = (struct rb_call_data *)*seq;
2819 const struct rb_callinfo *ci = cd->ci;
2820 VALUE e = rb_hash_new();
2821 int argc = vm_ci_argc(ci);
2822
2823 ID mid = vm_ci_mid(ci);
2824 rb_hash_aset(e, ID2SYM(rb_intern("mid")), mid ? ID2SYM(mid) : Qnil);
2825 rb_hash_aset(e, ID2SYM(rb_intern("flag")), UINT2NUM(vm_ci_flag(ci)));
2826
2827 if (vm_ci_flag(ci) & VM_CALL_KWARG) {
2828 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
2829 int i;
2830 VALUE kw = rb_ary_new2((long)kwarg->keyword_len);
2831
2832 argc -= kwarg->keyword_len;
2833 for (i = 0; i < kwarg->keyword_len; i++) {
2834 rb_ary_push(kw, kwarg->keywords[i]);
2835 }
2836 rb_hash_aset(e, ID2SYM(rb_intern("kw_arg")), kw);
2837 }
2838
2839 rb_hash_aset(e, ID2SYM(rb_intern("orig_argc")),
2840 INT2FIX(argc));
2841 rb_ary_push(ary, e);
2842 }
2843 break;
2844 case TS_ID:
2845 rb_ary_push(ary, ID2SYM(*seq));
2846 break;
2847 case TS_CDHASH:
2848 {
2849 VALUE hash = *seq;
2850 VALUE val = rb_ary_new();
2851 int i;
2852
2853 rb_hash_foreach(hash, cdhash_each, val);
2854
2855 for (i=0; i<RARRAY_LEN(val); i+=2) {
2856 VALUE pos = FIX2INT(rb_ary_entry(val, i+1));
2857 unsigned long idx = nseq - iseq_original + pos;
2858
2859 rb_ary_store(val, i+1,
2860 register_label(labels_table, idx));
2861 }
2862 rb_ary_push(ary, val);
2863 }
2864 break;
2865 case TS_FUNCPTR:
2866 {
2867#if SIZEOF_VALUE <= SIZEOF_LONG
2868 VALUE val = LONG2NUM((SIGNED_VALUE)*seq);
2869#else
2870 VALUE val = LL2NUM((SIGNED_VALUE)*seq);
2871#endif
2872 rb_ary_push(ary, val);
2873 }
2874 break;
2875 case TS_BUILTIN:
2876 {
2877 VALUE val = rb_hash_new();
2878#if SIZEOF_VALUE <= SIZEOF_LONG
2879 VALUE func_ptr = LONG2NUM((SIGNED_VALUE)((RB_BUILTIN)*seq)->func_ptr);
2880#else
2881 VALUE func_ptr = LL2NUM((SIGNED_VALUE)((RB_BUILTIN)*seq)->func_ptr);
2882#endif
2883 rb_hash_aset(val, ID2SYM(rb_intern("func_ptr")), func_ptr);
2884 rb_hash_aset(val, ID2SYM(rb_intern("argc")), INT2NUM(((RB_BUILTIN)*seq)->argc));
2885 rb_hash_aset(val, ID2SYM(rb_intern("index")), INT2NUM(((RB_BUILTIN)*seq)->index));
2886 rb_hash_aset(val, ID2SYM(rb_intern("name")), rb_str_new_cstr(((RB_BUILTIN)*seq)->name));
2887 rb_ary_push(ary, val);
2888 }
2889 break;
2890 default:
2891 rb_bug("unknown operand: %c", insn_op_type(insn, j));
2892 }
2893 }
2894 rb_ary_push(body, ary);
2895 }
2896
2897 nbody = body;
2898
2899 /* exception */
2900 if (iseq_body->catch_table) for (i=0; i<iseq_body->catch_table->size; i++) {
2901 VALUE ary = rb_ary_new();
2902 const struct iseq_catch_table_entry *entry =
2903 UNALIGNED_MEMBER_PTR(iseq_body->catch_table, entries[i]);
2904 rb_ary_push(ary, exception_type2symbol(entry->type));
2905 if (entry->iseq) {
2906 rb_ary_push(ary, iseq_data_to_ary(rb_iseq_check(entry->iseq)));
2907 }
2908 else {
2909 rb_ary_push(ary, Qnil);
2910 }
2911 rb_ary_push(ary, register_label(labels_table, entry->start));
2912 rb_ary_push(ary, register_label(labels_table, entry->end));
2913 rb_ary_push(ary, register_label(labels_table, entry->cont));
2914 rb_ary_push(ary, UINT2NUM(entry->sp));
2915 rb_ary_push(exception, ary);
2916 }
2917
2918 /* make body with labels and insert line number */
2919 body = rb_ary_new();
2920 prev_insn_info = NULL;
2921
2922 for (l=0, pos=0; l<RARRAY_LEN(nbody); l++) {
2923 const struct iseq_insn_info_entry *info;
2924 VALUE ary = RARRAY_AREF(nbody, l);
2925 st_data_t label;
2926
2927 if (st_lookup(labels_table, pos, &label)) {
2928 rb_ary_push(body, (VALUE)label);
2929 }
2930
2931 info = get_insn_info(iseq, pos);
2932
2933 if (prev_insn_info != info) {
2934 int line = info->line_no;
2936
2937 if (line > 0 && last_line != line) {
2938 rb_ary_push(body, INT2FIX(line));
2939 last_line = line;
2940 }
2941#define CHECK_EVENT(ev) if (events & ev) rb_ary_push(body, ID2SYM(rb_intern(#ev)));
2949#undef CHECK_EVENT
2950 prev_insn_info = info;
2951 }
2952
2953 rb_ary_push(body, ary);
2954 pos += RARRAY_LENINT(ary); /* reject too huge data */
2955 }
2956 RB_GC_GUARD(nbody);
2957 RB_GC_GUARD(labels_wrapper);
2958
2959 rb_hash_aset(misc, ID2SYM(rb_intern("arg_size")), INT2FIX(iseq_body->param.size));
2960 rb_hash_aset(misc, ID2SYM(rb_intern("local_size")), INT2FIX(iseq_body->local_table_size));
2961 rb_hash_aset(misc, ID2SYM(rb_intern("stack_max")), INT2FIX(iseq_body->stack_max));
2962 rb_hash_aset(misc, ID2SYM(rb_intern("node_id")), INT2FIX(iseq_body->location.node_id));
2963 rb_hash_aset(misc, ID2SYM(rb_intern("code_location")),
2969
2970 /*
2971 * [:magic, :major_version, :minor_version, :format_type, :misc,
2972 * :name, :path, :absolute_path, :start_lineno, :type, :locals, :args,
2973 * :catch_table, :bytecode]
2974 */
2975 rb_ary_push(val, rb_str_new2("YARVInstructionSequence/SimpleDataFormat"));
2976 rb_ary_push(val, INT2FIX(ISEQ_MAJOR_VERSION)); /* major */
2977 rb_ary_push(val, INT2FIX(ISEQ_MINOR_VERSION)); /* minor */
2978 rb_ary_push(val, INT2FIX(1));
2979 rb_ary_push(val, misc);
2980 rb_ary_push(val, iseq_body->location.label);
2981 rb_ary_push(val, rb_iseq_path(iseq));
2982 rb_ary_push(val, rb_iseq_realpath(iseq));
2983 rb_ary_push(val, iseq_body->location.first_lineno);
2984 rb_ary_push(val, ID2SYM(type));
2985 rb_ary_push(val, locals);
2986 rb_ary_push(val, params);
2987 rb_ary_push(val, exception);
2988 rb_ary_push(val, body);
2989 return val;
2990}
2991
2992VALUE
2993rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
2994{
2995 int i, r;
2996 const struct rb_iseq_constant_body *const body = iseq->body;
2997 const struct rb_iseq_param_keyword *const keyword = body->param.keyword;
2998 VALUE a, args = rb_ary_new2(body->param.size);
2999 ID req, opt, rest, block, key, keyrest;
3000#define PARAM_TYPE(type) rb_ary_push(a = rb_ary_new2(2), ID2SYM(type))
3001#define PARAM_ID(i) body->local_table[(i)]
3002#define PARAM(i, type) ( \
3003 PARAM_TYPE(type), \
3004 rb_id2str(PARAM_ID(i)) ? \
3005 rb_ary_push(a, ID2SYM(PARAM_ID(i))) : \
3006 a)
3007
3008 CONST_ID(req, "req");
3009 CONST_ID(opt, "opt");
3010 if (is_proc) {
3011 for (i = 0; i < body->param.lead_num; i++) {
3012 PARAM_TYPE(opt);
3014 rb_ary_push(args, a);
3015 }
3016 }
3017 else {
3018 for (i = 0; i < body->param.lead_num; i++) {
3019 rb_ary_push(args, PARAM(i, req));
3020 }
3021 }
3022 r = body->param.lead_num + body->param.opt_num;
3023 for (; i < r; i++) {
3024 PARAM_TYPE(opt);
3025 if (rb_id2str(PARAM_ID(i))) {
3026 rb_ary_push(a, ID2SYM(PARAM_ID(i)));
3027 }
3028 rb_ary_push(args, a);
3029 }
3030 if (body->param.flags.has_rest) {
3031 CONST_ID(rest, "rest");
3032 rb_ary_push(args, PARAM(body->param.rest_start, rest));
3033 }
3034 r = body->param.post_start + body->param.post_num;
3035 if (is_proc) {
3036 for (i = body->param.post_start; i < r; i++) {
3037 PARAM_TYPE(opt);
3039 rb_ary_push(args, a);
3040 }
3041 }
3042 else {
3043 for (i = body->param.post_start; i < r; i++) {
3044 rb_ary_push(args, PARAM(i, req));
3045 }
3046 }
3047 if (body->param.flags.accepts_no_kwarg) {
3048 ID nokey;
3049 CONST_ID(nokey, "nokey");
3050 PARAM_TYPE(nokey);
3051 rb_ary_push(args, a);
3052 }
3053 if (body->param.flags.has_kw) {
3054 i = 0;
3055 if (keyword->required_num > 0) {
3056 ID keyreq;
3057 CONST_ID(keyreq, "keyreq");
3058 for (; i < keyword->required_num; i++) {
3059 PARAM_TYPE(keyreq);
3060 if (rb_id2str(keyword->table[i])) {
3061 rb_ary_push(a, ID2SYM(keyword->table[i]));
3062 }
3063 rb_ary_push(args, a);
3064 }
3065 }
3066 CONST_ID(key, "key");
3067 for (; i < keyword->num; i++) {
3068 PARAM_TYPE(key);
3069 if (rb_id2str(keyword->table[i])) {
3070 rb_ary_push(a, ID2SYM(keyword->table[i]));
3071 }
3072 rb_ary_push(args, a);
3073 }
3074 }
3075 if (body->param.flags.has_kwrest) {
3076 CONST_ID(keyrest, "keyrest");
3077 rb_ary_push(args, PARAM(keyword->rest_start, keyrest));
3078 }
3079 if (body->param.flags.has_block) {
3080 CONST_ID(block, "block");
3081 rb_ary_push(args, PARAM(body->param.block_start, block));
3082 }
3083 return args;
3084}
3085
3086VALUE
3088{
3089 static const char expr_names[][18] = {
3090 "nil",
3091 "instance-variable",
3092 "local-variable",
3093 "global-variable",
3094 "class variable",
3095 "constant",
3096 "method",
3097 "yield",
3098 "super",
3099 "self",
3100 "true",
3101 "false",
3102 "assignment",
3103 "expression",
3104 };
3105 const char *estr;
3106 VALUE *defs, str;
3107
3108 if ((unsigned)(type - 1) >= (unsigned)numberof(expr_names)) return 0;
3109 estr = expr_names[type - 1];
3110 if (!estr[0]) return 0;
3111 defs = GET_VM()->defined_strings;
3112 if (!defs) {
3113 defs = ruby_xcalloc(numberof(expr_names), sizeof(VALUE));
3114 GET_VM()->defined_strings = defs;
3115 }
3116 str = defs[type-1];
3117 if (!str) {
3118 str = rb_str_new_cstr(estr);
3119 OBJ_FREEZE(str);
3120 defs[type-1] = str;
3122 }
3123 return str;
3124}
3125
3126/* A map from encoded_insn to insn_data: decoded insn number, its len,
3127 * non-trace version of encoded insn, and trace version. */
3128
3129static st_table *encoded_insn_data;
3130typedef struct insn_data_struct {
3131 int insn;
3136static insn_data_t insn_data[VM_INSTRUCTION_SIZE/2];
3137
3138void
3140{
3141#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
3142 const void * const *table = rb_vm_get_insns_address_table();
3143#define INSN_CODE(insn) ((VALUE)table[insn])
3144#else
3145#define INSN_CODE(insn) (insn)
3146#endif
3147 st_data_t insn;
3148 encoded_insn_data = st_init_numtable_with_size(VM_INSTRUCTION_SIZE / 2);
3149
3150 for (insn = 0; insn < VM_INSTRUCTION_SIZE/2; insn++) {
3151 st_data_t key1 = (st_data_t)INSN_CODE(insn);
3152 st_data_t key2 = (st_data_t)INSN_CODE(insn + VM_INSTRUCTION_SIZE/2);
3153
3154 insn_data[insn].insn = (int)insn;
3155 insn_data[insn].insn_len = insn_len(insn);
3156
3157 if (insn != BIN(opt_invokebuiltin_delegate_leave)) {
3158 insn_data[insn].notrace_encoded_insn = (void *) key1;
3159 insn_data[insn].trace_encoded_insn = (void *) key2;
3160 }
3161 else {
3162 insn_data[insn].notrace_encoded_insn = (void *) INSN_CODE(BIN(opt_invokebuiltin_delegate));
3163 insn_data[insn].trace_encoded_insn = (void *) INSN_CODE(BIN(opt_invokebuiltin_delegate) + VM_INSTRUCTION_SIZE/2);
3164 }
3165
3166 st_add_direct(encoded_insn_data, key1, (st_data_t)&insn_data[insn]);
3167 st_add_direct(encoded_insn_data, key2, (st_data_t)&insn_data[insn]);
3168 }
3169}
3170
3171int
3172rb_vm_insn_addr2insn(const void *addr)
3173{
3174 st_data_t key = (st_data_t)addr;
3175 st_data_t val;
3176
3177 if (st_lookup(encoded_insn_data, key, &val)) {
3178 insn_data_t *e = (insn_data_t *)val;
3179 return (int)e->insn;
3180 }
3181
3182 rb_bug("rb_vm_insn_addr2insn: invalid insn address: %p", addr);
3183}
3184
3185static inline int
3186encoded_iseq_trace_instrument(VALUE *iseq_encoded_insn, rb_event_flag_t turnon, bool remain_current_trace)
3187{
3188 st_data_t key = (st_data_t)*iseq_encoded_insn;
3189 st_data_t val;
3190
3191 if (st_lookup(encoded_insn_data, key, &val)) {
3192 insn_data_t *e = (insn_data_t *)val;
3193 if (remain_current_trace && key == (st_data_t)e->trace_encoded_insn) {
3194 turnon = 1;
3195 }
3196 *iseq_encoded_insn = (VALUE) (turnon ? e->trace_encoded_insn : e->notrace_encoded_insn);
3197 return e->insn_len;
3198 }
3199
3200 rb_bug("trace_instrument: invalid insn address: %p", (void *)*iseq_encoded_insn);
3201}
3202
3203void
3205{
3206 const struct rb_iseq_constant_body *const body = iseq->body;
3208 encoded_iseq_trace_instrument(&iseq_encoded[pos], 0, false);
3209}
3210
3211static int
3212iseq_add_local_tracepoint(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval, unsigned int target_line)
3213{
3214 unsigned int pc;
3215 int n = 0;
3216 const struct rb_iseq_constant_body *const body = iseq->body;
3218
3220
3221 for (pc=0; pc<body->iseq_size;) {
3222 const struct iseq_insn_info_entry *entry = get_insn_info(iseq, pc);
3223 rb_event_flag_t pc_events = entry->events;
3224 rb_event_flag_t target_events = turnon_events;
3225 unsigned int line = (int)entry->line_no;
3226
3227 if (target_line == 0 || target_line == line) {
3228 /* ok */
3229 }
3230 else {
3231 target_events &= ~RUBY_EVENT_LINE;
3232 }
3233
3234 if (pc_events & target_events) {
3235 n++;
3236 }
3237 pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & (target_events | iseq->aux.exec.global_trace_events), true);
3238 }
3239
3240 if (n > 0) {
3241 if (iseq->aux.exec.local_hooks == NULL) {
3242 ((rb_iseq_t *)iseq)->aux.exec.local_hooks = RB_ZALLOC(rb_hook_list_t);
3243 }
3244 rb_hook_list_connect_tracepoint((VALUE)iseq, iseq->aux.exec.local_hooks, tpval, target_line);
3245 }
3246
3247 return n;
3248}
3249
3253 unsigned int target_line;
3254 int n;
3255};
3256
3257static void
3258iseq_add_local_tracepoint_i(const rb_iseq_t *iseq, void *p)
3259{
3261 data->n += iseq_add_local_tracepoint(iseq, data->turnon_events, data->tpval, data->target_line);
3262 iseq_iterate_children(iseq, iseq_add_local_tracepoint_i, p);
3263}
3264
3265int
3267{
3270 data.tpval = tpval;
3271 data.target_line = target_line;
3272 data.n = 0;
3273
3274 iseq_add_local_tracepoint_i(iseq, (void *)&data);
3275 if (0) rb_funcall(Qnil, rb_intern("puts"), 1, rb_iseq_disasm(iseq)); /* for debug */
3276 return data.n;
3277}
3278
3279static int
3280iseq_remove_local_tracepoint(const rb_iseq_t *iseq, VALUE tpval)
3281{
3282 int n = 0;
3283
3284 if (iseq->aux.exec.local_hooks) {
3285 unsigned int pc;
3286 const struct rb_iseq_constant_body *const body = iseq->body;
3288 rb_event_flag_t local_events = 0;
3289
3291 local_events = iseq->aux.exec.local_hooks->events;
3292
3293 if (local_events == 0) {
3294 if (iseq->aux.exec.local_hooks->running == 0) {
3296 }
3297 ((rb_iseq_t *)iseq)->aux.exec.local_hooks = NULL;
3298 }
3299
3300 for (pc = 0; pc<body->iseq_size;) {
3301 rb_event_flag_t pc_events = rb_iseq_event_flags(iseq, pc);
3302 pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & (local_events | iseq->aux.exec.global_trace_events), false);
3303 }
3304 }
3305 return n;
3306}
3307
3310 int n;
3311};
3312
3313static void
3314iseq_remove_local_tracepoint_i(const rb_iseq_t *iseq, void *p)
3315{
3317 data->n += iseq_remove_local_tracepoint(iseq, data->tpval);
3318 iseq_iterate_children(iseq, iseq_remove_local_tracepoint_i, p);
3319}
3320
3321int
3323{
3325 data.tpval = tpval;
3326 data.n = 0;
3327
3328 iseq_remove_local_tracepoint_i(iseq, (void *)&data);
3329 return data.n;
3330}
3331
3332void
3334{
3335 if (iseq->aux.exec.global_trace_events == turnon_events) {
3336 return;
3337 }
3338
3339 if (!ISEQ_EXECUTABLE_P(iseq)) {
3340 /* this is building ISeq */
3341 return;
3342 }
3343 else {
3344 unsigned int pc;
3345 const struct rb_iseq_constant_body *const body = iseq->body;
3347 rb_event_flag_t enabled_events;
3348 rb_event_flag_t local_events = iseq->aux.exec.local_hooks ? iseq->aux.exec.local_hooks->events : 0;
3349 ((rb_iseq_t *)iseq)->aux.exec.global_trace_events = turnon_events;
3350 enabled_events = turnon_events | local_events;
3351
3352 for (pc=0; pc<body->iseq_size;) {
3353 rb_event_flag_t pc_events = rb_iseq_event_flags(iseq, pc);
3354 pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & enabled_events, true);
3355 }
3356 }
3357}
3358
3359static int
3360trace_set_i(void *vstart, void *vend, size_t stride, void *data)
3361{
3362 rb_event_flag_t turnon_events = *(rb_event_flag_t *)data;
3363
3364 VALUE v = (VALUE)vstart;
3365 for (; v != (VALUE)vend; v += stride) {
3366 void *ptr = asan_poisoned_object_p(v);
3367 asan_unpoison_object(v, false);
3368
3369 if (rb_obj_is_iseq(v)) {
3370 rb_iseq_trace_set(rb_iseq_check((rb_iseq_t *)v), turnon_events);
3371 }
3372
3374 }
3375 return 0;
3376}
3377
3378void
3380{
3381 rb_objspace_each_objects(trace_set_i, &turnon_events);
3382}
3383
3384VALUE
3386{
3387 return rb_iseq_local_variables(iseqw_check(iseqval));
3388}
3389
3390/*
3391 * call-seq:
3392 * iseq.to_binary(extra_data = nil) -> binary str
3393 *
3394 * Returns serialized iseq binary format data as a String object.
3395 * A corresponding iseq object is created by
3396 * RubyVM::InstructionSequence.load_from_binary() method.
3397 *
3398 * String extra_data will be saved with binary data.
3399 * You can access this data with
3400 * RubyVM::InstructionSequence.load_from_binary_extra_data(binary).
3401 *
3402 * Note that the translated binary data is not portable.
3403 * You can not move this binary data to another machine.
3404 * You can not use the binary data which is created by another
3405 * version/another architecture of Ruby.
3406 */
3407static VALUE
3408iseqw_to_binary(int argc, VALUE *argv, VALUE self)
3409{
3410 VALUE opt = !rb_check_arity(argc, 0, 1) ? Qnil : argv[0];
3411 return rb_iseq_ibf_dump(iseqw_check(self), opt);
3412}
3413
3414/*
3415 * call-seq:
3416 * RubyVM::InstructionSequence.load_from_binary(binary) -> iseq
3417 *
3418 * Load an iseq object from binary format String object
3419 * created by RubyVM::InstructionSequence.to_binary.
3420 *
3421 * This loader does not have a verifier, so that loading broken/modified
3422 * binary causes critical problem.
3423 *
3424 * You should not load binary data provided by others.
3425 * You should use binary data translated by yourself.
3426 */
3427static VALUE
3428iseqw_s_load_from_binary(VALUE self, VALUE str)
3429{
3430 return iseqw_new(rb_iseq_ibf_load(str));
3431}
3432
3433/*
3434 * call-seq:
3435 * RubyVM::InstructionSequence.load_from_binary_extra_data(binary) -> str
3436 *
3437 * Load extra data embed into binary format String object.
3438 */
3439static VALUE
3440iseqw_s_load_from_binary_extra_data(VALUE self, VALUE str)
3441{
3443}
3444
3445#if VM_INSN_INFO_TABLE_IMPL == 2
3446
3447/* An implementation of succinct bit-vector for insn_info table.
3448 *
3449 * A succinct bit-vector is a small and efficient data structure that provides
3450 * a bit-vector augmented with an index for O(1) rank operation:
3451 *
3452 * rank(bv, n): the number of 1's within a range from index 0 to index n
3453 *
3454 * This can be used to lookup insn_info table from PC.
3455 * For example, consider the following iseq and insn_info_table:
3456 *
3457 * iseq insn_info_table
3458 * PC insn+operand position lineno event
3459 * 0: insn1 0: 1 [Li]
3460 * 2: insn2 2: 2 [Li] <= (A)
3461 * 5: insn3 8: 3 [Li] <= (B)
3462 * 8: insn4
3463 *
3464 * In this case, a succinct bit-vector whose indexes 0, 2, 8 is "1" and
3465 * other indexes is "0", i.e., "101000001", is created.
3466 * To lookup the lineno of insn2, calculate rank("10100001", 2) = 2, so
3467 * the line (A) is the entry in question.
3468 * To lookup the lineno of insn4, calculate rank("10100001", 8) = 3, so
3469 * the line (B) is the entry in question.
3470 *
3471 * A naive implementation of succinct bit-vector works really well
3472 * not only for large size but also for small size. However, it has
3473 * tiny overhead for very small size. So, this implementation consist
3474 * of two parts: one part is the "immediate" table that keeps rank result
3475 * as a raw table, and the other part is a normal succinct bit-vector.
3476 */
3477
3478#define IMMEDIATE_TABLE_SIZE 54 /* a multiple of 9, and < 128 */
3479
3480struct succ_index_table {
3481 uint64_t imm_part[IMMEDIATE_TABLE_SIZE / 9];
3482 struct succ_dict_block {
3483 unsigned int rank;
3484 uint64_t small_block_ranks; /* 9 bits * 7 = 63 bits */
3485 uint64_t bits[512/64];
3486 } succ_part[FLEX_ARY_LEN];
3487};
3488
3489#define imm_block_rank_set(v, i, r) (v) |= (uint64_t)(r) << (7 * (i))
3490#define imm_block_rank_get(v, i) (((int)((v) >> ((i) * 7))) & 0x7f)
3491#define small_block_rank_set(v, i, r) (v) |= (uint64_t)(r) << (9 * ((i) - 1))
3492#define small_block_rank_get(v, i) ((i) == 0 ? 0 : (((int)((v) >> (((i) - 1) * 9))) & 0x1ff))
3493
3494static struct succ_index_table *
3495succ_index_table_create(int max_pos, int *data, int size)
3496{
3497 const int imm_size = (max_pos < IMMEDIATE_TABLE_SIZE ? max_pos + 8 : IMMEDIATE_TABLE_SIZE) / 9;
3498 const int succ_size = (max_pos < IMMEDIATE_TABLE_SIZE ? 0 : (max_pos - IMMEDIATE_TABLE_SIZE + 511)) / 512;
3499 struct succ_index_table *sd =
3501 imm_size, sizeof(uint64_t),
3502 succ_size, sizeof(struct succ_dict_block));
3503 int i, j, k, r;
3504
3505 r = 0;
3506 for (j = 0; j < imm_size; j++) {
3507 for (i = 0; i < 9; i++) {
3508 if (r < size && data[r] == j * 9 + i) r++;
3509 imm_block_rank_set(sd->imm_part[j], i, r);
3510 }
3511 }
3512 for (k = 0; k < succ_size; k++) {
3513 struct succ_dict_block *sd_block = &sd->succ_part[k];
3514 int small_rank = 0;
3515 sd_block->rank = r;
3516 for (j = 0; j < 8; j++) {
3517 uint64_t bits = 0;
3518 if (j) small_block_rank_set(sd_block->small_block_ranks, j, small_rank);
3519 for (i = 0; i < 64; i++) {
3520 if (r < size && data[r] == k * 512 + j * 64 + i + IMMEDIATE_TABLE_SIZE) {
3521 bits |= ((uint64_t)1) << i;
3522 r++;
3523 }
3524 }
3525 sd_block->bits[j] = bits;
3526 small_rank += rb_popcount64(bits);
3527 }
3528 }
3529 return sd;
3530}
3531
3532static unsigned int *
3533succ_index_table_invert(int max_pos, struct succ_index_table *sd, int size)
3534{
3535 const int imm_size = (max_pos < IMMEDIATE_TABLE_SIZE ? max_pos + 8 : IMMEDIATE_TABLE_SIZE) / 9;
3536 const int succ_size = (max_pos < IMMEDIATE_TABLE_SIZE ? 0 : (max_pos - IMMEDIATE_TABLE_SIZE + 511)) / 512;
3537 unsigned int *positions = ALLOC_N(unsigned int, size), *p;
3538 int i, j, k, r = -1;
3539 p = positions;
3540 for (j = 0; j < imm_size; j++) {
3541 for (i = 0; i < 9; i++) {
3542 int nr = imm_block_rank_get(sd->imm_part[j], i);
3543 if (r != nr) *p++ = j * 9 + i;
3544 r = nr;
3545 }
3546 }
3547 for (k = 0; k < succ_size; k++) {
3548 for (j = 0; j < 8; j++) {
3549 for (i = 0; i < 64; i++) {
3550 if (sd->succ_part[k].bits[j] & (((uint64_t)1) << i)) {
3551 *p++ = k * 512 + j * 64 + i + IMMEDIATE_TABLE_SIZE;
3552 }
3553 }
3554 }
3555 }
3556 return positions;
3557}
3558
3559static int
3560succ_index_lookup(const struct succ_index_table *sd, int x)
3561{
3562 if (x < IMMEDIATE_TABLE_SIZE) {
3563 const int i = x / 9;
3564 const int j = x % 9;
3565 return imm_block_rank_get(sd->imm_part[i], j);
3566 }
3567 else {
3568 const int block_index = (x - IMMEDIATE_TABLE_SIZE) / 512;
3569 const struct succ_dict_block *block = &sd->succ_part[block_index];
3570 const int block_bit_index = (x - IMMEDIATE_TABLE_SIZE) % 512;
3571 const int small_block_index = block_bit_index / 64;
3572 const int small_block_popcount = small_block_rank_get(block->small_block_ranks, small_block_index);
3573 const int popcnt = rb_popcount64(block->bits[small_block_index] << (63 - block_bit_index % 64));
3574
3575 return block->rank + small_block_popcount + popcnt;
3576 }
3577}
3578#endif
3579
3580/*
3581 * Document-class: RubyVM::InstructionSequence
3582 *
3583 * The InstructionSequence class represents a compiled sequence of
3584 * instructions for the Virtual Machine used in MRI. Not all implementations of Ruby
3585 * may implement this class, and for the implementations that implement it,
3586 * the methods defined and behavior of the methods can change in any version.
3587 *
3588 * With it, you can get a handle to the instructions that make up a method or
3589 * a proc, compile strings of Ruby code down to VM instructions, and
3590 * disassemble instruction sequences to strings for easy inspection. It is
3591 * mostly useful if you want to learn how YARV works, but it also lets
3592 * you control various settings for the Ruby iseq compiler.
3593 *
3594 * You can find the source for the VM instructions in +insns.def+ in the Ruby
3595 * source.
3596 *
3597 * The instruction sequence results will almost certainly change as Ruby
3598 * changes, so example output in this documentation may be different from what
3599 * you see.
3600 *
3601 * Of course, this class is MRI specific.
3602 */
3603
3604void
3606{
3607 /* declare ::RubyVM::InstructionSequence */
3608 rb_cISeq = rb_define_class_under(rb_cRubyVM, "InstructionSequence", rb_cObject);
3610 rb_define_method(rb_cISeq, "inspect", iseqw_inspect, 0);
3611 rb_define_method(rb_cISeq, "disasm", iseqw_disasm, 0);
3612 rb_define_method(rb_cISeq, "disassemble", iseqw_disasm, 0);
3613 rb_define_method(rb_cISeq, "to_a", iseqw_to_a, 0);
3614 rb_define_method(rb_cISeq, "eval", iseqw_eval, 0);
3615
3616 rb_define_method(rb_cISeq, "to_binary", iseqw_to_binary, -1);
3617 rb_define_singleton_method(rb_cISeq, "load_from_binary", iseqw_s_load_from_binary, 1);
3618 rb_define_singleton_method(rb_cISeq, "load_from_binary_extra_data", iseqw_s_load_from_binary_extra_data, 1);
3619
3620
3621 /* location APIs */
3622 rb_define_method(rb_cISeq, "path", iseqw_path, 0);
3623 rb_define_method(rb_cISeq, "absolute_path", iseqw_absolute_path, 0);
3624 rb_define_method(rb_cISeq, "label", iseqw_label, 0);
3625 rb_define_method(rb_cISeq, "base_label", iseqw_base_label, 0);
3626 rb_define_method(rb_cISeq, "first_lineno", iseqw_first_lineno, 0);
3627 rb_define_method(rb_cISeq, "trace_points", iseqw_trace_points, 0);
3628 rb_define_method(rb_cISeq, "each_child", iseqw_each_child, 0);
3629
3630#if 0 /* TBD */
3631 rb_define_private_method(rb_cISeq, "marshal_dump", iseqw_marshal_dump, 0);
3632 rb_define_private_method(rb_cISeq, "marshal_load", iseqw_marshal_load, 1);
3633 /* disable this feature because there is no verifier. */
3634 rb_define_singleton_method(rb_cISeq, "load", iseq_s_load, -1);
3635#endif
3636 (void)iseq_s_load;
3637
3638 rb_define_singleton_method(rb_cISeq, "compile", iseqw_s_compile, -1);
3639 rb_define_singleton_method(rb_cISeq, "new", iseqw_s_compile, -1);
3640 rb_define_singleton_method(rb_cISeq, "compile_file", iseqw_s_compile_file, -1);
3641 rb_define_singleton_method(rb_cISeq, "compile_option", iseqw_s_compile_option_get, 0);
3642 rb_define_singleton_method(rb_cISeq, "compile_option=", iseqw_s_compile_option_set, 1);
3643 rb_define_singleton_method(rb_cISeq, "disasm", iseqw_s_disasm, 1);
3644 rb_define_singleton_method(rb_cISeq, "disassemble", iseqw_s_disasm, 1);
3645 rb_define_singleton_method(rb_cISeq, "of", iseqw_s_of, 1);
3646
3647 rb_undef_method(CLASS_OF(rb_cISeq), "translate");
3648 rb_undef_method(CLASS_OF(rb_cISeq), "load_iseq");
3649}
#define offsetof(p_type, field)
Definition: addrinfo.h:186
VALUE rb_ary_new_from_values(long n, const VALUE *elts)
Definition: array.c:788
void rb_ary_store(VALUE ary, long idx, VALUE val)
Definition: array.c:1141
VALUE rb_ary_resurrect(VALUE ary)
Definition: array.c:2679
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:1301
VALUE rb_ary_new(void)
Definition: array.c:749
VALUE rb_ary_tmp_new(long capa)
Definition: array.c:846
VALUE rb_ary_entry(VALUE ary, long offset)
Definition: array.c:1672
VALUE rb_ary_join(VALUE ary, VALUE sep)
Definition: array.c:2780
Internal header for bitwise integer algorithms.
int bits(struct state *s, int need)
Definition: blast.c:72
int main(void)
Definition: closure_fn0.c:49
const ID rb_iseq_shared_exc_local_tbl[]
Definition: compile.c:125
void rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
Definition: compile.c:11971
VALUE rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
Definition: compile.c:11913
rb_iseq_t * iseq_alloc(void)
VALUE rb_iseq_ibf_load_extra_data(VALUE str)
Definition: compile.c:12164
VALUE rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
Definition: compile.c:729
const rb_iseq_t * rb_iseq_ibf_load(VALUE str)
Definition: compile.c:12136
VALUE rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc)
Definition: compile.c:715
void rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params, VALUE exception, VALUE body)
Definition: compile.c:9665
VALUE * rb_iseq_original_iseq(const rb_iseq_t *iseq)
Definition: compile.c:863
void rb_iseq_mark_insn_storage(struct iseq_compile_data_storage *storage)
Definition: compile.c:9611
Internal header for the compiler.
#define FLEX_ARY_LEN
Definition: compilers.h:88
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:653
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
Definition: cxxanyargs.hpp:668
#define rb_define_private_method(klass, mid, func, arity)
Defines klass#mid and makes it private.
Definition: cxxanyargs.hpp:660
struct RIMemo * ptr
Definition: debug.c:88
enum imemo_type types
Definition: debug.c:86
#define RB_DEBUG_COUNTER_ADD(type, num)
#define RB_DEBUG_COUNTER_INC(type)
#define MJIT_FUNC_EXPORTED
Definition: dllexport.h:55
string_t out
Definition: enough.c:230
#define sym(name)
Definition: enumerator.c:4007
uint8_t len
Definition: escape.c:17
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
#define numberof(array)
Definition: etc.c:649
#define RUBY_EVENT_END
Definition: event.h:32
#define RUBY_EVENT_C_CALL
Definition: event.h:35
#define RUBY_EVENT_B_RETURN
Definition: event.h:42
#define RUBY_EVENT_CLASS
Definition: event.h:31
#define RUBY_EVENT_LINE
Definition: event.h:30
#define RUBY_EVENT_RETURN
Definition: event.h:34
#define RUBY_EVENT_C_RETURN
Definition: event.h:36
#define RUBY_EVENT_B_CALL
Definition: event.h:41
uint32_t rb_event_flag_t
Definition: event.h:66
#define RUBY_EVENT_CALL
Definition: event.h:33
ID id_class
Definition: eventids1.c:32
ID id_ensure
Definition: eventids1.c:48
ID id_rescue
Definition: eventids1.c:94
#define RSTRING_LEN(string)
Definition: fbuffer.h:22
#define RSTRING_PTR(string)
Definition: fbuffer.h:19
#define LIKELY(x)
Definition: ffi_common.h:125
VALUE rb_realpath_internal(VALUE basedir, VALUE path, int strict)
Definition: file.c:4496
#define RB_OBJ_FREEZE
Definition: fl_type.h:86
#define PRIsVALUE
Definition: function.c:10
void ruby_xfree(void *x)
Deallocates a storage instance.
Definition: gc.c:10914
VALUE rb_gc_location(VALUE value)
Definition: gc.c:9003
void rb_mark_set(st_table *tbl)
Definition: gc.c:5686
void * ruby_xcalloc(size_t n, size_t size)
Identical to ruby_xmalloc2(), except it zero-fills the region before it returns.
Definition: gc.c:12815
void rb_gc_mark_movable(VALUE ptr)
Definition: gc.c:6106
void rb_mark_tbl(st_table *tbl)
Definition: gc.c:5893
void * rb_xcalloc_mul_add_mul(size_t x, size_t y, size_t z, size_t w)
Definition: gc.c:10941
void rb_gc_mark(VALUE ptr)
Definition: gc.c:6112
void rb_objspace_each_objects(each_obj_callback *callback, void *data)
Definition: gc.c:3285
void rb_gc_register_mark_object(VALUE obj)
Inform the garbage collector that object is a live Ruby object that should not be moved.
Definition: gc.c:8022
#define RUBY_MARK_LEAVE(msg)
Definition: gc.h:65
#define RUBY_MARK_ENTER(msg)
Definition: gc.h:64
#define RUBY_MARK_MOVABLE_UNLESS_NULL(ptr)
Definition: gc.h:71
#define RUBY_FREE_ENTER(msg)
Definition: gc.h:66
#define RUBY_FREE_LEAVE(msg)
Definition: gc.h:67
#define RUBY_MARK_UNLESS_NULL(ptr)
Definition: gc.h:75
#define CLASS_OF
Definition: globals.h:153
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:797
void rb_undef_method(VALUE klass, const char *name)
Definition: class.c:1777
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:2296
#define OBJ_FREEZE
Definition: fl_type.h:134
#define FL_TEST_RAW
Definition: fl_type.h:131
#define FL_TEST
Definition: fl_type.h:130
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2917
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition: eval.c:712
void rb_bug(const char *fmt,...)
Definition: error.c:768
VALUE rb_ident_hash_new(void)
Definition: hash.c:4443
VALUE rb_eTypeError
Definition: error.c:1057
VALUE rb_iseqw_local_variables(VALUE iseqval)
Definition: iseq.c:3385
VALUE rb_iseqw_new(const rb_iseq_t *iseq)
Definition: iseq.c:1217
VALUE rb_eSyntaxError
Definition: error.c:1073
VALUE rb_cObject
Object class.
Definition: object.c:49
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition: object.c:92
VALUE rb_obj_class(VALUE)
Definition: object.c:245
VALUE rb_inspect(VALUE)
Convenient wrapper of Object::inspect.
Definition: object.c:585
VALUE rb_obj_freeze(VALUE)
Make the object unmodifiable.
Definition: object.c:1101
unsigned in(void *in_desc, z_const unsigned char **buf)
Definition: gun.c:89
VALUE rb_hash_resurrect(VALUE hash)
Definition: hash.c:1590
void rb_hash_foreach(VALUE hash, rb_foreach_func *func, VALUE farg)
Definition: hash.c:1498
VALUE rb_hash_new_with_size(st_index_t size)
Definition: hash.c:1544
VALUE rb_hash_aref(VALUE hash, VALUE key)
Definition: hash.c:2046
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Definition: hash.c:2901
VALUE rb_hash_lookup(VALUE hash, VALUE key)
Definition: hash.c:2072
VALUE rb_hash_new(void)
Definition: hash.c:1538
void rb_id_table_free(struct rb_id_table *tbl)
Definition: id_table.c:103
Thin wrapper to ruby/config.h.
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:1077
Defines RBIMPL_HAS_BUILTIN.
#define rb_ary_new2
Definition: array.h:72
void rb_error_arity(int, int, int)
#define rb_check_arity
Definition: error.h:34
VALUE rb_io_close(VALUE)
Definition: io.c:4935
VALUE rb_file_open_str(VALUE, const char *)
Definition: io.c:6382
VALUE rb_obj_is_method(VALUE)
Definition: proc.c:1590
VALUE rb_obj_is_proc(VALUE)
Definition: proc.c:152
#define rb_str_new2
Definition: string.h:276
VALUE rb_str_resize(VALUE, long)
Definition: string.c:2859
VALUE rb_str_concat(VALUE, VALUE)
Definition: string.c:3217
#define rb_str_cat2
Definition: string.h:285
#define rb_str_new(str, len)
Definition: string.h:213
VALUE rb_str_cat(VALUE, const char *, long)
Definition: string.c:2962
#define rb_exc_new_cstr(exc, str)
Definition: string.h:271
void rb_str_set_len(VALUE, long)
Definition: string.c:2842
VALUE rb_str_resurrect(VALUE str)
Definition: string.c:1637
VALUE rb_str_inspect(VALUE)
Definition: string.c:6199
int rb_str_cmp(VALUE, VALUE)
Definition: string.c:3378
VALUE rb_str_append(VALUE, VALUE)
Definition: string.c:3118
void rb_str_modify_expand(VALUE, long)
Definition: string.c:2270
VALUE rb_str_intern(VALUE)
Definition: symbol.c:840
#define rb_str_cat_cstr(buf, str)
Definition: string.h:266
VALUE rb_str_dup(VALUE)
Definition: string.c:1631
#define rb_str_new_cstr(str)
Definition: string.h:219
VALUE rb_class_name(VALUE)
Definition: variable.c:293
VALUE rb_check_funcall(VALUE, ID, int, const VALUE *)
Definition: vm_eval.c:619
int rb_respond_to(VALUE, ID)
Definition: vm_method.c:2561
void rb_undef_alloc_func(VALUE)
Definition: vm_method.c:954
#define ID2SYM
Definition: symbol.h:44
VALUE rb_sym2str(VALUE)
Definition: symbol.c:927
ID rb_intern(const char *)
Definition: symbol.c:785
ID rb_check_id(volatile VALUE *)
Returns ID for the given name if it is interned already, or 0.
Definition: symbol.c:1069
#define CONST_ID
Definition: symbol.h:47
#define FIX2INT
Definition: int.h:41
#define NUM2INT
Definition: int.h:44
#define INT2NUM
Definition: int.h:43
#define UINT2NUM
Definition: int.h:46
#define LL2NUM
Definition: long_long.h:30
Internal header for Class.
#define rb_typeddata_is_instance_of
Definition: error.h:71
Internal header for File.
Internal header for GC.
#define UNALIGNED_MEMBER_PTR(ptr, mem)
Definition: gc.h:59
Internal header for Hash.
Internal header for the parser.
void * rb_parser_load_file(VALUE parser, VALUE name)
Definition: ruby.c:2374
int rb_str_symname_p(VALUE)
Definition: string.c:11027
#define rb_fstring_lit(str)
Definition: string.h:78
VALUE rb_fstring(VALUE)
Definition: string.c:353
Internal header for Thread.
VALUE rb_get_coverages(void)
Definition: thread.c:5773
VALUE rb_default_coverage(int)
Definition: thread.c:5815
#define COVERAGE_TARGET_ONESHOT_LINES
Definition: thread.h:23
int rb_get_coverage_mode(void)
Definition: thread.c:5779
const void ** rb_vm_get_insns_address_table(void)
Definition: vm_exec.c:153
const char * rb_type_str(enum ruby_value_type type)
Definition: vm_eval.c:686
#define rb_ary_new_from_args(...)
Definition: internal.h:65
#define rb_funcallv(...)
Definition: internal.h:77
#define PRIdVALUE
Definition: inttypes.h:72
#define PRIuSIZE
Definition: inttypes.h:127
#define PRIdPTRDIFF
Definition: inttypes.h:105
#define PRIuVALUE
Definition: inttypes.h:74
voidpf void uLong size
Definition: ioapi.h:138
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
void rb_iseq_remove_coverage_all(void)
Definition: iseq.c:1170
#define INITIALIZED
VALUE rb_iseq_path(const rb_iseq_t *iseq)
Definition: iseq.c:1087
void rb_iseq_init_trace(rb_iseq_t *iseq)
Definition: iseq.c:675
int rb_vm_insn_addr2insn(const void *addr)
Definition: iseq.c:3172
VALUE rb_iseq_pathobj_new(VALUE path, VALUE realpath)
Definition: iseq.c:502
VALUE iseq_value_itr_t(void *ctx, VALUE obj)
Definition: iseq.c:158
void rb_iseq_insns_info_encode_positions(const rb_iseq_t *iseq)
Definition: iseq.c:646
void 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)
Definition: iseq.c:1136
rb_iseq_t * rb_iseq_new_with_callback(const struct rb_iseq_new_with_callback_callback_func *ifunc, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_iseq_t *parent, enum iseq_type type, const rb_compile_option_t *option)
Definition: iseq.c:888
unsigned int rb_iseq_line_no(const rb_iseq_t *iseq, size_t pos)
Definition: iseq.c:1821
void rb_iseq_pathobj_set(const rb_iseq_t *iseq, VALUE path, VALUE realpath)
Definition: iseq.c:521
VALUE rb_dump_literal(VALUE lit)
Definition: node.c:83
#define CALL_FLAG(n)
#define PARAM_TYPE(type)
VALUE rb_cISeq
Definition: iseq.c:46
void rb_vm_encoded_insn_data_table_init(void)
Definition: iseq.c:3139
void Init_ISeq(void)
Definition: iseq.c:3605
#define CHECK_STRING(v)
Definition: iseq.c:920
VALUE rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
Definition: iseq.c:2993
rb_iseq_t * rb_iseq_new_with_opt(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_iseq_t *parent, int isolated_depth, enum iseq_type type, const rb_compile_option_t *option)
Definition: iseq.c:862
#define C(ev, cstr, l)
#define CHECK_ARRAY(v)
Definition: iseq.c:918
#define PARAM(i, type)
VALUE rb_iseq_label(const rb_iseq_t *iseq)
Definition: iseq.c:1105
#define SET_COMPILE_OPTION(o, h, mem)
#define DECL_SYMBOL(name)
Definition: iseq.c:2603
VALUE rb_iseq_base_label(const rb_iseq_t *iseq)
Definition: iseq.c:1111
VALUE rb_insn_operand_intern(const rb_iseq_t *iseq, VALUE insn, int op_no, VALUE op, int len, size_t pos, const VALUE *pnop, VALUE child)
Definition: iseq.c:1889
rb_iseq_t * rb_iseq_new_main(const rb_ast_body_t *ast, VALUE path, VALUE realpath, const rb_iseq_t *parent)
Definition: iseq.c:833
VALUE rb_iseq_coverage(const rb_iseq_t *iseq)
Definition: iseq.c:1146
int rb_insn_unified_local_var_level(VALUE)
VALUE rb_iseq_defined_string(enum defined_type type)
Definition: iseq.c:3087
void rb_iseq_update_references(rb_iseq_t *iseq)
Definition: iseq.c:257
const rb_iseq_t * rb_iseqw_to_iseq(VALUE iseqw)
Definition: iseq.c:1410
struct insn_data_struct insn_data_t
#define PARAM_ID(i)
#define INIT_SYMBOL(name)
Definition: iseq.c:2606
void rb_iseq_trace_set_all(rb_event_flag_t turnon_events)
Definition: iseq.c:3379
void rb_iseq_trace_flag_cleared(const rb_iseq_t *iseq, size_t pos)
Definition: iseq.c:3204
#define CHECK_EVENT(ev)
const char * ruby_node_name(int node)
Definition: iseq.c:2593
VALUE rb_iseq_absolute_path(const rb_iseq_t *iseq)
Definition: iseq.c:1099
#define INSN_CODE(insn)
void rb_iseq_trace_set(const rb_iseq_t *iseq, rb_event_flag_t turnon_events)
Definition: iseq.c:3333
VALUE rb_iseq_first_lineno(const rb_iseq_t *iseq)
Definition: iseq.c:1117
const rb_iseq_t * rb_iseq_load_iseq(VALUE fname)
Definition: iseq.c:907
rb_iseq_t * rb_iseq_new_eval(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_iseq_t *parent, int isolated_depth)
Definition: iseq.c:841
rb_event_flag_t rb_iseq_event_flags(const rb_iseq_t *iseq, size_t pos)
Definition: iseq.c:1834
struct rb_iseq_constant_body * rb_iseq_constant_body_alloc(void)
Definition: iseq.c:486
VALUE rb_vm_insns_translator_t(const void *addr)
Definition: iseq.c:159
#define CHECK_HASH(v)
Definition: iseq.c:919
void rb_iseq_mark(const rb_iseq_t *iseq)
Definition: iseq.c:332
VALUE rb_iseq_method_name(const rb_iseq_t *iseq)
Definition: iseq.c:1123
rb_iseq_t * rb_iseq_new(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent, enum iseq_type type)
Definition: iseq.c:809
VALUE rb_iseq_disasm(const rb_iseq_t *iseq)
Definition: iseq.c:2335
VALUE rb_iseq_load(VALUE data, VALUE parent, VALUE opt)
Definition: iseq.c:1032
void rb_iseq_free(const rb_iseq_t *iseq)
Definition: iseq.c:105
void rb_iseq_clear_event_flags(const rb_iseq_t *iseq, size_t pos, rb_event_flag_t reset)
Definition: iseq.c:1846
#define hidden_obj_p(obj)
Definition: iseq.c:56
rb_iseq_t * rb_iseq_new_top(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent)
Definition: iseq.c:817
#define SET_COMPILE_OPTION_NUM(o, h, mem)
int rb_iseq_disasm_insn(VALUE ret, const VALUE *code, size_t pos, const rb_iseq_t *iseq, VALUE child)
Disassemble a instruction Iseq -> Iseq inspect object.
Definition: iseq.c:2078
VALUE rb_iseq_realpath(const rb_iseq_t *iseq)
Definition: iseq.c:1093
int rb_iseq_remove_local_tracepoint_recursively(const rb_iseq_t *iseq, VALUE tpval)
Definition: iseq.c:3322
size_t rb_iseq_memsize(const rb_iseq_t *iseq)
Definition: iseq.c:442
int rb_iseq_add_local_tracepoint_recursively(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval, unsigned int target_line)
Definition: iseq.c:3266
#define CHECK_SYMBOL(v)
Definition: iseq.c:921
#define ISEQ_COVERAGE(iseq)
Definition: iseq.h:27
#define ISEQ_COVERAGE_SET(iseq, cov)
Definition: iseq.h:28
#define ISEQ_TRANSLATED
Definition: iseq.h:80
#define ISEQ_NOT_LOADED_YET
Definition: iseq.h:78
#define ISEQ_MAJOR_VERSION
Definition: iseq.h:17
#define ISEQ_USE_COMPILE_DATA
Definition: iseq.h:79
defined_type
Definition: iseq.h:276
@ DEFINED_REF
Definition: iseq.h:293
@ DEFINED_FUNC
Definition: iseq.h:294
@ DEFINED_CONST_FROM
Definition: iseq.h:295
#define ISEQ_TRACE_EVENTS
Definition: iseq.h:68
VALUE rb_iseq_local_variables(const rb_iseq_t *iseq)
Definition: vm.c:885
#define INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE
Definition: iseq.h:265
#define ISEQ_EXECUTABLE_P(iseq)
Definition: iseq.h:83
const rb_iseq_t * rb_method_iseq(VALUE body)
Definition: proc.c:2835
#define ISEQ_MARKABLE_ISEQ
Definition: iseq.h:81
#define ISEQ_BRANCH_COVERAGE(iseq)
Definition: iseq.h:30
#define ISEQ_MINOR_VERSION
Definition: iseq.h:18
#define ISEQ_PC2BRANCHINDEX_SET(iseq, h)
Definition: iseq.h:33
VALUE rb_yield(VALUE)
Definition: vm_eval.c:1341
#define INT2FIX
Definition: long.h:48
#define ULONG2NUM
Definition: long.h:60
#define LONG2NUM
Definition: long.h:50
#define NUM2LONG
Definition: long.h:51
#define ALLOC_N
Definition: memory.h:133
#define RB_GC_GUARD(v)
Definition: memory.h:91
#define RB_ZALLOC(type)
Definition: memory.h:108
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition: cxxanyargs.hpp:56
unsigned int top
Definition: nkf.c:4323
const int id
Definition: nkf.c:209
const char * name
Definition: nkf.c:208
#define TRUE
Definition: nkf.h:175
#define FALSE
Definition: nkf.h:174
void rb_ast_dispose(rb_ast_t *ast)
Definition: node.c:1448
#define nd_node_id(n)
Definition: node.h:213
#define debug(lvl, x...)
Definition: ffi.c:52
#define RARRAY_AREF(a, i)
Definition: psych_emitter.c:7
#define RARRAY_LEN
Definition: rarray.h:52
#define RBASIC_CLASS
Definition: rbasic.h:35
#define DATA_PTR(obj)
Definition: rdata.h:56
#define NULL
Definition: regenc.h:69
#define RB_OBJ_WRITE(a, slot, b)
WB for new reference from ‘a’ to ‘b’.
Definition: rgengc.h:107
#define RB_OBJ_WRITTEN(a, oldv, b)
WB for new reference from ‘a’ to ‘b’.
Definition: rgengc.h:114
#define RHASH_SIZE(h)
Definition: rhash.h:50
VALUE rb_parser_new(void)
Definition: ripper.c:20781
rb_ast_t * rb_parser_compile_string_path(VALUE vparser, VALUE f, VALUE s, int line)
Definition: ripper.c:14014
VALUE rb_parser_set_context(VALUE vparser, const struct rb_iseq_struct *base, int main)
Definition: ripper.c:20791
rb_ast_t * rb_parser_compile_file_path(VALUE vparser, VALUE fname, VALUE file, int start)
Definition: ripper.c:14029
#define StringValue(v)
Definition: rstring.h:50
#define StringValueCStr(v)
Definition: rstring.h:52
#define TypedData_Wrap_Struct(klass, data_type, sval)
Definition: rtypeddata.h:101
@ RUBY_TYPED_FREE_IMMEDIATELY
Definition: rtypeddata.h:62
@ RUBY_TYPED_WB_PROTECTED
Definition: rtypeddata.h:64
#define FilePathValue(v)
Definition: ruby.h:61
int argc
Definition: ruby.c:240
char ** argv
Definition: ruby.c:241
Internal header for ASAN / MSAN / etc.
#define asan_poison_object_if(ptr, obj)
Definition: sanitizers.h:130
unsigned long long uint64_t
Definition: sha2.h:102
#define uint64_t
Definition: siphash.h:15
#define Qundef
#define SPECIAL_CONST_P
#define Qtrue
#define RTEST
#define Qnil
#define Qfalse
#define NIL_P
#define FIXNUM_P
#define f
VALUE rb_str_catf(VALUE, const char *,...)
Definition: sprintf.c:1243
VALUE rb_sprintf(const char *,...)
Definition: sprintf.c:1203
@ ST_CONTINUE
Definition: st.h:99
unsigned long st_data_t
Definition: st.h:22
#define st_init_numtable_with_size
Definition: st.h:108
#define st_is_member(table, key)
Definition: st.h:97
#define st_init_numtable
Definition: st.h:106
#define st_lookup
Definition: st.h:128
#define st_add_direct
Definition: st.h:154
#define st_insert
Definition: st.h:124
#define st_free_table
Definition: st.h:156
#define const
Definition: strftime.c:108
Definition: node.h:149
rb_code_location_t nd_loc
Definition: node.h:172
Definition: inftree9.h:24
Definition: gzappend.c:170
void * trace_encoded_insn
Definition: iseq.c:3134
void * notrace_encoded_insn
Definition: iseq.c:3133
Definition: iseq.h:218
catch_type
Definition: iseq.h:219
rb_iseq_t * iseq
Definition: iseq.h:240
unsigned int cont
Definition: iseq.h:244
enum iseq_catch_table_entry::catch_type type
unsigned int start
Definition: iseq.h:242
unsigned int end
Definition: iseq.h:243
unsigned int sp
Definition: iseq.h:245
unsigned int pos
Definition: iseq.h:269
unsigned int size
Definition: iseq.h:270
struct iseq_compile_data_storage * next
Definition: iseq.h:268
char buff[FLEX_ARY_LEN]
Definition: iseq.h:271
struct iseq_compile_data::@122 insn
struct rb_id_table * ivar_cache_table
Definition: iseq.h:111
struct iseq_compile_data_storage * storage_head
Definition: iseq.h:97
struct iseq_compile_data::@121 node
const VALUE err_info
Definition: iseq.h:87
const VALUE catch_table_ary
Definition: iseq.h:88
struct iseq_inline_constant_cache_entry * entry
Definition: vm_core.h:232
Definition: vm_core.h:235
struct rb_iv_index_tbl_entry * entry
Definition: vm_core.h:236
Definition: iseq.h:213
int line_no
Definition: iseq.h:214
rb_event_flag_t events
Definition: iseq.h:215
const NODE * root
Definition: node.h:399
VALUE compile_option
Definition: node.h:400
rb_ast_body_t body
Definition: node.h:406
const int argc
Definition: builtin.h:9
const char *const name
Definition: builtin.h:13
const struct rb_callcache * cc
Definition: vm_callinfo.h:428
const struct rb_callinfo * ci
Definition: vm_callinfo.h:427
rb_code_position_t beg_pos
Definition: node.h:136
rb_code_position_t end_pos
Definition: node.h:137
unsigned int coverage_enabled
Definition: iseq.h:209
unsigned int peephole_optimization
Definition: iseq.h:201
unsigned int running
Definition: vm_core.h:557
rb_event_flag_t events
Definition: vm_core.h:555
const struct iseq_insn_info_entry * body
Definition: vm_core.h:397
struct iseq_catch_table * catch_table
Definition: vm_core.h:408
unsigned int ambiguous_param0
Definition: vm_core.h:354
rb_snum_t flip_count
Definition: vm_core.h:418
const VALUE * opt_table
Definition: vm_core.h:368
struct rb_iseq_constant_body::iseq_insn_info insns_info
enum rb_iseq_constant_body::iseq_type type
unsigned int size
Definition: vm_core.h:359
unsigned int ci_size
Definition: vm_core.h:426
struct rb_id_table * outer_variables
Definition: vm_core.h:431
const struct rb_iseq_constant_body::@188::rb_iseq_param_keyword * keyword
struct rb_iseq_struct * local_iseq
Definition: vm_core.h:412
unsigned int has_block
Definition: vm_core.h:352
unsigned int local_table_size
Definition: vm_core.h:424
unsigned int has_kwrest
Definition: vm_core.h:351
unsigned int has_post
Definition: vm_core.h:349
unsigned int stack_max
Definition: vm_core.h:427
struct rb_iseq_constant_body::@188::@190 flags
union iseq_inline_storage_entry * is_entries
Definition: vm_core.h:414
VALUE * iseq_encoded
Definition: vm_core.h:319
unsigned int iseq_size
Definition: vm_core.h:318
rb_iseq_location_t location
Definition: vm_core.h:393
struct rb_iseq_constant_body::@189 variable
unsigned int accepts_no_kwarg
Definition: vm_core.h:355
unsigned int is_size
Definition: vm_core.h:425
unsigned int has_kw
Definition: vm_core.h:350
struct rb_iseq_constant_body::@188 param
parameter information
unsigned int has_opt
Definition: vm_core.h:347
unsigned int has_lead
Definition: vm_core.h:346
const struct rb_iseq_struct * parent_iseq
Definition: vm_core.h:411
struct rb_call_data * call_data
Definition: vm_core.h:415
const ID * local_table
Definition: vm_core.h:405
unsigned int has_rest
Definition: vm_core.h:348
rb_code_location_t code_location
Definition: vm_core.h:272
struct rb_iseq_constant_body * body
Definition: vm_core.h:448
struct rb_hook_list_struct * local_hooks
Definition: vm_core.h:459
VALUE wrapper
Definition: vm_core.h:446
struct rb_iseq_struct::@191::@193 exec
union rb_iseq_struct::@191 aux
rb_event_flag_t global_trace_events
Definition: vm_core.h:460
struct rb_iseq_struct::@191::@192 loader
uint32_t index
Definition: class.h:29
VALUE class_value
Definition: class.h:31
Definition: st.h:79
unsigned int target_line
Definition: iseq.c:3253
rb_event_flag_t turnon_events
Definition: iseq.c:3251
#define snprintf
Definition: subst.h:14
Definition: vm_core.h:239
struct iseq_inline_storage_entry::@187 once
VALUE value
Definition: vm_core.h:242
unsigned long VALUE
Definition: value.h:38
#define SIGNED_VALUE
Definition: value.h:40
unsigned long ID
Definition: value.h:39
#define T_FILE
Definition: value_type.h:61
#define T_STRING
Definition: value_type.h:77
#define T_NONE
Definition: value_type.h:73
#define T_HASH
Definition: value_type.h:64
#define T_ARRAY
Definition: value_type.h:55
#define BUILTIN_TYPE
Definition: value_type.h:84
ruby_value_type
C-level type of an object.
Definition: value_type.h:110
VALUE rb_iseq_eval(const rb_iseq_t *iseq)
Definition: vm.c:2403
VALUE rb_cRubyVM
Definition: vm.c:373
const struct rb_callcache * rb_vm_empty_cc(void)
Definition: vm.c:4100
rb_event_flag_t ruby_vm_event_enabled_global_flags
Definition: vm.c:404
#define rb_id2str(id)
Definition: vm_backtrace.c:30
#define VM_CALL_KWARG
Definition: vm_callinfo.h:37
#define VM_ENV_DATA_SIZE
Definition: vm_core.h:1206
#define VM_ASSERT(expr)
Definition: vm_core.h:61
void rb_hook_list_free(rb_hook_list_t *hooks)
Definition: vm_trace.c:69
#define RUBY_EVENT_COVERAGE_LINE
Definition: vm_core.h:2022
struct iseq_inline_constant_cache * IC
Definition: vm_core.h:1144
void rb_hook_list_mark(rb_hook_list_t *hooks)
Definition: vm_trace.c:56
#define RUBY_EVENT_COVERAGE_BRANCH
Definition: vm_core.h:2023
void rb_hook_list_remove_tracepoint(rb_hook_list_t *list, VALUE tpval)
Definition: vm_trace.c:1268
struct iseq_inline_iv_cache_entry * IVC
Definition: vm_core.h:1145
void rb_hook_list_connect_tracepoint(VALUE target, rb_hook_list_t *list, VALUE tpval, unsigned int target_line)
Definition: vm_trace.c:1258
#define OPT_PEEPHOLE_OPTIMIZATION
Definition: vm_opts.h:19
#define OPT_TAILCALL_OPTIMIZATION
Definition: vm_opts.h:18
#define OPT_OPERANDS_UNIFICATION
Definition: vm_opts.h:55
#define OPT_INLINE_CONST_CACHE
Definition: vm_opts.h:21
#define OPT_DEBUG_FROZEN_STRING_LITERAL
Definition: vm_opts.h:23
#define OPT_INSTRUCTIONS_UNIFICATION
Definition: vm_opts.h:56
#define OPT_FROZEN_STRING_LITERAL
Definition: vm_opts.h:22
#define OPT_STACK_CACHING
Definition: vm_opts.h:58
#define OPT_SPECIALISED_INSTRUCTION
Definition: vm_opts.h:20
int err
Definition: win32.c:142
if((ID)(DISPID) nameid !=nameid)
Definition: win32ole.c:357
#define ZALLOC(strm, items, size)
Definition: zutil.h:266