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