Ruby 4.1.0dev (2026-10-28 revision 1b06b950bb460d20a9dcecb8b97d363adbf4a358)
iseq.c (1b06b950bb460d20a9dcecb8b97d363adbf4a358)
1/**********************************************************************
2
3 iseq.c -
4
5 $Author$
6 created at: 2006-07-11(Tue) 09:00:03 +0900
7
8 Copyright (C) 2006 Koichi Sasada
9
10**********************************************************************/
11
12#define RUBY_VM_INSNS_INFO 1
13/* #define RUBY_MARK_FREE_DEBUG 1 */
14
15#include "ruby/internal/config.h"
16
17#ifdef HAVE_DLADDR
18# include <dlfcn.h>
19#endif
20
21#include "eval_intern.h"
22#include "id.h"
23#include "id_table.h"
24#include "internal.h"
25#include "internal/bits.h"
26#include "internal/class.h"
27#include "internal/compile.h"
28#include "internal/coverage.h"
29#include "internal/error.h"
30#include "internal/file.h"
31#include "internal/gc.h"
32#include "internal/hash.h"
33#include "internal/io.h"
34#include "internal/ruby_parser.h"
35#include "internal/sanitizers.h"
36#include "internal/set_table.h"
37#include "internal/symbol.h"
38#include "internal/thread.h"
39#include "internal/variable.h"
40#include "iseq.h"
41#include "prism_compile.h"
42#include "ruby/util.h"
43#include "vm_core.h"
44#include "vm_sync.h"
45#include "ractor_core.h"
46#include "vm_callinfo.h"
47#include "yjit.h"
48#include "ruby/ractor.h"
49#include "builtin.h"
50#include "insns.inc"
51#include "insns_info.inc"
52#include "zjit.h"
53
54VALUE rb_cISeq;
55static VALUE iseqw_new(const rb_iseq_t *iseq);
56static const rb_iseq_t *iseqw_check(VALUE iseqw);
57
58#if VM_INSN_INFO_TABLE_IMPL == 2
59static struct succ_index_table *succ_index_table_create(int max_pos, int *data, int size);
60static unsigned int *succ_index_table_invert(int max_pos, struct succ_index_table *sd, int size);
61static int succ_index_lookup(const struct succ_index_table *sd, int x);
62#endif
63
64#define hidden_obj_p(obj) (!SPECIAL_CONST_P(obj) && !RBASIC(obj)->klass)
65
66static inline VALUE
67obj_resurrect(VALUE obj)
68{
69 if (hidden_obj_p(obj)) {
70 switch (BUILTIN_TYPE(obj)) {
71 case T_STRING:
72 obj = rb_str_resurrect(obj);
73 break;
74 case T_ARRAY:
75 obj = rb_ary_resurrect(obj);
76 break;
77 case T_HASH:
78 obj = rb_hash_resurrect(obj);
79 break;
80 default:
81 break;
82 }
83 }
84 return obj;
85}
86
87static void
88free_arena(struct iseq_compile_data_storage *cur)
89{
90 struct iseq_compile_data_storage *next;
91
92 while (cur) {
93 next = cur->next;
94 ruby_xfree_sized(cur, offsetof(struct iseq_compile_data_storage, buff) + cur->size * sizeof(char));
95 cur = next;
96 }
97}
98
99static void
100compile_data_free(struct iseq_compile_data *compile_data)
101{
102 if (compile_data) {
103 free_arena(compile_data->node.storage_head);
104 free_arena(compile_data->insn.storage_head);
105 if (compile_data->ivar_cache_table) {
106 rb_id_table_free(compile_data->ivar_cache_table);
107 }
108 SIZED_FREE(compile_data);
109 }
110}
111
112static void
113remove_from_constant_cache(ID id, IC ic)
114{
115 rb_vm_t *vm = GET_VM();
116 VALUE lookup_result;
117 st_data_t ic_data = (st_data_t)ic;
118
119 if (rb_id_table_lookup(&vm->constant_cache, id, &lookup_result)) {
120 set_table *ics = (set_table *)lookup_result;
121 set_table_delete(ics, &ic_data);
122
123 if (ics->num_entries == 0 &&
124 // See comment in vm_track_constant_cache on why we need this check
125 id != vm->inserting_constant_cache_id) {
126 rb_id_table_delete(&vm->constant_cache, id);
127 set_free_table(ics);
128 }
129 }
130}
131
132// When an ISEQ is being freed, all of its associated ICs are going to go away
133// as well. Because of this, we need to iterate over the ICs, and clear them
134// from the VM's constant cache.
135static void
136iseq_clear_ic_references(const rb_iseq_t *iseq)
137{
138 // In some cases (when there is a compilation error), we end up with
139 // ic_size greater than 0, but no allocated is_entries buffer.
140 // If there's no is_entries buffer to loop through, return early.
141 // [Bug #19173]
142 if (!ISEQ_BODY(iseq)->is_entries) {
143 return;
144 }
145
146 for (unsigned int ic_idx = 0; ic_idx < ISEQ_BODY(iseq)->ic_size; ic_idx++) {
147 IC ic = &ISEQ_IS_IC_ENTRY(ISEQ_BODY(iseq), ic_idx);
148
149 // Iterate over the IC's constant path's segments and clean any references to
150 // the ICs out of the VM's constant cache table.
151 const ID *segments = ic->segments;
152
153 // It's possible that segments is NULL if we overallocated an IC but
154 // optimizations removed the instruction using it
155 if (segments == NULL)
156 continue;
157
158 int i;
159 for (i = 0; segments[i]; i++) {
160 ID id = segments[i];
161 if (id == idNULL) continue;
162 remove_from_constant_cache(id, ic);
163 }
164
165 SIZED_FREE_N(segments, i + 1);
166 }
167}
168
169
171rb_iseq_local_hooks(const rb_iseq_t *iseq, rb_ractor_t *r, bool create)
172{
173 rb_hook_list_t *hook_list = NULL;
174 st_data_t val;
175 if (st_lookup(rb_ractor_targeted_hooks(r), (st_data_t)iseq, &val)) {
176 hook_list = (rb_hook_list_t*)val;
177 RUBY_ASSERT(hook_list->type == hook_list_type_targeted_iseq);
178 }
179 else if (create) {
180 hook_list = RB_ZALLOC(rb_hook_list_t);
181 hook_list->type = hook_list_type_targeted_iseq;
182 st_insert(rb_ractor_targeted_hooks(r), (st_data_t)iseq, (st_data_t)hook_list);
183 }
184 return hook_list;
185}
186
187void
188rb_iseq_free(const rb_iseq_t *iseq)
189{
190 RUBY_FREE_ENTER("iseq");
191
192 if (iseq && ISEQ_BODY(iseq)) {
193 iseq_clear_ic_references(iseq);
194 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
195#if USE_YJIT
196 if (rb_yjit_enabled_p) rb_yjit_iseq_free(iseq);
197 if (FL_TEST_RAW((VALUE)iseq, ISEQ_TRANSLATED)) {
198 RUBY_ASSERT(rb_yjit_live_iseq_count > 0);
199 rb_yjit_live_iseq_count--;
200 }
201#endif
202#if USE_ZJIT
203 if (rb_zjit_enabled_p) rb_zjit_iseq_free(iseq);
204#endif
205 SIZED_FREE_N(body->iseq_encoded, body->iseq_size);
206 SIZED_FREE_N(body->insns_info.body, body->insns_info.size);
207#ifdef USE_ISEQ_NODE_ID
208 SIZED_FREE_N(body->insns_info.node_ids, body->insns_info.node_ids_size);
209#endif
210#if VM_INSN_INFO_TABLE_IMPL == 2
211 ruby_xfree(body->insns_info.positions_or_succ_index_table.succ_index_table);
212#else
213 SIZED_FREE_N(body->insns_info.positions_or_succ_index_table.positions, body->insns_info.size);
214#endif
215 SIZED_FREE_N(body->is_entries, ISEQ_IS_SIZE(body));
216 SIZED_FREE_N(body->call_data, body->ci_size);
217 if (body->catch_table) {
218 ruby_xfree_sized(body->catch_table, iseq_catch_table_bytes(body->catch_table->size));
219 }
220 SIZED_FREE_N(body->param.opt_table, body->param.opt_num + 1);
221 if (ISEQ_MBITS_BUFLEN(body->iseq_size) > 1 && body->mark_bits.list) {
222 SIZED_FREE_N(body->mark_bits.list, ISEQ_MBITS_BUFLEN(body->iseq_size));
223 }
224
225 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
226 if (body->variable) xfree(body->variable);
227
228 struct rb_iseq_param_keyword *pkw = (struct rb_iseq_param_keyword *)body->param.keyword;
229 if (pkw != NULL) {
230 if (pkw->table != &body->local_table[pkw->bits_start - pkw->num])
231 SIZED_FREE_N(pkw->table, pkw->required_num);
232 if (pkw->default_values) {
233 SIZED_FREE_N(pkw->default_values, pkw->num - pkw->required_num);
234 }
235 SIZED_FREE(pkw);
236 }
237 if (LIKELY(body->local_table != rb_iseq_shared_exc_local_tbl)) {
238 SIZED_FREE_N(body->local_table, body->local_table_size);
239 }
240 if (!ISEQ_LVAR_STATES_EMBED_P(body->local_table_size)) {
241 SIZED_FREE_N(body->lvar_states.list, ISEQ_LVAR_STATES_BUFLEN(body->local_table_size));
242 }
243
244 compile_data_free(ISEQ_COMPILE_DATA(iseq));
245 if (body->outer_variables) rb_id_table_free(body->outer_variables);
246 SIZED_FREE(body);
247 }
248
249 RUBY_FREE_LEAVE("iseq");
250}
251
252/* CAS-publish the out-of-lined variable struct: concurrent callers (e.g. two
253 * dumpers hitting rb_iseq_original_iseq on a shared iseq) can each build a
254 * copy, mirroring the original_iseq CAS in compile.c. */
255struct rb_iseq_variable *
256rb_iseq_variable_ensure(rb_iseq_t *iseq)
257{
258 struct rb_iseq_variable *v = ISEQ_VARIABLE(iseq);
259 if (v) return v;
260 v = ALLOC(struct rb_iseq_variable);
261 v->flip_count = 0;
262 v->script_lines = Qnil;
263 v->coverage = Qfalse;
264 v->pc2branchindex = Qfalse;
265 v->original_iseq = NULL;
266 struct rb_iseq_variable *prev = ATOMIC_PTR_CAS(ISEQ_BODY(iseq)->variable, NULL, v);
267 if (prev) {
268 xfree(v);
269 v = prev;
270 }
271 return v;
272}
273
274void
275rb_iseq_coverage_set(rb_iseq_t *iseq, VALUE cov)
276{
277 if (!RTEST(cov) && !ISEQ_VARIABLE(iseq)) return;
278 struct rb_iseq_variable *v = rb_iseq_variable_ensure(iseq);
279 RB_OBJ_WRITE(iseq, &v->coverage, cov);
280}
281
282void
283rb_iseq_pc2branchindex_set(rb_iseq_t *iseq, VALUE h)
284{
285 if (!RTEST(h) && !ISEQ_VARIABLE(iseq)) return;
286 struct rb_iseq_variable *v = rb_iseq_variable_ensure(iseq);
287 RB_OBJ_WRITE(iseq, &v->pc2branchindex, h);
288}
289
290rb_snum_t
291rb_iseq_flip_cnt_increment(const rb_iseq_t *iseq)
292{
293 struct rb_iseq_variable *v = rb_iseq_variable_ensure((rb_iseq_t *)iseq);
294 rb_snum_t cnt = v->flip_count;
295 v->flip_count += 1;
296 return cnt;
297}
298
299typedef VALUE iseq_value_itr_t(void *ctx, VALUE obj);
300
301static inline void
302iseq_scan_bits(const struct rb_gc_mark_ctx *ctx, unsigned int page, iseq_bits_t bits, VALUE *code, VALUE *original_iseq)
303{
304 unsigned int offset;
305 unsigned int page_offset = (page * ISEQ_MBITS_BITLENGTH);
306
307 while (bits) {
308 offset = ntz_intptr(bits);
309 if (original_iseq) {
310 VALUE op = original_iseq[page_offset + offset];
311 rb_gc_mark_and_move_ctx(ctx, &code[page_offset + offset]);
312 VALUE newop = code[page_offset + offset];
313 if (op != newop) {
314 original_iseq[page_offset + offset] = newop;
315 }
316 }
317 else {
318 rb_gc_mark_and_move_ctx(ctx, &code[page_offset + offset]);
319 }
320 bits &= bits - 1; // Reset Lowest Set Bit (BLSR)
321 }
322}
323
324static void
325rb_iseq_mark_and_move_each_compile_data_value(const struct rb_gc_mark_ctx *ctx, const rb_iseq_t *iseq, VALUE *original_iseq)
326{
327 unsigned int size;
328 VALUE *code;
329 const struct iseq_compile_data *const compile_data = ISEQ_COMPILE_DATA(iseq);
330
331 size = compile_data->iseq_size;
332 code = compile_data->iseq_encoded;
333
334 // Embedded VALUEs
335 if (compile_data->mark_bits.list) {
336 if(compile_data->is_single_mark_bit) {
337 iseq_scan_bits(ctx, 0, compile_data->mark_bits.single, code, original_iseq);
338 }
339 else {
340 for (unsigned int i = 0; i < ISEQ_MBITS_BUFLEN(size); i++) {
341 iseq_bits_t bits = compile_data->mark_bits.list[i];
342 iseq_scan_bits(ctx, i, bits, code, original_iseq);
343 }
344 }
345 }
346}
347static void
348rb_iseq_mark_and_move_each_body_value(const struct rb_gc_mark_ctx *ctx, const rb_iseq_t *iseq, VALUE *original_iseq)
349{
350 unsigned int size;
351 VALUE *code;
352 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
353
354 size = body->iseq_size;
355 code = body->iseq_encoded;
356
357 union iseq_inline_storage_entry *is_entries = body->is_entries;
358
359 if (body->is_entries) {
360 // Skip iterating over ivc caches
361 is_entries += body->ivc_size;
362
363 // ICVARC entries
364 for (unsigned int i = 0; i < body->icvarc_size; i++, is_entries++) {
365 ICVARC icvarc = (ICVARC)is_entries;
366 if (icvarc->entry) {
367 rb_gc_mark_and_move_ctx(ctx, (VALUE *)&icvarc->entry);
368 }
369 }
370
371 // ISE entries
372 for (unsigned int i = 0; i < body->ise_size; i++, is_entries++) {
373 union iseq_inline_storage_entry *const is = (union iseq_inline_storage_entry *)is_entries;
374 if (is->once.value) {
375 rb_gc_mark_and_move_ctx(ctx, &is->once.value);
376 }
377 }
378
379 // IC Entries
380 for (unsigned int i = 0; i < body->ic_size; i++, is_entries++) {
381 IC ic = (IC)is_entries;
382 if (ic->entry) {
383 rb_gc_mark_and_move_ptr_ctx(ctx, &ic->entry);
384 }
385 }
386 }
387
388 // Embedded VALUEs
389 if (body->mark_bits.list) {
390 if (ISEQ_MBITS_BUFLEN(size) == 1) {
391 iseq_scan_bits(ctx, 0, body->mark_bits.single, code, original_iseq);
392 }
393 else {
394 for (unsigned int i = 0; i < ISEQ_MBITS_BUFLEN(size); i++) {
395 iseq_bits_t bits = body->mark_bits.list[i];
396 iseq_scan_bits(ctx, i, bits, code, original_iseq);
397 }
398 }
399 }
400}
401
402static bool
403cc_is_active(const struct rb_callcache *cc)
404{
405 RUBY_ASSERT(cc);
406 RUBY_ASSERT(vm_cc_markable(cc));
407
408 return vm_cc_valid(cc) && !METHOD_ENTRY_INVALIDATED(vm_cc_cme(cc));
409}
410
411void
412rb_iseq_mark_and_move(const struct rb_gc_mark_ctx *ctx, rb_iseq_t *iseq, bool reference_updating)
413{
414 RUBY_MARK_ENTER("iseq");
415
416 if (ISEQ_BODY(iseq)) {
417 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
418
419 rb_iseq_mark_and_move_each_body_value(ctx, iseq, reference_updating ? ISEQ_ORIGINAL_ISEQ(iseq) : NULL);
420
421 struct rb_iseq_variable *v = ISEQ_VARIABLE(iseq);
422 if (v) rb_gc_mark_and_move_ctx(ctx, &v->script_lines);
423 rb_gc_mark_and_move_ctx(ctx, &body->location.label);
424 rb_gc_mark_and_move_ctx(ctx, &body->location.pathobj);
425 if (body->local_iseq) rb_gc_mark_and_move_ptr_ctx(ctx, &body->local_iseq);
426 if (body->parent_iseq) rb_gc_mark_and_move_ptr_ctx(ctx, &body->parent_iseq);
427 if (body->mandatory_only_iseq) rb_gc_mark_and_move_ptr_ctx(ctx, &body->mandatory_only_iseq);
428
429 if (body->call_data) {
430 struct rb_call_data *cds = body->call_data;
431 for (unsigned int i = 0; i < body->ci_size; i++) {
432
433 if (cds[i].ci) rb_gc_mark_and_move_ptr_ctx(ctx, &cds[i].ci);
434
435 const struct rb_callcache *cc = cds[i].cc;
436 if (!cc || cc == &rb_vm_empty_cc || cc == &rb_vm_empty_cc_for_super ||
437 cc == &rb_vm_uncached_cc) {
438 // No need for marking, reference updating, or clearing
439 // We also want to avoid reassigning to improve CoW
440 continue;
441 }
442
443 if (reference_updating) {
444 rb_gc_update_moved_ptr_ctx(ctx, &cds[i].cc);
445 }
446 else {
447 if (cc_is_active(cc)) {
448 rb_gc_mark_movable_ctx(ctx, (VALUE)cc);
449 }
450 else {
451 // Either the CC or CME has been invalidated. Replace
452 // it with the empty CC so that it can be GC'd.
453 cds[i].cc = &rb_vm_empty_cc;
454 }
455 }
456 }
457 }
458
459 if (body->param.flags.has_kw && body->param.keyword != NULL) {
460 const struct rb_iseq_param_keyword *const keyword = body->param.keyword;
461
462 if (keyword->default_values != NULL) {
463 for (int j = 0, i = keyword->required_num; i < keyword->num; i++, j++) {
464 rb_gc_mark_and_move_ctx(ctx, &keyword->default_values[j]);
465 }
466 }
467 }
468
469 if (body->catch_table) {
470 struct iseq_catch_table *table = body->catch_table;
471
472 for (unsigned int i = 0; i < table->size; i++) {
473 struct iseq_catch_table_entry *entry;
474 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
475 if (entry->iseq) {
476 rb_gc_mark_and_move_ptr_ctx(ctx, &entry->iseq);
477 }
478 }
479 }
480
481#if USE_YJIT || USE_ZJIT
482 /* The JIT payload's critical section is the VM lock (racing other Ractors'
483 * compile/invalidate). Iseqs are born shareable, so a multi-Ractor local GC
484 * never traverses them. */
485 const bool jit_payload_lock_p = rb_gc_multi_objspace_p();
486 bool jit_payload_p = body->jit_payload != NULL;
487#endif
488 if (reference_updating) {
489#if USE_YJIT || USE_ZJIT
490 if (jit_payload_p) {
491 if (jit_payload_lock_p) {
492 RB_VM_LOCKING_NO_BARRIER() {
493# if USE_YJIT
494 if (rb_yjit_enabled_p) rb_yjit_iseq_update_references(iseq);
495# endif
496# if USE_ZJIT
497 if (rb_zjit_enabled_p) rb_zjit_iseq_update_references(body->jit_payload);
498# endif
499 }
500 }
501 else {
502# if USE_YJIT
503 if (rb_yjit_enabled_p) rb_yjit_iseq_update_references(iseq);
504# endif
505# if USE_ZJIT
506 if (rb_zjit_enabled_p) rb_zjit_iseq_update_references(body->jit_payload);
507# endif
508 }
509 }
510#endif
511 }
512 else {
513 // TODO: check jit payload
514 if (!rb_gc_checking_shareable_ctx(ctx)) {
515#if USE_YJIT || USE_ZJIT
516 if (jit_payload_p) {
517 if (jit_payload_lock_p) {
518 RB_VM_LOCKING_NO_BARRIER() {
519# if USE_YJIT
520 if (rb_yjit_enabled_p) rb_yjit_iseq_mark(body->jit_payload);
521# endif
522# if USE_ZJIT
523 if (rb_zjit_enabled_p) rb_zjit_iseq_mark(body->jit_payload);
524# endif
525 }
526 }
527 else {
528# if USE_YJIT
529 if (rb_yjit_enabled_p) rb_yjit_iseq_mark(body->jit_payload);
530# endif
531# if USE_ZJIT
532 if (rb_zjit_enabled_p) rb_zjit_iseq_mark(body->jit_payload);
533# endif
534 }
535 }
536#endif
537 }
538 }
539
540 // TODO: ractor aware coverage
541 if (!rb_gc_checking_shareable_ctx(ctx)) {
542 if (v) {
543 rb_gc_mark_and_move_ctx(ctx, &v->coverage);
544 rb_gc_mark_and_move_ctx(ctx, &v->pc2branchindex);
545 }
546 }
547 }
548
549 if (FL_TEST_RAW((VALUE)iseq, ISEQ_NOT_LOADED_YET)) {
550 if (!rb_gc_checking_shareable_ctx(ctx)) {
551 rb_gc_mark_and_move_ctx(ctx, &iseq->aux.loader.obj);
552 }
553 }
554 else if (FL_TEST_RAW((VALUE)iseq, ISEQ_USE_COMPILE_DATA)) {
555 if (!rb_gc_checking_shareable_ctx(ctx)) {
556 const struct iseq_compile_data *const compile_data = ISEQ_COMPILE_DATA(iseq);
557
558 rb_iseq_mark_and_move_insn_storage(compile_data->insn.storage_head);
559 rb_iseq_mark_and_move_each_compile_data_value(ctx, iseq, reference_updating ? ISEQ_ORIGINAL_ISEQ(iseq) : NULL);
560
561 rb_gc_mark_and_move_ctx(ctx, (VALUE *)&compile_data->err_info);
562 rb_gc_mark_and_move_ctx(ctx, (VALUE *)&compile_data->catch_table_ary);
563 }
564 }
565 else {
566 /* executable */
567 VM_ASSERT(ISEQ_EXECUTABLE_P(iseq));
568 }
569
570 RUBY_MARK_LEAVE("iseq");
571}
572
573static size_t
574param_keyword_size(const struct rb_iseq_param_keyword *pkw)
575{
576 size_t size = 0;
577
578 if (!pkw) return size;
579
580 size += sizeof(struct rb_iseq_param_keyword);
581 size += sizeof(VALUE) * (pkw->num - pkw->required_num);
582
583 return size;
584}
585
586size_t
587rb_iseq_memsize(const rb_iseq_t *iseq)
588{
589 size_t size = 0; /* struct already counted as RVALUE size */
590 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
591 const struct iseq_compile_data *compile_data;
592
593 /* TODO: should we count original_iseq? */
594
595 if (ISEQ_EXECUTABLE_P(iseq) && body) {
596 size += sizeof(struct rb_iseq_constant_body);
597 if (body->variable) size += sizeof(struct rb_iseq_variable);
598 size += body->iseq_size * sizeof(VALUE);
599 size += body->insns_info.size * (sizeof(struct iseq_insn_info_entry) + sizeof(unsigned int));
600#ifdef USE_ISEQ_NODE_ID
601 size += body->insns_info.node_ids_size;
602#endif
603 size += body->local_table_size * sizeof(ID); // body->local_table
604 if (!ISEQ_LVAR_STATES_EMBED_P(body->local_table_size) && body->lvar_states.list) {
605 size += ISEQ_LVAR_STATES_BUFLEN(body->local_table_size) * sizeof(uint8_t);
606 }
607 size += ISEQ_MBITS_BUFLEN(body->iseq_size) * ISEQ_MBITS_SIZE;
608 if (body->catch_table) {
609 size += iseq_catch_table_bytes(body->catch_table->size);
610 }
611 size += (body->param.opt_num + 1) * sizeof(VALUE);
612 size += param_keyword_size(body->param.keyword);
613
614 if (body->outer_variables) size += rb_id_table_memsize(body->outer_variables);
615
616 /* body->is_entries */
617 size += ISEQ_IS_SIZE(body) * sizeof(union iseq_inline_storage_entry);
618
619 if (ISEQ_BODY(iseq)->is_entries) {
620 /* IC entries constant segments */
621 for (unsigned int ic_idx = 0; ic_idx < body->ic_size; ic_idx++) {
622 IC ic = &ISEQ_IS_IC_ENTRY(body, ic_idx);
623 const ID *ids = ic->segments;
624 if (!ids) continue;
625 while (*ids++) {
626 size += sizeof(ID);
627 }
628 size += sizeof(ID); // null terminator
629 }
630 }
631
632 /* body->call_data */
633 size += body->ci_size * sizeof(struct rb_call_data);
634 // TODO: should we count imemo_callinfo?
635 }
636
637 compile_data = ISEQ_COMPILE_DATA(iseq);
638 if (compile_data) {
639 struct iseq_compile_data_storage *cur;
640
641 size += sizeof(struct iseq_compile_data);
642
643 cur = compile_data->node.storage_head;
644 while (cur) {
645 size += cur->size + offsetof(struct iseq_compile_data_storage, buff);
646 cur = cur->next;
647 }
648 }
649
650 return size;
651}
652
654rb_iseq_constant_body_alloc(void)
655{
656 struct rb_iseq_constant_body *iseq_body;
657 iseq_body = ZALLOC(struct rb_iseq_constant_body);
658 return iseq_body;
659}
660
661static rb_iseq_t *
662iseq_alloc(void)
663{
664 rb_iseq_t *iseq = iseq_imemo_alloc();
665 ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
666 return iseq;
667}
668
669VALUE
670rb_iseq_pathobj_new(VALUE path, VALUE realpath, bool *no_realpath)
671{
672 VALUE pathobj;
673 VM_ASSERT(RB_TYPE_P(path, T_STRING));
674 VM_ASSERT(NIL_P(realpath) || RB_TYPE_P(realpath, T_STRING));
675
676 *no_realpath = NIL_P(realpath);
677
678 if (*no_realpath || path == realpath || rb_str_cmp(path, realpath) == 0) {
679 pathobj = rb_fstring(path);
680 }
681 else {
682 realpath = rb_fstring(realpath);
683 VALUE fpath = rb_fstring(path);
684
685 pathobj = rb_ary_new_from_args(2, fpath, realpath);
686 rb_ary_freeze(pathobj);
687 RB_OBJ_SET_SHAREABLE(pathobj);
688 }
689 return pathobj;
690}
691
692void
693rb_iseq_pathobj_set(const rb_iseq_t *iseq, VALUE path, VALUE realpath)
694{
695 bool no_realpath;
696 VALUE pathobj = rb_iseq_pathobj_new(path, realpath, &no_realpath);
697 RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->location.pathobj, pathobj);
698 ISEQ_BODY(iseq)->no_realpath = no_realpath;
699}
700
701// Make a dummy iseq for a dummy frame that exposes a path for profilers to inspect
702rb_iseq_t *
703rb_iseq_alloc_with_dummy_path(VALUE fname)
704{
705 rb_iseq_t *dummy_iseq = iseq_alloc();
706
707 ISEQ_BODY(dummy_iseq)->type = ISEQ_TYPE_TOP;
708
709 if (!RB_OBJ_SHAREABLE_P(fname)) {
711 }
712
713 RB_OBJ_WRITE(dummy_iseq, &ISEQ_BODY(dummy_iseq)->location.pathobj, fname);
714 RB_OBJ_WRITE(dummy_iseq, &ISEQ_BODY(dummy_iseq)->location.label, fname);
715
716 return dummy_iseq;
717}
718
719static rb_iseq_location_t *
720iseq_location_setup(rb_iseq_t *iseq, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_code_location_t *code_location, const int node_id)
721{
722 rb_iseq_location_t *loc = &ISEQ_BODY(iseq)->location;
723
724 rb_iseq_pathobj_set(iseq, path, realpath);
725 RB_OBJ_WRITE(iseq, &loc->label, name);
726 loc->first_lineno = first_lineno;
727
728 if (ISEQ_BODY(iseq)->local_iseq == iseq && rb_streql_lit(name, "initialize")) {
729 ISEQ_BODY(iseq)->param.flags.use_block = 1;
730 }
731
732 if (code_location) {
733 loc->node_id = node_id;
734 loc->code_location = *code_location;
735 }
736 else {
737 loc->code_location.beg_pos.lineno = 0;
738 loc->code_location.beg_pos.column = 0;
739 loc->code_location.end_pos.lineno = -1;
740 loc->code_location.end_pos.column = -1;
741 }
742
743 return loc;
744}
745
746static void
747set_relation(rb_iseq_t *iseq, const rb_iseq_t *piseq)
748{
749 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
750 const VALUE type = body->type;
751
752 /* set class nest stack */
753 if (type == ISEQ_TYPE_TOP) {
754 body->local_iseq = iseq;
755 }
756 else if (type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) {
757 body->local_iseq = iseq;
758 }
759 else if (piseq) {
760 RB_OBJ_WRITE(iseq, &body->local_iseq, ISEQ_BODY(piseq)->local_iseq);
761 }
762
763 if (piseq) {
764 RB_OBJ_WRITE(iseq, &body->parent_iseq, piseq);
765 }
766
767 if (type == ISEQ_TYPE_MAIN) {
768 body->local_iseq = iseq;
769 }
770}
771
772static struct iseq_compile_data_storage *
773new_arena(void)
774{
775 struct iseq_compile_data_storage * new_arena =
777 ALLOC_N(char, INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE +
778 offsetof(struct iseq_compile_data_storage, buff));
779
780 new_arena->pos = 0;
781 new_arena->next = 0;
782 new_arena->size = INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE;
783
784 return new_arena;
785}
786
787static int
788prepare_node_id(const NODE *node)
789{
790 if (!node) return -1;
791
792 if (nd_type(node) == NODE_SCOPE && RNODE_SCOPE(node)->nd_parent) {
793 return nd_node_id(RNODE_SCOPE(node)->nd_parent);
794 }
795
796 return nd_node_id(node);
797}
798
799static VALUE
800prepare_iseq_build(rb_iseq_t *iseq,
801 VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_code_location_t *code_location, const int node_id,
802 const rb_iseq_t *parent, int isolated_depth, enum rb_iseq_type type,
803 VALUE script_lines, const rb_compile_option_t *option)
804{
805 VALUE coverage = Qfalse;
806 VALUE err_info = Qnil;
807 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
808
809 if (parent && (type == ISEQ_TYPE_MAIN || type == ISEQ_TYPE_TOP))
810 err_info = Qfalse;
811
812 body->type = type;
813 set_relation(iseq, parent);
814
815 name = rb_fstring(name);
816 iseq_location_setup(iseq, name, path, realpath, first_lineno, code_location, node_id);
817 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
818 if (body->variable) {
819 body->variable->flip_count = 0;
820 RB_OBJ_WRITE(iseq, &body->variable->script_lines, Qnil);
821 RB_OBJ_WRITE(iseq, &body->variable->coverage, Qnil);
822 }
823
824 if (!NIL_P(script_lines)) {
825 struct rb_iseq_variable *v = rb_iseq_variable_ensure(iseq);
826 RB_OBJ_WRITE(iseq, &v->script_lines, rb_ractor_make_shareable(script_lines));
827 }
828
829 ISEQ_COMPILE_DATA_ALLOC(iseq);
830 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err_info);
831 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, Qnil);
832
833 ISEQ_COMPILE_DATA(iseq)->node.storage_head = ISEQ_COMPILE_DATA(iseq)->node.storage_current = new_arena();
834 ISEQ_COMPILE_DATA(iseq)->insn.storage_head = ISEQ_COMPILE_DATA(iseq)->insn.storage_current = new_arena();
835 ISEQ_COMPILE_DATA(iseq)->isolated_depth = isolated_depth;
836 ISEQ_COMPILE_DATA(iseq)->option = option;
837 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = NULL;
838 ISEQ_COMPILE_DATA(iseq)->builtin_function_table = GET_VM()->builtin_function_table;
839
840 if (option->coverage_enabled) {
841 VALUE coverages = rb_get_coverages();
842 if (RTEST(coverages)) {
843 coverage = rb_hash_lookup(coverages, rb_iseq_path(iseq));
844 if (NIL_P(coverage)) coverage = Qfalse;
845 }
846 }
847 ISEQ_COVERAGE_SET(iseq, coverage);
848 if (coverage && ISEQ_BRANCH_COVERAGE(iseq))
849 ISEQ_PC2BRANCHINDEX_SET(iseq, rb_ary_hidden_new(0));
850
851 return Qtrue;
852}
853
854#if VM_CHECK_MODE > 0 && VM_INSN_INFO_TABLE_IMPL > 0
855static void validate_get_insn_info(const rb_iseq_t *iseq);
856#endif
857
858void
859rb_iseq_insns_info_encode_positions(const rb_iseq_t *iseq)
860{
861#if VM_INSN_INFO_TABLE_IMPL == 2
862 /* create succ_index_table */
863 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
864 int size = body->insns_info.size;
865 int max_pos = body->iseq_size;
866 unsigned int *positions = body->insns_info.positions_or_succ_index_table.positions;
867 struct succ_index_table *sd = succ_index_table_create(max_pos, (int *)positions, size);
868 SIZED_FREE_N(positions, size);
869 body->insns_info.positions_or_succ_index_table.succ_index_table = sd;
870#endif
871}
872
873#if VM_INSN_INFO_TABLE_IMPL == 2
874unsigned int *
875rb_iseq_insns_info_decode_positions(const struct rb_iseq_constant_body *body)
876{
877 int size = body->insns_info.size;
878 int max_pos = body->iseq_size;
879 struct succ_index_table *sd = body->insns_info.positions_or_succ_index_table.succ_index_table;
880 return succ_index_table_invert(max_pos, sd, size);
881}
882#endif
883
884void
885rb_iseq_init_trace(rb_iseq_t *iseq)
886{
887 iseq->aux.exec.global_trace_events = 0;
888 if (ruby_vm_event_enabled_global_flags & ISEQ_TRACE_EVENTS) {
889 rb_iseq_trace_set(iseq, ruby_vm_event_enabled_global_flags & ISEQ_TRACE_EVENTS);
890 }
891}
892
893static VALUE
894finish_iseq_build(rb_iseq_t *iseq)
895{
896 struct iseq_compile_data *data = ISEQ_COMPILE_DATA(iseq);
897 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
898 VALUE err = data->err_info;
899 ISEQ_COMPILE_DATA_CLEAR(iseq);
900 compile_data_free(data);
901
902#if VM_CHECK_MODE > 0 && VM_INSN_INFO_TABLE_IMPL > 0
903 validate_get_insn_info(iseq);
904#endif
905
906 if (RTEST(err)) {
907 VALUE path = pathobj_path(body->location.pathobj);
908 if (err == Qtrue) err = rb_exc_new_cstr(rb_eSyntaxError, "compile error");
909 rb_funcallv(err, rb_intern("set_backtrace"), 1, &path);
910 rb_exc_raise(err);
911 }
912
913 RB_DEBUG_COUNTER_INC(iseq_num);
914 RB_DEBUG_COUNTER_ADD(iseq_cd_num, ISEQ_BODY(iseq)->ci_size);
915
916 rb_iseq_init_trace(iseq);
917 return Qtrue;
918}
919
920static rb_compile_option_t COMPILE_OPTION_DEFAULT = {
921 .inline_const_cache = OPT_INLINE_CONST_CACHE,
922 .peephole_optimization = OPT_PEEPHOLE_OPTIMIZATION,
923 .tailcall_optimization = OPT_TAILCALL_OPTIMIZATION,
924 .specialized_instruction = OPT_SPECIALISED_INSTRUCTION,
925 .operands_unification = OPT_OPERANDS_UNIFICATION,
926 .instructions_unification = OPT_INSTRUCTIONS_UNIFICATION,
927 .frozen_string_literal = OPT_FROZEN_STRING_LITERAL,
928 .debug_frozen_string_literal = OPT_DEBUG_FROZEN_STRING_LITERAL,
929 .coverage_enabled = TRUE,
930};
931
932static const rb_compile_option_t COMPILE_OPTION_FALSE = {
933 .frozen_string_literal = -1, // unspecified
934};
935
936int
937rb_iseq_opt_frozen_string_literal(void)
938{
939 return COMPILE_OPTION_DEFAULT.frozen_string_literal;
940}
941
942static void
943set_compile_option_from_hash(rb_compile_option_t *option, VALUE opt)
944{
945#define SET_COMPILE_OPTION(o, h, mem) \
946 { VALUE flag = rb_hash_aref((h), ID2SYM(rb_intern(#mem))); \
947 if (flag == Qtrue) { (o)->mem = 1; } \
948 else if (flag == Qfalse) { (o)->mem = 0; } \
949 }
950#define SET_COMPILE_OPTION_NUM(o, h, mem) \
951 { VALUE num = rb_hash_aref((h), ID2SYM(rb_intern(#mem))); \
952 if (!NIL_P(num)) (o)->mem = NUM2INT(num); \
953 }
954 SET_COMPILE_OPTION(option, opt, inline_const_cache);
955 SET_COMPILE_OPTION(option, opt, peephole_optimization);
956 SET_COMPILE_OPTION(option, opt, tailcall_optimization);
957 SET_COMPILE_OPTION(option, opt, specialized_instruction);
958 SET_COMPILE_OPTION(option, opt, operands_unification);
959 SET_COMPILE_OPTION(option, opt, instructions_unification);
960 SET_COMPILE_OPTION(option, opt, frozen_string_literal);
961 SET_COMPILE_OPTION(option, opt, debug_frozen_string_literal);
962 SET_COMPILE_OPTION(option, opt, coverage_enabled);
963 SET_COMPILE_OPTION_NUM(option, opt, debug_level);
964#undef SET_COMPILE_OPTION
965#undef SET_COMPILE_OPTION_NUM
966}
967
968static rb_compile_option_t *
969set_compile_option_from_ast(rb_compile_option_t *option, const rb_ast_body_t *ast)
970{
971 if (ast->frozen_string_literal >= 0) {
972 option->frozen_string_literal = ast->frozen_string_literal;
973 }
974 return option;
975}
976
977static void
978make_compile_option(rb_compile_option_t *option, VALUE opt)
979{
980 if (NIL_P(opt)) {
981 *option = COMPILE_OPTION_DEFAULT;
982 }
983 else if (opt == Qfalse) {
984 *option = COMPILE_OPTION_FALSE;
985 }
986 else if (opt == Qtrue) {
987 int i;
988 for (i = 0; i < (int)(sizeof(rb_compile_option_t) / sizeof(int)); ++i)
989 ((int *)option)[i] = 1;
990 }
991 else if (RB_TYPE_P(opt, T_HASH)) {
992 *option = COMPILE_OPTION_DEFAULT;
993 set_compile_option_from_hash(option, opt);
994 }
995 else {
996 rb_raise(rb_eTypeError, "Compile option must be Hash/true/false/nil");
997 }
998}
999
1000static VALUE
1001make_compile_option_value(rb_compile_option_t *option)
1002{
1003 VALUE opt = rb_hash_new_capa(11);
1004#define SET_COMPILE_OPTION(o, h, mem) \
1005 rb_hash_aset((h), ID2SYM(rb_intern(#mem)), RBOOL((o)->mem))
1006#define SET_COMPILE_OPTION_NUM(o, h, mem) \
1007 rb_hash_aset((h), ID2SYM(rb_intern(#mem)), INT2NUM((o)->mem))
1008 {
1009 SET_COMPILE_OPTION(option, opt, inline_const_cache);
1010 SET_COMPILE_OPTION(option, opt, peephole_optimization);
1011 SET_COMPILE_OPTION(option, opt, tailcall_optimization);
1012 SET_COMPILE_OPTION(option, opt, specialized_instruction);
1013 SET_COMPILE_OPTION(option, opt, operands_unification);
1014 SET_COMPILE_OPTION(option, opt, instructions_unification);
1015 SET_COMPILE_OPTION(option, opt, debug_frozen_string_literal);
1016 SET_COMPILE_OPTION(option, opt, coverage_enabled);
1017 SET_COMPILE_OPTION_NUM(option, opt, debug_level);
1018 }
1019#undef SET_COMPILE_OPTION
1020#undef SET_COMPILE_OPTION_NUM
1021 VALUE frozen_string_literal = option->frozen_string_literal == -1 ? Qnil : RBOOL(option->frozen_string_literal);
1022 rb_hash_aset(opt, ID2SYM(rb_intern("frozen_string_literal")), frozen_string_literal);
1023 return opt;
1024}
1025
1026rb_iseq_t *
1027rb_iseq_new(const VALUE ast_value, VALUE name, VALUE path, VALUE realpath,
1028 const rb_iseq_t *parent, enum rb_iseq_type type)
1029{
1030 return rb_iseq_new_with_opt(ast_value, name, path, realpath, 0, parent,
1031 0, type, &COMPILE_OPTION_DEFAULT,
1032 Qnil);
1033}
1034
1035static int
1036ast_line_count(const VALUE ast_value)
1037{
1038 rb_ast_t *ast = rb_ruby_ast_data_get(ast_value);
1039 return ast->body.line_count;
1040}
1041
1042static VALUE
1043iseq_setup_coverage(VALUE coverages, VALUE path, int line_count)
1044{
1045 if (line_count >= 0) {
1046 int len = (rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES) ? 0 : line_count;
1047
1048 VALUE coverage = rb_default_coverage(len);
1049 rb_hash_aset(coverages, path, coverage);
1050
1051 return coverage;
1052 }
1053
1054 return Qnil;
1055}
1056
1057static inline void
1058iseq_new_setup_coverage(VALUE path, int line_count)
1059{
1060 VALUE coverages = rb_get_coverages();
1061
1062 if (RTEST(coverages)) {
1063 iseq_setup_coverage(coverages, path, line_count);
1064 }
1065}
1066
1067rb_iseq_t *
1068rb_iseq_new_top(const VALUE ast_value, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent)
1069{
1070 iseq_new_setup_coverage(path, ast_line_count(ast_value));
1071
1072 return rb_iseq_new_with_opt(ast_value, name, path, realpath, 0, parent, 0,
1073 ISEQ_TYPE_TOP, &COMPILE_OPTION_DEFAULT,
1074 Qnil);
1075}
1076
1080rb_iseq_t *
1081pm_iseq_new_top(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent, int *error_state)
1082{
1083 iseq_new_setup_coverage(path, (int) (pm_parser_line_offsets(node->parser)->size - 1));
1084
1085 return pm_iseq_new_with_opt(node, name, path, realpath, 0, parent, 0,
1086 ISEQ_TYPE_TOP, &COMPILE_OPTION_DEFAULT, error_state);
1087}
1088
1089rb_iseq_t *
1090rb_iseq_new_main(const VALUE ast_value, VALUE path, VALUE realpath, const rb_iseq_t *parent, int opt)
1091{
1092 iseq_new_setup_coverage(path, ast_line_count(ast_value));
1093
1094 return rb_iseq_new_with_opt(ast_value, rb_fstring_lit("<main>"),
1095 path, realpath, 0,
1096 parent, 0, ISEQ_TYPE_MAIN, opt ? &COMPILE_OPTION_DEFAULT : &COMPILE_OPTION_FALSE,
1097 Qnil);
1098}
1099
1104rb_iseq_t *
1105pm_iseq_new_main(pm_scope_node_t *node, VALUE path, VALUE realpath, const rb_iseq_t *parent, int opt, int *error_state)
1106{
1107 iseq_new_setup_coverage(path, (int) (pm_parser_line_offsets(node->parser)->size - 1));
1108
1109 return pm_iseq_new_with_opt(node, rb_fstring_lit("<main>"),
1110 path, realpath, 0,
1111 parent, 0, ISEQ_TYPE_MAIN, opt ? &COMPILE_OPTION_DEFAULT : &COMPILE_OPTION_FALSE, error_state);
1112}
1113
1114rb_iseq_t *
1115rb_iseq_new_eval(const VALUE ast_value, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth)
1116{
1117 if (rb_get_coverage_mode() & COVERAGE_TARGET_EVAL) {
1118 VALUE coverages = rb_get_coverages();
1119 if (RTEST(coverages) && RTEST(path) && !RTEST(rb_hash_has_key(coverages, path))) {
1120 iseq_setup_coverage(coverages, path, ast_line_count(ast_value) + first_lineno - 1);
1121 }
1122 }
1123
1124 rb_compile_option_t option = COMPILE_OPTION_DEFAULT;
1125 rb_ast_t *ast = rb_ruby_ast_data_get(ast_value);
1126 if (ast->body.coverage_enabled >= 0) {
1127 option.coverage_enabled = ast->body.coverage_enabled;
1128 }
1129 return rb_iseq_new_with_opt(ast_value, name, path, realpath, first_lineno,
1130 parent, isolated_depth, ISEQ_TYPE_EVAL, &option,
1131 Qnil);
1132}
1133
1134rb_iseq_t *
1135pm_iseq_new_eval(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath,
1136 int first_lineno, const rb_iseq_t *parent, int isolated_depth, int *error_state)
1137{
1138 if (rb_get_coverage_mode() & COVERAGE_TARGET_EVAL) {
1139 VALUE coverages = rb_get_coverages();
1140 if (RTEST(coverages) && RTEST(path) && !RTEST(rb_hash_has_key(coverages, path))) {
1141 iseq_setup_coverage(coverages, path, ((int) (pm_parser_line_offsets(node->parser)->size - 1)) + first_lineno - 1);
1142 }
1143 }
1144
1145 return pm_iseq_new_with_opt(node, name, path, realpath, first_lineno,
1146 parent, isolated_depth, ISEQ_TYPE_EVAL, &COMPILE_OPTION_DEFAULT, error_state);
1147}
1148
1149static inline rb_iseq_t *
1150iseq_translate(rb_iseq_t *iseq)
1151{
1152 if (rb_respond_to(rb_cISeq, rb_intern("translate"))) {
1153 VALUE v1 = iseqw_new(iseq);
1154 VALUE v2 = rb_funcall(rb_cISeq, rb_intern("translate"), 1, v1);
1155 if (v1 != v2 && CLASS_OF(v2) == rb_cISeq) {
1156 iseq = (rb_iseq_t *)iseqw_check(v2);
1157 }
1158 }
1159
1160 return iseq;
1161}
1162
1163rb_iseq_t *
1164rb_iseq_new_with_opt(VALUE ast_value, VALUE name, VALUE path, VALUE realpath,
1165 int first_lineno, const rb_iseq_t *parent, int isolated_depth,
1166 enum rb_iseq_type type, const rb_compile_option_t *option,
1167 VALUE script_lines)
1168{
1169 rb_ast_t *ast = rb_ruby_ast_data_get(ast_value);
1170 rb_ast_body_t *body = ast ? &ast->body : NULL;
1171 const NODE *node = body ? body->root : 0;
1172 /* TODO: argument check */
1173 rb_iseq_t *iseq = iseq_alloc();
1174 rb_compile_option_t new_opt;
1175
1176 if (!option) option = &COMPILE_OPTION_DEFAULT;
1177 if (body) {
1178 new_opt = *option;
1179 option = set_compile_option_from_ast(&new_opt, body);
1180 }
1181
1182 if (!NIL_P(script_lines)) {
1183 // noop
1184 }
1185 else if (body && body->script_lines) {
1186 script_lines = rb_parser_build_script_lines_from(body->script_lines);
1187 }
1188 else if (parent) {
1189 script_lines = ISEQ_SCRIPT_LINES(parent);
1190 }
1191
1192 prepare_iseq_build(iseq, name, path, realpath, first_lineno, node ? &node->nd_loc : NULL, prepare_node_id(node),
1193 parent, isolated_depth, type, script_lines, option);
1194
1195 if (body && body->has_source_hash) {
1196 ISEQ_BODY(iseq)->source_hash = body->source_hash;
1197 RUBY_ASSERT(ISEQ_BODY(iseq)->source_hash != 0);
1198 }
1199
1200 rb_iseq_compile_node(iseq, node);
1201 finish_iseq_build(iseq);
1202 RB_GC_GUARD(ast_value);
1203
1204 return iseq_translate(iseq);
1205}
1206
1212rb_iseq_t *
1213pm_iseq_build(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath,
1214 int first_lineno, const rb_iseq_t *parent, int isolated_depth,
1215 enum rb_iseq_type type, const rb_compile_option_t *option)
1216{
1217 rb_iseq_t *iseq = iseq_alloc();
1218 ISEQ_BODY(iseq)->prism = true;
1219
1220 ISEQ_BODY(iseq)->source_hash = node->source_hash;
1221 RUBY_ASSERT(ISEQ_BODY(iseq)->source_hash != 0);
1222
1223 rb_compile_option_t next_option;
1224 if (!option) option = &COMPILE_OPTION_DEFAULT;
1225
1226 next_option = *option;
1227 next_option.coverage_enabled = node->coverage_enabled < 0 ? 0 : node->coverage_enabled > 0;
1228 option = &next_option;
1229
1230 pm_location_t *location = &node->base.location;
1231 int32_t start_line = pm_parser_start_line(node->parser);
1232 const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(node->parser);
1233
1234 pm_line_column_t start = pm_line_offset_list_line_column(line_offsets, location->start, start_line);
1235 pm_line_column_t end = pm_line_offset_list_line_column(line_offsets, location->start + location->length, start_line);
1236
1237 rb_code_location_t code_location = (rb_code_location_t) {
1238 .beg_pos = { .lineno = (int) start.line, .column = (int) start.column },
1239 .end_pos = { .lineno = (int) end.line, .column = (int) end.column }
1240 };
1241
1242 prepare_iseq_build(iseq, name, path, realpath, first_lineno, &code_location, node->ast_node->node_id,
1243 parent, isolated_depth, type, node->script_lines == NULL ? Qnil : *node->script_lines, option);
1244
1245 pm_iseq_compile_node(iseq, node);
1246 finish_iseq_build(iseq);
1247
1248 return iseq_translate(iseq);
1249}
1250
1252 rb_iseq_t *iseq;
1253 pm_scope_node_t *node;
1254 VALUE name, path, realpath;
1255 int first_lineno, isolated_depth;
1256 const rb_iseq_t *parent;
1257 enum rb_iseq_type type;
1258 const rb_compile_option_t *option;
1259};
1260
1261static VALUE
1262pm_iseq_new_with_opt_try(VALUE d)
1263{
1264 struct pm_iseq_new_with_opt_data *data = (struct pm_iseq_new_with_opt_data *)d;
1265 data->iseq = pm_iseq_build(data->node, data->name, data->path, data->realpath,
1266 data->first_lineno, data->parent, data->isolated_depth,
1267 data->type, data->option);
1268 return Qundef;
1269}
1270
1283rb_iseq_t *
1284pm_iseq_new_with_opt(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath,
1285 int first_lineno, const rb_iseq_t *parent, int isolated_depth,
1286 enum rb_iseq_type type, const rb_compile_option_t *option, int *error_state)
1287{
1288 struct pm_iseq_new_with_opt_data data = {
1289 .node = node, .name = name, .path = path, .realpath = realpath,
1290 .first_lineno = first_lineno, .parent = parent,
1291 .isolated_depth = isolated_depth, .type = type, .option = option
1292 };
1293 rb_protect(pm_iseq_new_with_opt_try, (VALUE)&data, error_state);
1294
1295 if (*error_state) return NULL;
1296
1297 return data.iseq;
1298}
1299
1300rb_iseq_t *
1301rb_iseq_new_with_callback(
1302 const struct rb_iseq_new_with_callback_callback_func * ifunc,
1303 VALUE name, VALUE path, VALUE realpath,
1304 int first_lineno, const rb_iseq_t *parent,
1305 enum rb_iseq_type type, const rb_compile_option_t *option)
1306{
1307 /* TODO: argument check */
1308 rb_iseq_t *iseq = iseq_alloc();
1309
1310 if (!option) option = &COMPILE_OPTION_DEFAULT;
1311 prepare_iseq_build(iseq, name, path, realpath, first_lineno, NULL, -1, parent, 0, type, Qnil, option);
1312
1313 rb_iseq_compile_callback(iseq, ifunc);
1314 finish_iseq_build(iseq);
1315
1316 return iseq;
1317}
1318
1319const rb_iseq_t *
1320rb_iseq_load_iseq(VALUE fname)
1321{
1322 VALUE iseqv = rb_check_funcall(rb_cISeq, rb_intern("load_iseq"), 1, &fname);
1323
1324 if (!SPECIAL_CONST_P(iseqv) && RBASIC_CLASS(iseqv) == rb_cISeq) {
1325 return iseqw_check(iseqv);
1326 }
1327
1328 return NULL;
1329}
1330
1331const rb_iseq_t *
1332rb_iseq_compile_iseq(VALUE str, VALUE fname)
1333{
1334 VALUE args[] = {
1335 str, fname
1336 };
1337 VALUE iseqv = rb_check_funcall(rb_cISeq, rb_intern("compile"), 2, args);
1338
1339 if (!SPECIAL_CONST_P(iseqv) && RBASIC_CLASS(iseqv) == rb_cISeq) {
1340 return iseqw_check(iseqv);
1341 }
1342
1343 return NULL;
1344}
1345
1346#define CHECK_ARRAY(v) rb_to_array_type(v)
1347#define CHECK_HASH(v) rb_to_hash_type(v)
1348#define CHECK_STRING(v) rb_str_to_str(v)
1349#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
1350static inline VALUE CHECK_INTEGER(VALUE v) {(void)NUM2LONG(v); return v;}
1351
1352static enum rb_iseq_type
1353iseq_type_from_sym(VALUE type)
1354{
1355 const ID id_top = rb_intern("top");
1356 const ID id_method = rb_intern("method");
1357 const ID id_block = rb_intern("block");
1358 const ID id_class = rb_intern("class");
1359 const ID id_rescue = rb_intern("rescue");
1360 const ID id_ensure = rb_intern("ensure");
1361 const ID id_eval = rb_intern("eval");
1362 const ID id_main = rb_intern("main");
1363 const ID id_plain = rb_intern("plain");
1364 /* ensure all symbols are static or pinned down before
1365 * conversion */
1366 const ID typeid = rb_check_id(&type);
1367 if (typeid == id_top) return ISEQ_TYPE_TOP;
1368 if (typeid == id_method) return ISEQ_TYPE_METHOD;
1369 if (typeid == id_block) return ISEQ_TYPE_BLOCK;
1370 if (typeid == id_class) return ISEQ_TYPE_CLASS;
1371 if (typeid == id_rescue) return ISEQ_TYPE_RESCUE;
1372 if (typeid == id_ensure) return ISEQ_TYPE_ENSURE;
1373 if (typeid == id_eval) return ISEQ_TYPE_EVAL;
1374 if (typeid == id_main) return ISEQ_TYPE_MAIN;
1375 if (typeid == id_plain) return ISEQ_TYPE_PLAIN;
1376 return (enum rb_iseq_type)-1;
1377}
1378
1379static VALUE
1380iseq_load(VALUE data, const rb_iseq_t *parent, VALUE opt)
1381{
1382 rb_iseq_t *iseq = iseq_alloc();
1383
1384 VALUE magic, version1, version2, format_type, misc;
1385 VALUE name, path, realpath, code_location, node_id;
1386 VALUE type, body, locals, params, exception;
1387
1388 st_data_t iseq_type;
1389 rb_compile_option_t option;
1390 int i = 0;
1391 rb_code_location_t tmp_loc = { {0, 0}, {-1, -1} };
1392
1393 /* [magic, major_version, minor_version, format_type, misc,
1394 * label, path, first_lineno,
1395 * type, locals, args, exception_table, body]
1396 */
1397
1398 data = CHECK_ARRAY(data);
1399
1400 magic = CHECK_STRING(rb_ary_entry(data, i++));
1401 version1 = CHECK_INTEGER(rb_ary_entry(data, i++));
1402 version2 = CHECK_INTEGER(rb_ary_entry(data, i++));
1403 format_type = CHECK_INTEGER(rb_ary_entry(data, i++));
1404 misc = CHECK_HASH(rb_ary_entry(data, i++));
1405 ((void)magic, (void)version1, (void)version2, (void)format_type);
1406
1407 name = CHECK_STRING(rb_ary_entry(data, i++));
1408 path = CHECK_STRING(rb_ary_entry(data, i++));
1409 realpath = rb_ary_entry(data, i++);
1410 realpath = NIL_P(realpath) ? Qnil : CHECK_STRING(realpath);
1411 int first_lineno = RB_NUM2INT(rb_ary_entry(data, i++));
1412
1413 type = CHECK_SYMBOL(rb_ary_entry(data, i++));
1414 locals = CHECK_ARRAY(rb_ary_entry(data, i++));
1415 params = CHECK_HASH(rb_ary_entry(data, i++));
1416 exception = CHECK_ARRAY(rb_ary_entry(data, i++));
1417 body = CHECK_ARRAY(rb_ary_entry(data, i++));
1418
1419 ISEQ_BODY(iseq)->local_iseq = iseq;
1420
1421 iseq_type = iseq_type_from_sym(type);
1422 if (iseq_type == (enum rb_iseq_type)-1) {
1423 rb_raise(rb_eTypeError, "unsupported type: :%"PRIsVALUE, rb_sym2str(type));
1424 }
1425
1426 node_id = rb_hash_aref(misc, ID2SYM(rb_intern("node_id")));
1427
1428 code_location = rb_hash_aref(misc, ID2SYM(rb_intern("code_location")));
1429 if (RB_TYPE_P(code_location, T_ARRAY) && RARRAY_LEN(code_location) == 4) {
1430 tmp_loc.beg_pos.lineno = NUM2INT(rb_ary_entry(code_location, 0));
1431 tmp_loc.beg_pos.column = NUM2INT(rb_ary_entry(code_location, 1));
1432 tmp_loc.end_pos.lineno = NUM2INT(rb_ary_entry(code_location, 2));
1433 tmp_loc.end_pos.column = NUM2INT(rb_ary_entry(code_location, 3));
1434 }
1435
1436 if (SYM2ID(rb_hash_aref(misc, ID2SYM(rb_intern("parser")))) == rb_intern("prism")) {
1437 ISEQ_BODY(iseq)->prism = true;
1438 }
1439
1440 make_compile_option(&option, opt);
1441 option.peephole_optimization = FALSE; /* because peephole optimization can modify original iseq */
1442 prepare_iseq_build(iseq, name, path, realpath, first_lineno, &tmp_loc, NUM2INT(node_id),
1443 parent, 0, (enum rb_iseq_type)iseq_type, Qnil, &option);
1444
1445 rb_iseq_build_from_ary(iseq, misc, locals, params, exception, body);
1446
1447 finish_iseq_build(iseq);
1448
1449 return iseqw_new(iseq);
1450}
1451
1452/*
1453 * :nodoc:
1454 */
1455static VALUE
1456iseq_s_load(int argc, VALUE *argv, VALUE self)
1457{
1458 VALUE data, opt=Qnil;
1459 rb_scan_args(argc, argv, "11", &data, &opt);
1460 return iseq_load(data, NULL, opt);
1461}
1462
1463VALUE
1464rb_iseq_load(VALUE data, VALUE parent, VALUE opt)
1465{
1466 return iseq_load(data, RTEST(parent) ? (rb_iseq_t *)parent : NULL, opt);
1467}
1468
1469static rb_iseq_t *
1470rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, VALUE opt)
1471{
1472 rb_iseq_t *iseq = NULL;
1473 rb_compile_option_t option;
1474#if !defined(__GNUC__)
1475# define INITIALIZED volatile /* suppress warnings */
1476#else
1477# define INITIALIZED /* volatile */
1478#endif
1479 VALUE (*parse)(VALUE vparser, VALUE fname, VALUE file, int start);
1480 int ln;
1481 VALUE INITIALIZED ast_value;
1482 rb_ast_t *ast;
1483 VALUE name = rb_fstring_lit("<compiled>");
1484
1485 /* safe results first */
1486 make_compile_option(&option, opt);
1487 ln = NUM2INT(line);
1488 StringValueCStr(file);
1489 if (RB_TYPE_P(src, T_FILE)) {
1490 parse = rb_parser_compile_file_path;
1491 }
1492 else {
1493 parse = rb_parser_compile_string_path;
1494 StringValue(src);
1495 }
1496 {
1497 const VALUE parser = rb_parser_new();
1498 const rb_iseq_t *outer_scope = rb_iseq_new(Qnil, name, name, Qnil, 0, ISEQ_TYPE_TOP);
1499 VALUE outer_scope_v = (VALUE)outer_scope;
1500 rb_parser_set_context(parser, outer_scope, FALSE);
1501 if (ruby_vm_keep_script_lines) rb_parser_set_script_lines(parser);
1502 RB_GC_GUARD(outer_scope_v);
1503 ast_value = (*parse)(parser, file, src, ln);
1504 }
1505
1506 ast = rb_ruby_ast_data_get(ast_value);
1507
1508 if (!ast || !ast->body.root) {
1509 rb_ast_dispose(ast);
1510 rb_exc_raise(GET_EC()->errinfo);
1511 }
1512 else {
1513 if (option.coverage_enabled) iseq_new_setup_coverage(file, ast_line_count(ast_value));
1514 iseq = rb_iseq_new_with_opt(ast_value, name, file, realpath, ln,
1515 NULL, 0, ISEQ_TYPE_TOP, &option,
1516 Qnil);
1517 rb_ast_dispose(ast);
1518 }
1519
1520 return iseq;
1521}
1522
1523static rb_iseq_t *
1524pm_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, VALUE opt)
1525{
1526 rb_iseq_t *iseq = NULL;
1527 rb_compile_option_t option;
1528 int ln;
1529 VALUE name = rb_fstring_lit("<compiled>");
1530
1531 /* safe results first */
1532 make_compile_option(&option, opt);
1533 ln = NUM2INT(line);
1534 StringValueCStr(file);
1535
1536 bool parse_file = false;
1537 if (RB_TYPE_P(src, T_FILE)) {
1538 parse_file = true;
1539 src = rb_io_path(src);
1540 }
1541 else {
1542 src = StringValue(src);
1543 }
1544
1545 pm_parse_result_t result;
1546 pm_parse_result_init(&result);
1547 pm_options_line_set(result.options, NUM2INT(line));
1548 pm_options_scopes_init(result.options, 1);
1549 result.node.coverage_enabled = option.coverage_enabled;
1550
1551 switch (option.frozen_string_literal) {
1552 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
1553 break;
1554 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
1555 pm_options_frozen_string_literal_set(result.options, false);
1556 break;
1557 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
1558 pm_options_frozen_string_literal_set(result.options, true);
1559 break;
1560 default:
1561 rb_bug("pm_iseq_compile_with_option: invalid frozen_string_literal=%d", option.frozen_string_literal);
1562 break;
1563 }
1564
1565 VALUE script_lines;
1566 VALUE error;
1567
1568 if (parse_file) {
1569 error = pm_load_parse_file(&result, src, ruby_vm_keep_script_lines ? &script_lines : NULL);
1570 }
1571 else {
1572 error = pm_parse_string(&result, src, file, ruby_vm_keep_script_lines ? &script_lines : NULL);
1573 }
1574
1575 RB_GC_GUARD(src);
1576
1577 if (error == Qnil) {
1578 int error_state;
1579 if (option.coverage_enabled) iseq_new_setup_coverage(file, (int) (pm_parser_line_offsets(result.node.parser)->size - 1));
1580 iseq = pm_iseq_new_with_opt(&result.node, name, file, realpath, ln, NULL, 0, ISEQ_TYPE_TOP, &option, &error_state);
1581
1582 pm_parse_result_free(&result);
1583
1584 if (error_state) {
1585 RUBY_ASSERT(iseq == NULL);
1586 rb_jump_tag(error_state);
1587 }
1588 }
1589 else {
1590 pm_parse_result_free(&result);
1591 rb_exc_raise(error);
1592 }
1593
1594 return iseq;
1595}
1596
1597VALUE
1598rb_iseq_path(const rb_iseq_t *iseq)
1599{
1600 return pathobj_path(ISEQ_BODY(iseq)->location.pathobj);
1601}
1602
1603VALUE
1604rb_iseq_realpath(const rb_iseq_t *iseq)
1605{
1606 return pathobj_realpath(ISEQ_BODY(iseq)->location.pathobj, ISEQ_BODY(iseq)->no_realpath);
1607}
1608
1609VALUE
1610rb_iseq_absolute_path(const rb_iseq_t *iseq)
1611{
1612 return rb_iseq_realpath(iseq);
1613}
1614
1615int
1616rb_iseq_from_eval_p(const rb_iseq_t *iseq)
1617{
1618 return NIL_P(rb_iseq_realpath(iseq));
1619}
1620
1621VALUE
1622rb_iseq_label(const rb_iseq_t *iseq)
1623{
1624 return ISEQ_BODY(iseq)->location.label;
1625}
1626
1627VALUE
1628rb_iseq_base_label(const rb_iseq_t *iseq)
1629{
1630 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
1631 const rb_iseq_t *local_iseq = body->local_iseq;
1632
1633 if (local_iseq == NULL || local_iseq == iseq) {
1634 return body->location.label;
1635 }
1636 else {
1637 return ISEQ_BODY(rb_iseq_check(local_iseq))->location.label;
1638 }
1639}
1640
1641VALUE
1642rb_iseq_first_lineno(const rb_iseq_t *iseq)
1643{
1644 return RB_INT2NUM(ISEQ_BODY(iseq)->location.first_lineno);
1645}
1646
1647VALUE
1648rb_iseq_method_name(const rb_iseq_t *iseq)
1649{
1650 struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
1651
1652 if (body->type == ISEQ_TYPE_METHOD) {
1653 return body->location.label;
1654 }
1655 else {
1656 return Qnil;
1657 }
1658}
1659
1660void
1661rb_iseq_code_location(const rb_iseq_t *iseq, int *beg_pos_lineno, int *beg_pos_column, int *end_pos_lineno, int *end_pos_column)
1662{
1663 const rb_code_location_t *loc = &ISEQ_BODY(iseq)->location.code_location;
1664 if (beg_pos_lineno) *beg_pos_lineno = loc->beg_pos.lineno;
1665 if (beg_pos_column) *beg_pos_column = loc->beg_pos.column;
1666 if (end_pos_lineno) *end_pos_lineno = loc->end_pos.lineno;
1667 if (end_pos_column) *end_pos_column = loc->end_pos.column;
1668}
1669
1670static ID iseq_type_id(enum rb_iseq_type type);
1671
1672VALUE
1673rb_iseq_type(const rb_iseq_t *iseq)
1674{
1675 return ID2SYM(iseq_type_id(ISEQ_BODY(iseq)->type));
1676}
1677
1678VALUE
1679rb_iseq_coverage(const rb_iseq_t *iseq)
1680{
1681 return ISEQ_COVERAGE(iseq);
1682}
1683
1684static int
1685remove_coverage_i(void *vstart, void *vend, size_t stride, void *data)
1686{
1687 VALUE v = (VALUE)vstart;
1688 for (; v != (VALUE)vend; v += stride) {
1689 void *ptr = rb_asan_poisoned_object_p(v);
1690 rb_asan_unpoison_object(v, false);
1691
1692 if (rb_obj_is_iseq(v)) {
1693 rb_iseq_t *iseq = (rb_iseq_t *)v;
1694 if (ISEQ_VARIABLE(iseq)) {
1695 ISEQ_COVERAGE_SET(iseq, Qnil);
1696 }
1697 }
1698
1699 asan_poison_object_if(ptr, v);
1700 }
1701 return 0;
1702}
1703
1704void
1705rb_iseq_remove_coverage_all(void)
1706{
1707 rb_objspace_each_objects(remove_coverage_i, NULL);
1708}
1709
1710/* define wrapper class methods (RubyVM::InstructionSequence) */
1711
1712static void
1713iseqw_mark_and_move(void *ptr)
1714{
1715 rb_gc_mark_and_move((VALUE *)ptr);
1716}
1717
1718static size_t
1719iseqw_memsize(const void *ptr)
1720{
1721 return rb_iseq_memsize(*(const rb_iseq_t **)ptr);
1722}
1723
1724static const rb_data_type_t iseqw_data_type = {
1725 "T_IMEMO/iseq",
1726 {
1727 iseqw_mark_and_move,
1729 iseqw_memsize,
1730 iseqw_mark_and_move,
1731 },
1732 0, 0, RUBY_TYPED_THREAD_SAFE_FREE|RUBY_TYPED_WB_PROTECTED
1733};
1734
1735static VALUE
1736iseqw_new(const rb_iseq_t *iseq)
1737{
1738 rb_iseq_t **ptr;
1739 VALUE obj = TypedData_Make_Struct(rb_cISeq, rb_iseq_t *, &iseqw_data_type, ptr);
1740 RB_OBJ_WRITE(obj, ptr, iseq);
1742 return obj;
1743}
1744
1745VALUE
1746rb_iseqw_new(const rb_iseq_t *iseq)
1747{
1748 return iseqw_new(iseq);
1749}
1750
1756static VALUE
1757iseqw_s_compile_parser(int argc, VALUE *argv, VALUE self, bool prism)
1758{
1759 VALUE src, file = Qnil, path = Qnil, line = Qnil, opt = Qnil;
1760 int i;
1761
1762 i = rb_scan_args(argc, argv, "1*:", &src, NULL, &opt);
1763 if (i > 4+NIL_P(opt)) rb_error_arity(argc, 1, 5);
1764 switch (i) {
1765 case 5: opt = argv[--i];
1766 case 4: line = argv[--i];
1767 case 3: path = argv[--i];
1768 case 2: file = argv[--i];
1769 }
1770
1771 if (NIL_P(file)) file = rb_fstring_lit("<compiled>");
1772 if (NIL_P(path)) path = file;
1773 if (NIL_P(line)) line = INT2FIX(1);
1774
1775 Check_Type(path, T_STRING);
1776 Check_Type(file, T_STRING);
1777
1778 rb_iseq_t *iseq;
1779 if (prism) {
1780 iseq = pm_iseq_compile_with_option(src, file, path, line, opt);
1781 }
1782 else {
1783 iseq = rb_iseq_compile_with_option(src, file, path, line, opt);
1784 }
1785
1786 return iseqw_new(iseq);
1787}
1788
1789/*
1790 * call-seq:
1791 * InstructionSequence.compile(source[, file[, path[, line[, options]]]]) -> iseq
1792 * InstructionSequence.new(source[, file[, path[, line[, options]]]]) -> iseq
1793 *
1794 * Takes +source+, which can be a string of Ruby code, or an open +File+ object.
1795 * that contains Ruby source code.
1796 *
1797 * Optionally takes +file+, +path+, and +line+ which describe the file path,
1798 * real path and first line number of the ruby code in +source+ which are
1799 * metadata attached to the returned +iseq+.
1800 *
1801 * +file+ is used for +__FILE__+ and exception backtrace. +path+ is used for
1802 * +require_relative+ base. It is recommended these should be the same full
1803 * path.
1804 *
1805 * +options+, which can be +true+, +false+ or a +Hash+, is used to
1806 * modify the default behavior of the Ruby iseq compiler.
1807 *
1808 * For details regarding valid compile options see ::compile_option=.
1809 *
1810 * RubyVM::InstructionSequence.compile("a = 1 + 2")
1811 * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
1812 *
1813 * path = "test.rb"
1814 * RubyVM::InstructionSequence.compile(File.read(path), path, File.expand_path(path))
1815 * #=> <RubyVM::InstructionSequence:<compiled>@test.rb:1>
1816 *
1817 * file = File.open("test.rb")
1818 * RubyVM::InstructionSequence.compile(file)
1819 * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>:1>
1820 *
1821 * path = File.expand_path("test.rb")
1822 * RubyVM::InstructionSequence.compile(File.read(path), path, path)
1823 * #=> <RubyVM::InstructionSequence:<compiled>@/absolute/path/to/test.rb:1>
1824 *
1825 */
1826static VALUE
1827iseqw_s_compile(int argc, VALUE *argv, VALUE self)
1828{
1829 return iseqw_s_compile_parser(argc, argv, self, rb_ruby_prism_p());
1830}
1831
1832/*
1833 * call-seq:
1834 * InstructionSequence.compile_parsey(source[, file[, path[, line[, options]]]]) -> iseq
1835 *
1836 * Takes +source+, which can be a string of Ruby code, or an open +File+ object.
1837 * that contains Ruby source code. It parses and compiles using parse.y.
1838 *
1839 * Optionally takes +file+, +path+, and +line+ which describe the file path,
1840 * real path and first line number of the ruby code in +source+ which are
1841 * metadata attached to the returned +iseq+.
1842 *
1843 * +file+ is used for +__FILE__+ and exception backtrace. +path+ is used for
1844 * +require_relative+ base. It is recommended these should be the same full
1845 * path.
1846 *
1847 * +options+, which can be +true+, +false+ or a +Hash+, is used to
1848 * modify the default behavior of the Ruby iseq compiler.
1849 *
1850 * For details regarding valid compile options see ::compile_option=.
1851 *
1852 * RubyVM::InstructionSequence.compile_parsey("a = 1 + 2")
1853 * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
1854 *
1855 * path = "test.rb"
1856 * RubyVM::InstructionSequence.compile_parsey(File.read(path), path, File.expand_path(path))
1857 * #=> <RubyVM::InstructionSequence:<compiled>@test.rb:1>
1858 *
1859 * file = File.open("test.rb")
1860 * RubyVM::InstructionSequence.compile_parsey(file)
1861 * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>:1>
1862 *
1863 * path = File.expand_path("test.rb")
1864 * RubyVM::InstructionSequence.compile_parsey(File.read(path), path, path)
1865 * #=> <RubyVM::InstructionSequence:<compiled>@/absolute/path/to/test.rb:1>
1866 *
1867 */
1868static VALUE
1869iseqw_s_compile_parsey(int argc, VALUE *argv, VALUE self)
1870{
1871 return iseqw_s_compile_parser(argc, argv, self, false);
1872}
1873
1874/*
1875 * call-seq:
1876 * InstructionSequence.compile_prism(source[, file[, path[, line[, options]]]]) -> iseq
1877 *
1878 * Takes +source+, which can be a string of Ruby code, or an open +File+ object.
1879 * that contains Ruby source code. It parses and compiles using prism.
1880 *
1881 * Optionally takes +file+, +path+, and +line+ which describe the file path,
1882 * real path and first line number of the ruby code in +source+ which are
1883 * metadata attached to the returned +iseq+.
1884 *
1885 * +file+ is used for +__FILE__+ and exception backtrace. +path+ is used for
1886 * +require_relative+ base. It is recommended these should be the same full
1887 * path.
1888 *
1889 * +options+, which can be +true+, +false+ or a +Hash+, is used to
1890 * modify the default behavior of the Ruby iseq compiler.
1891 *
1892 * For details regarding valid compile options see ::compile_option=.
1893 *
1894 * RubyVM::InstructionSequence.compile_prism("a = 1 + 2")
1895 * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
1896 *
1897 * path = "test.rb"
1898 * RubyVM::InstructionSequence.compile_prism(File.read(path), path, File.expand_path(path))
1899 * #=> <RubyVM::InstructionSequence:<compiled>@test.rb:1>
1900 *
1901 * file = File.open("test.rb")
1902 * RubyVM::InstructionSequence.compile_prism(file)
1903 * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>:1>
1904 *
1905 * path = File.expand_path("test.rb")
1906 * RubyVM::InstructionSequence.compile_prism(File.read(path), path, path)
1907 * #=> <RubyVM::InstructionSequence:<compiled>@/absolute/path/to/test.rb:1>
1908 *
1909 */
1910static VALUE
1911iseqw_s_compile_prism(int argc, VALUE *argv, VALUE self)
1912{
1913 return iseqw_s_compile_parser(argc, argv, self, true);
1914}
1915
1916static VALUE iseqw_s_compile_file_prism(int argc, VALUE *argv, VALUE self);
1917
1918/*
1919 * call-seq:
1920 * InstructionSequence.compile_file(file[, options]) -> iseq
1921 *
1922 * Takes +file+, a String with the location of a Ruby source file, reads,
1923 * parses and compiles the file, and returns +iseq+, the compiled
1924 * InstructionSequence with source location metadata set.
1925 *
1926 * Optionally takes +options+, which can be +true+, +false+ or a +Hash+, to
1927 * modify the default behavior of the Ruby iseq compiler.
1928 *
1929 * For details regarding valid compile options see ::compile_option=.
1930 *
1931 * # /tmp/hello.rb
1932 * puts "Hello, world!"
1933 *
1934 * # elsewhere
1935 * RubyVM::InstructionSequence.compile_file("/tmp/hello.rb")
1936 * #=> <RubyVM::InstructionSequence:<main>@/tmp/hello.rb>
1937 */
1938static VALUE
1939iseqw_s_compile_file(int argc, VALUE *argv, VALUE self)
1940{
1941 if (rb_ruby_prism_p()) {
1942 return iseqw_s_compile_file_prism(argc, argv, self);
1943 }
1944
1945 VALUE file, opt = Qnil;
1946 VALUE parser, f, exc = Qnil, ret;
1947 rb_ast_t *ast;
1948 VALUE ast_value;
1949 rb_compile_option_t option;
1950 int i;
1951
1952 i = rb_scan_args(argc, argv, "1*:", &file, NULL, &opt);
1953 if (i > 1+NIL_P(opt)) rb_error_arity(argc, 1, 2);
1954 switch (i) {
1955 case 2: opt = argv[--i];
1956 }
1957 FilePathValue(file);
1958 file = rb_fstring(file); /* rb_io_t->pathv gets frozen anyways */
1959
1960 make_compile_option(&option, opt);
1961
1962 f = rb_file_open_str(file, "r");
1963
1964 rb_execution_context_t *ec = GET_EC();
1965 VALUE v = rb_vm_push_frame_fname(ec, file);
1966
1967 parser = rb_parser_new();
1968 rb_parser_set_context(parser, NULL, FALSE);
1969 ast_value = rb_parser_load_file(parser, file);
1970 if (option.coverage_enabled) iseq_new_setup_coverage(file, ast_line_count(ast_value));
1971 ast = rb_ruby_ast_data_get(ast_value);
1972 if (!ast->body.root) exc = GET_EC()->errinfo;
1973
1974 rb_io_close(f);
1975 if (!ast->body.root) {
1976 rb_ast_dispose(ast);
1977 rb_exc_raise(exc);
1978 }
1979
1980 ret = iseqw_new(rb_iseq_new_with_opt(ast_value, rb_fstring_lit("<main>"),
1981 file,
1982 rb_realpath_internal(Qnil, file, 1),
1983 1, NULL, 0, ISEQ_TYPE_TOP, &option,
1984 Qnil));
1985 rb_ast_dispose(ast);
1986 RB_GC_GUARD(ast_value);
1987
1988 rb_vm_pop_frame(ec);
1989 RB_GC_GUARD(v);
1990 return ret;
1991}
1992
1993/*
1994 * call-seq:
1995 * InstructionSequence.compile_file_prism(file[, options]) -> iseq
1996 *
1997 * Takes +file+, a String with the location of a Ruby source file, reads,
1998 * parses and compiles the file, and returns +iseq+, the compiled
1999 * InstructionSequence with source location metadata set. It parses and
2000 * compiles using prism.
2001 *
2002 * Optionally takes +options+, which can be +true+, +false+ or a +Hash+, to
2003 * modify the default behavior of the Ruby iseq compiler.
2004 *
2005 * For details regarding valid compile options see ::compile_option=.
2006 *
2007 * # /tmp/hello.rb
2008 * puts "Hello, world!"
2009 *
2010 * # elsewhere
2011 * RubyVM::InstructionSequence.compile_file_prism("/tmp/hello.rb")
2012 * #=> <RubyVM::InstructionSequence:<main>@/tmp/hello.rb>
2013 */
2014static VALUE
2015iseqw_s_compile_file_prism(int argc, VALUE *argv, VALUE self)
2016{
2017 VALUE file, opt = Qnil, ret;
2018 rb_compile_option_t option;
2019 int i;
2020
2021 i = rb_scan_args(argc, argv, "1*:", &file, NULL, &opt);
2022 if (i > 1+NIL_P(opt)) rb_error_arity(argc, 1, 2);
2023 switch (i) {
2024 case 2: opt = argv[--i];
2025 }
2026 FilePathValue(file);
2027 file = rb_fstring(file); /* rb_io_t->pathv gets frozen anyways */
2028
2029 rb_execution_context_t *ec = GET_EC();
2030 VALUE v = rb_vm_push_frame_fname(ec, file);
2031
2032 make_compile_option(&option, opt);
2033
2034 pm_parse_result_t result;
2035 pm_parse_result_init(&result);
2036 result.node.coverage_enabled = option.coverage_enabled;
2037
2038 switch (option.frozen_string_literal) {
2039 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
2040 break;
2041 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
2042 pm_options_frozen_string_literal_set(result.options, false);
2043 break;
2044 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
2045 pm_options_frozen_string_literal_set(result.options, true);
2046 break;
2047 default:
2048 rb_bug("iseqw_s_compile_file_prism: invalid frozen_string_literal=%d", option.frozen_string_literal);
2049 break;
2050 }
2051
2052 VALUE script_lines;
2053 VALUE error = pm_load_parse_file(&result, file, ruby_vm_keep_script_lines ? &script_lines : NULL);
2054
2055 if (error == Qnil) {
2056 int error_state;
2057 if (option.coverage_enabled) iseq_new_setup_coverage(file, (int) (pm_parser_line_offsets(result.node.parser)->size - 1));
2058 rb_iseq_t *iseq = pm_iseq_new_with_opt(&result.node, rb_fstring_lit("<main>"),
2059 file,
2060 rb_realpath_internal(Qnil, file, 1),
2061 1, NULL, 0, ISEQ_TYPE_TOP, &option, &error_state);
2062
2063 pm_parse_result_free(&result);
2064
2065 if (error_state) {
2066 RUBY_ASSERT(iseq == NULL);
2067 rb_jump_tag(error_state);
2068 }
2069
2070 ret = iseqw_new(iseq);
2071 rb_vm_pop_frame(ec);
2072 RB_GC_GUARD(v);
2073 return ret;
2074 }
2075 else {
2076 pm_parse_result_free(&result);
2077 rb_vm_pop_frame(ec);
2078 RB_GC_GUARD(v);
2079 rb_exc_raise(error);
2080 }
2081}
2082
2083/*
2084 * call-seq:
2085 * InstructionSequence.compile_option = options
2086 *
2087 * Sets the default values for various optimizations in the Ruby iseq
2088 * compiler.
2089 *
2090 * Possible values for +options+ include +true+, which enables all options,
2091 * +false+ which disables all options, and +nil+ which leaves all options
2092 * unchanged.
2093 *
2094 * You can also pass a +Hash+ of +options+ that you want to change, any
2095 * options not present in the hash will be left unchanged.
2096 *
2097 * Possible option names (which are keys in +options+) which can be set to
2098 * +true+ or +false+ include:
2099 *
2100 * * +:inline_const_cache+
2101 * * +:instructions_unification+
2102 * * +:operands_unification+
2103 * * +:peephole_optimization+
2104 * * +:specialized_instruction+
2105 * * +:tailcall_optimization+
2106 *
2107 * Additionally, +:debug_level+ can be set to an integer.
2108 *
2109 * These default options can be overwritten for a single run of the iseq
2110 * compiler by passing any of the above values as the +options+ parameter to
2111 * ::new, ::compile and ::compile_file.
2112 */
2113static VALUE
2114iseqw_s_compile_option_set(VALUE self, VALUE opt)
2115{
2116 rb_compile_option_t option;
2117 make_compile_option(&option, opt);
2118 COMPILE_OPTION_DEFAULT = option;
2119 return opt;
2120}
2121
2122/*
2123 * call-seq:
2124 * InstructionSequence.compile_option -> options
2125 *
2126 * Returns a hash of default options used by the Ruby iseq compiler.
2127 *
2128 * For details, see InstructionSequence.compile_option=.
2129 */
2130static VALUE
2131iseqw_s_compile_option_get(VALUE self)
2132{
2133 return make_compile_option_value(&COMPILE_OPTION_DEFAULT);
2134}
2135
2136static const rb_iseq_t *
2137iseqw_check(VALUE iseqw)
2138{
2139 rb_iseq_t **iseq_ptr;
2140 TypedData_Get_Struct(iseqw, rb_iseq_t *, &iseqw_data_type, iseq_ptr);
2141 rb_iseq_t *iseq = *iseq_ptr;
2142
2143 if (!ISEQ_BODY(iseq)) {
2144 rb_ibf_load_iseq_complete(iseq);
2145 }
2146
2147 if (!ISEQ_BODY(iseq)->location.label) {
2148 rb_raise(rb_eTypeError, "uninitialized InstructionSequence");
2149 }
2150 return iseq;
2151}
2152
2153const rb_iseq_t *
2154rb_iseqw_to_iseq(VALUE iseqw)
2155{
2156 return iseqw_check(iseqw);
2157}
2158
2159/*
2160 * call-seq:
2161 * iseq.eval -> obj
2162 *
2163 * Evaluates the instruction sequence and returns the result.
2164 *
2165 * RubyVM::InstructionSequence.compile("1 + 2").eval #=> 3
2166 */
2167static VALUE
2168iseqw_eval(VALUE self)
2169{
2170 const rb_iseq_t *iseq = iseqw_check(self);
2171 if (0 == ISEQ_BODY(iseq)->iseq_size) {
2172 rb_raise(rb_eTypeError, "attempt to evaluate dummy InstructionSequence");
2173 }
2174 return rb_iseq_eval(iseq, rb_current_box());
2175}
2176
2177/*
2178 * Returns a human-readable string representation of this instruction
2179 * sequence, including the #label and #path.
2180 */
2181static VALUE
2182iseqw_inspect(VALUE self)
2183{
2184 const rb_iseq_t *iseq = iseqw_check(self);
2185 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2186 VALUE klass = rb_class_name(rb_obj_class(self));
2187
2188 if (!body->location.label) {
2189 return rb_sprintf("#<%"PRIsVALUE": uninitialized>", klass);
2190 }
2191 else {
2192 return rb_sprintf("<%"PRIsVALUE":%"PRIsVALUE"@%"PRIsVALUE":%d>",
2193 klass,
2194 body->location.label, rb_iseq_path(iseq),
2195 FIX2INT(rb_iseq_first_lineno(iseq)));
2196 }
2197}
2198
2199/*
2200 * Returns the path of this instruction sequence.
2201 *
2202 * <code><compiled></code> if the iseq was evaluated from a string.
2203 *
2204 * For example, using irb:
2205 *
2206 * iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
2207 * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
2208 * iseq.path
2209 * #=> "<compiled>"
2210 *
2211 * Using ::compile_file:
2212 *
2213 * # /tmp/method.rb
2214 * def hello
2215 * puts "hello, world"
2216 * end
2217 *
2218 * # in irb
2219 * > iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
2220 * > iseq.path #=> /tmp/method.rb
2221 */
2222static VALUE
2223iseqw_path(VALUE self)
2224{
2225 return rb_iseq_path(iseqw_check(self));
2226}
2227
2228/*
2229 * Returns the absolute path of this instruction sequence.
2230 *
2231 * +nil+ if the iseq was evaluated from a string.
2232 *
2233 * For example, using ::compile_file:
2234 *
2235 * # /tmp/method.rb
2236 * def hello
2237 * puts "hello, world"
2238 * end
2239 *
2240 * # in irb
2241 * > iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
2242 * > iseq.absolute_path #=> /tmp/method.rb
2243 */
2244static VALUE
2245iseqw_absolute_path(VALUE self)
2246{
2247 return rb_iseq_realpath(iseqw_check(self));
2248}
2249
2250/* Returns the label of this instruction sequence.
2251 *
2252 * <code><main></code> if it's at the top level, <code><compiled></code> if it
2253 * was evaluated from a string.
2254 *
2255 * For example, using irb:
2256 *
2257 * iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
2258 * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
2259 * iseq.label
2260 * #=> "<compiled>"
2261 *
2262 * Using ::compile_file:
2263 *
2264 * # /tmp/method.rb
2265 * def hello
2266 * puts "hello, world"
2267 * end
2268 *
2269 * # in irb
2270 * > iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
2271 * > iseq.label #=> <main>
2272 */
2273static VALUE
2274iseqw_label(VALUE self)
2275{
2276 return rb_iseq_label(iseqw_check(self));
2277}
2278
2279/* Returns the base label of this instruction sequence.
2280 *
2281 * For example, using irb:
2282 *
2283 * iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
2284 * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
2285 * iseq.base_label
2286 * #=> "<compiled>"
2287 *
2288 * Using ::compile_file:
2289 *
2290 * # /tmp/method.rb
2291 * def hello
2292 * puts "hello, world"
2293 * end
2294 *
2295 * # in irb
2296 * > iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
2297 * > iseq.base_label #=> <main>
2298 */
2299static VALUE
2300iseqw_base_label(VALUE self)
2301{
2302 return rb_iseq_base_label(iseqw_check(self));
2303}
2304
2305/* Returns the number of the first source line where the instruction sequence
2306 * was loaded from.
2307 *
2308 * For example, using irb:
2309 *
2310 * iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
2311 * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
2312 * iseq.first_lineno
2313 * #=> 1
2314 */
2315static VALUE
2316iseqw_first_lineno(VALUE self)
2317{
2318 return rb_iseq_first_lineno(iseqw_check(self));
2319}
2320
2321static VALUE iseq_data_to_ary(const rb_iseq_t *iseq);
2322
2323/*
2324 * call-seq:
2325 * iseq.to_a -> ary
2326 *
2327 * Returns an Array with 14 elements representing the instruction sequence
2328 * with the following data:
2329 *
2330 * [magic]
2331 * A string identifying the data format. <b>Always
2332 * +YARVInstructionSequence/SimpleDataFormat+.</b>
2333 *
2334 * [major_version]
2335 * The major version of the instruction sequence.
2336 *
2337 * [minor_version]
2338 * The minor version of the instruction sequence.
2339 *
2340 * [format_type]
2341 * A number identifying the data format. <b>Always 1</b>.
2342 *
2343 * [misc]
2344 * A hash containing:
2345 *
2346 * [+:arg_size+]
2347 * the total number of arguments taken by the method or the block (0 if
2348 * _iseq_ doesn't represent a method or block)
2349 * [+:local_size+]
2350 * the number of local variables + 1
2351 * [+:stack_max+]
2352 * used in calculating the stack depth at which a SystemStackError is
2353 * thrown.
2354 *
2355 * [#label]
2356 * The name of the context (block, method, class, module, etc.) that this
2357 * instruction sequence belongs to.
2358 *
2359 * <code><main></code> if it's at the top level, <code><compiled></code> if
2360 * it was evaluated from a string.
2361 *
2362 * [#path]
2363 * The relative path to the Ruby file where the instruction sequence was
2364 * loaded from.
2365 *
2366 * <code><compiled></code> if the iseq was evaluated from a string.
2367 *
2368 * [#absolute_path]
2369 * The absolute path to the Ruby file where the instruction sequence was
2370 * loaded from.
2371 *
2372 * +nil+ if the iseq was evaluated from a string.
2373 *
2374 * [#first_lineno]
2375 * The number of the first source line where the instruction sequence was
2376 * loaded from.
2377 *
2378 * [type]
2379 * The type of the instruction sequence.
2380 *
2381 * Valid values are +:top+, +:method+, +:block+, +:class+, +:rescue+,
2382 * +:ensure+, +:eval+, +:main+, and +plain+.
2383 *
2384 * [locals]
2385 * An array containing the names of all arguments and local variables as
2386 * symbols.
2387 *
2388 * [params]
2389 * An Hash object containing parameter information.
2390 *
2391 * More info about these values can be found in +vm_core.h+.
2392 *
2393 * [catch_table]
2394 * A list of exceptions and control flow operators (rescue, next, redo,
2395 * break, etc.).
2396 *
2397 * [bytecode]
2398 * An array of arrays containing the instruction names and operands that
2399 * make up the body of the instruction sequence.
2400 *
2401 * Note that this format is MRI specific and version dependent.
2402 *
2403 */
2404static VALUE
2405iseqw_to_a(VALUE self)
2406{
2407 const rb_iseq_t *iseq = iseqw_check(self);
2408 return iseq_data_to_ary(iseq);
2409}
2410
2411#if VM_INSN_INFO_TABLE_IMPL == 1 /* binary search */
2412static const struct iseq_insn_info_entry *
2413get_insn_info_binary_search(const rb_iseq_t *iseq, size_t pos)
2414{
2415 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2416 size_t size = body->insns_info.size;
2417 const struct iseq_insn_info_entry *insns_info = body->insns_info.body;
2418 const unsigned int *positions = body->insns_info.positions_or_succ_index_table.positions;
2419 const int debug = 0;
2420
2421 if (debug) {
2422 printf("size: %"PRIuSIZE"\n", size);
2423 printf("insns_info[%"PRIuSIZE"]: position: %d, line: %d, pos: %"PRIuSIZE"\n",
2424 (size_t)0, positions[0], insns_info[0].line_no, pos);
2425 }
2426
2427 if (size == 0) {
2428 return NULL;
2429 }
2430 else if (size == 1) {
2431 return &insns_info[0];
2432 }
2433 else {
2434 size_t l = 1, r = size - 1;
2435 while (l <= r) {
2436 size_t m = l + (r - l) / 2;
2437 if (positions[m] == pos) {
2438 return &insns_info[m];
2439 }
2440 if (positions[m] < pos) {
2441 l = m + 1;
2442 }
2443 else {
2444 r = m - 1;
2445 }
2446 }
2447 if (l >= size) {
2448 return &insns_info[size-1];
2449 }
2450 if (positions[l] > pos) {
2451 return &insns_info[l-1];
2452 }
2453 return &insns_info[l];
2454 }
2455}
2456
2457static const struct iseq_insn_info_entry *
2458get_insn_info(const rb_iseq_t *iseq, size_t pos)
2459{
2460 return get_insn_info_binary_search(iseq, pos);
2461}
2462#endif
2463
2464#if VM_INSN_INFO_TABLE_IMPL == 2 /* succinct bitvector */
2465static const struct iseq_insn_info_entry *
2466get_insn_info_succinct_bitvector(const rb_iseq_t *iseq, size_t pos)
2467{
2468 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2469 size_t size = body->insns_info.size;
2470 const struct iseq_insn_info_entry *insns_info = body->insns_info.body;
2471 const int debug = 0;
2472
2473 if (debug) {
2474 printf("size: %"PRIuSIZE"\n", size);
2475 printf("insns_info[%"PRIuSIZE"]: line: %d, pos: %"PRIuSIZE"\n",
2476 (size_t)0, insns_info[0].line_no, pos);
2477 }
2478
2479 if (size == 0) {
2480 return NULL;
2481 }
2482 else if (size == 1) {
2483 return &insns_info[0];
2484 }
2485 else {
2486 int index;
2487 VM_ASSERT(body->insns_info.positions_or_succ_index_table.succ_index_table != NULL);
2488 index = succ_index_lookup(body->insns_info.positions_or_succ_index_table.succ_index_table, (int)pos);
2489 return &insns_info[index-1];
2490 }
2491}
2492
2493static const struct iseq_insn_info_entry *
2494get_insn_info(const rb_iseq_t *iseq, size_t pos)
2495{
2496 return get_insn_info_succinct_bitvector(iseq, pos);
2497}
2498#endif
2499
2500#if VM_CHECK_MODE > 0 || VM_INSN_INFO_TABLE_IMPL == 0
2501static const struct iseq_insn_info_entry *
2502get_insn_info_linear_search(const rb_iseq_t *iseq, const unsigned int *positions, size_t pos)
2503{
2504 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2505 size_t i = 0, size = body->insns_info.size;
2506 const struct iseq_insn_info_entry *insns_info = body->insns_info.body;
2507 const int debug = 0;
2508
2509 if (debug) {
2510 printf("size: %"PRIuSIZE"\n", size);
2511 printf("insns_info[%"PRIuSIZE"]: position: %d, line: %d, pos: %"PRIuSIZE"\n",
2512 i, positions[i], insns_info[i].line_no, pos);
2513 }
2514
2515 if (size == 0) {
2516 return NULL;
2517 }
2518 else if (size == 1) {
2519 return &insns_info[0];
2520 }
2521 else {
2522 for (i=1; i<size; i++) {
2523 if (debug) printf("insns_info[%"PRIuSIZE"]: position: %d, line: %d, pos: %"PRIuSIZE"\n",
2524 i, positions[i], insns_info[i].line_no, pos);
2525
2526 if (positions[i] == pos) {
2527 return &insns_info[i];
2528 }
2529 if (positions[i] > pos) {
2530 return &insns_info[i-1];
2531 }
2532 }
2533 }
2534 return &insns_info[i-1];
2535}
2536#endif
2537
2538#if VM_INSN_INFO_TABLE_IMPL == 0 /* linear search */
2539static const struct iseq_insn_info_entry *
2540get_insn_info(const rb_iseq_t *iseq, size_t pos)
2541{
2542 return get_insn_info_linear_search(iseq, ISEQ_BODY(iseq)->insns_info.positions_or_succ_index_table.positions, pos);
2543}
2544#endif
2545
2546#if VM_CHECK_MODE > 0 && VM_INSN_INFO_TABLE_IMPL > 0
2547static void
2548validate_get_insn_info(const rb_iseq_t *iseq)
2549{
2550 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2551 size_t i;
2552#if VM_INSN_INFO_TABLE_IMPL == 2
2553 unsigned int *positions = rb_iseq_insns_info_decode_positions(body);
2554#else
2555 const unsigned int *positions = body->insns_info.positions_or_succ_index_table.positions;
2556#endif
2557 for (i = 0; i < body->iseq_size; i++) {
2558 if (get_insn_info_linear_search(iseq, positions, i) != get_insn_info(iseq, i)) {
2559 rb_bug("validate_get_insn_info: get_insn_info_linear_search(iseq, %"PRIuSIZE") != get_insn_info(iseq, %"PRIuSIZE")", i, i);
2560 }
2561 }
2562#if VM_INSN_INFO_TABLE_IMPL == 2
2563 SIZED_FREE_N(positions, body->insns_info.size);
2564#endif
2565}
2566#endif
2567
2568unsigned int
2569rb_iseq_line_no(const rb_iseq_t *iseq, size_t pos)
2570{
2571 const struct iseq_insn_info_entry *entry = get_insn_info(iseq, pos);
2572
2573 if (entry) {
2574 return entry->line_no;
2575 }
2576 else {
2577 return 0;
2578 }
2579}
2580
2581#ifdef USE_ISEQ_NODE_ID
2582static int
2583node_id_stream_read(const uint8_t **ptr, const uint8_t *end)
2584{
2585 uint32_t zz = 0;
2586 unsigned int shift = 0;
2587 while (*ptr < end) {
2588 uint8_t byte = **ptr;
2589 (*ptr)++;
2590 zz |= (uint32_t)(byte & 0x7f) << shift;
2591 if (!(byte & 0x80)) break;
2592 shift += 7;
2593 }
2594 return (int)(zz >> 1) ^ -(int)(zz & 1);
2595}
2596
2597int
2598rb_iseq_node_id(const rb_iseq_t *iseq, size_t pos)
2599{
2600 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2601 if (body->insns_info.node_ids_size == 0) {
2602 return 0;
2603 }
2604
2605 const VALUE *code = rb_iseq_original_iseq(iseq);
2606 const uint8_t *ptr = body->insns_info.node_ids;
2607 const uint8_t *end = ptr + body->insns_info.node_ids_size;
2608 size_t code_pos = 0;
2609 int node_id = 0;
2610
2611 while (ptr < end && code_pos < body->iseq_size) {
2612 size_t len = (size_t)insn_len(code[code_pos]);
2613 node_id += node_id_stream_read(&ptr, end);
2614 if (pos < code_pos + len) {
2615 return node_id;
2616 }
2617 code_pos += len;
2618 }
2619
2620 VM_ASSERT(0); /* node_ids out of sync with the instruction sequence */
2621 return -1;
2622}
2623#endif
2624
2626rb_iseq_event_flags(const rb_iseq_t *iseq, size_t pos)
2627{
2628 const struct iseq_insn_info_entry *entry = get_insn_info(iseq, pos);
2629 if (entry) {
2630 return entry->events;
2631 }
2632 else {
2633 return 0;
2634 }
2635}
2636
2637static void rb_iseq_trace_flag_cleared(const rb_iseq_t *iseq, size_t pos);
2638
2639// Clear tracing event flags and turn off tracing for a given instruction as needed.
2640// This is currently used after updating a one-shot line coverage for the current instruction.
2641void
2642rb_iseq_clear_event_flags(const rb_iseq_t *iseq, size_t pos, rb_event_flag_t reset)
2643{
2644 RB_VM_LOCKING() {
2645 rb_vm_barrier();
2646
2647 struct iseq_insn_info_entry *entry = (struct iseq_insn_info_entry *)get_insn_info(iseq, pos);
2648 if (entry) {
2649 entry->events &= ~reset;
2650 if (!(entry->events & iseq->aux.exec.global_trace_events)) {
2651 rb_iseq_trace_flag_cleared(iseq, pos);
2652 }
2653 }
2654 }
2655}
2656
2657static VALUE
2658local_var_name(const rb_iseq_t *diseq, VALUE level, VALUE op)
2659{
2660 VALUE i;
2661 VALUE name;
2662 ID lid;
2663 int idx;
2664
2665 for (i = 0; i < level; i++) {
2666 diseq = ISEQ_BODY(diseq)->parent_iseq;
2667 }
2668 idx = ISEQ_BODY(diseq)->local_table_size - (int)op - 1;
2669 lid = ISEQ_BODY(diseq)->local_table[idx];
2670 name = rb_id2str(lid);
2671 if (!name) {
2672 name = rb_str_new_cstr("?");
2673 }
2674 else if (!rb_is_local_id(lid)) {
2675 name = rb_str_inspect(name);
2676 }
2677 else {
2678 name = rb_str_dup(name);
2679 }
2680 rb_str_catf(name, "@%d", idx);
2681 return name;
2682}
2683
2684int rb_insn_unified_local_var_level(VALUE);
2685VALUE rb_dump_literal(VALUE lit);
2686
2687VALUE
2688rb_insn_operand_intern(const rb_iseq_t *iseq,
2689 VALUE insn, int op_no, VALUE op,
2690 int len, size_t pos, const VALUE *pnop, VALUE child)
2691{
2692 const char *types = insn_op_types(insn);
2693 char type = types[op_no];
2694 VALUE ret = Qundef;
2695
2696 switch (type) {
2697 case TS_OFFSET: /* LONG */
2698 ret = rb_sprintf("%"PRIdVALUE, (VALUE)(pos + len + op));
2699 break;
2700
2701 case TS_NUM: /* ULONG */
2702 if (insn == BIN(defined) && op_no == 0) {
2703 enum defined_type deftype = (enum defined_type)op;
2704 switch (deftype) {
2705 case DEFINED_FUNC:
2706 ret = rb_fstring_lit("func");
2707 break;
2708 case DEFINED_REF:
2709 ret = rb_fstring_lit("ref");
2710 break;
2711 case DEFINED_CONST_FROM:
2712 ret = rb_fstring_lit("constant-from");
2713 break;
2714 default:
2715 ret = rb_iseq_defined_string(deftype);
2716 break;
2717 }
2718 if (ret) break;
2719 }
2720 else if (insn == BIN(checktype) && op_no == 0) {
2721 const char *type_str = rb_type_str((enum ruby_value_type)op);
2722 if (type_str) {
2723 ret = rb_str_new_cstr(type_str); break;
2724 }
2725 }
2726 ret = rb_sprintf("%"PRIuVALUE, op);
2727 break;
2728
2729 case TS_LINDEX:{
2730 int level;
2731 if (types[op_no+1] == TS_NUM && pnop) {
2732 ret = local_var_name(iseq, *pnop, op - VM_ENV_DATA_SIZE);
2733 }
2734 else if ((level = rb_insn_unified_local_var_level(insn)) >= 0) {
2735 ret = local_var_name(iseq, (VALUE)level, op - VM_ENV_DATA_SIZE);
2736 }
2737 else {
2738 ret = rb_inspect(INT2FIX(op));
2739 }
2740 break;
2741 }
2742 case TS_ID: /* ID (symbol) */
2743 ret = rb_inspect(ID2SYM(op));
2744 break;
2745
2746 case TS_VALUE: /* VALUE */
2747 op = obj_resurrect(op);
2748 if (insn == BIN(defined) && op_no == 1 && FIXNUM_P(op)) {
2749 /* should be DEFINED_REF */
2750 int type = NUM2INT(op);
2751 if (type) {
2752 if (type & 1) {
2753 ret = rb_sprintf(":$%c", (type >> 1));
2754 }
2755 else {
2756 ret = rb_sprintf(":$%d", (type >> 1));
2757 }
2758 break;
2759 }
2760 }
2761 ret = rb_dump_literal(op);
2762 if (CLASS_OF(op) == rb_cISeq) {
2763 if (child) {
2764 rb_ary_push(child, op);
2765 }
2766 }
2767 break;
2768
2769 case TS_ISEQ: /* iseq */
2770 {
2771 if (op) {
2772 const rb_iseq_t *iseq = rb_iseq_check((rb_iseq_t *)op);
2773 ret = ISEQ_BODY(iseq)->location.label;
2774 if (child) {
2775 rb_ary_push(child, (VALUE)iseq);
2776 }
2777 }
2778 else {
2779 ret = rb_str_new2("nil");
2780 }
2781 break;
2782 }
2783
2784 case TS_IC:
2785 {
2786 ret = rb_sprintf("<ic:%"PRIdPTRDIFF" ", (union iseq_inline_storage_entry *)op - ISEQ_BODY(iseq)->is_entries);
2787 const ID *segments = ((IC)op)->segments;
2788 rb_str_cat2(ret, rb_id2name(*segments++));
2789 while (*segments) {
2790 rb_str_catf(ret, "::%s", rb_id2name(*segments++));
2791 }
2792 rb_str_cat2(ret, ">");
2793 }
2794 break;
2795 case TS_IVC:
2796 case TS_ICVARC:
2797 case TS_ISE:
2798 ret = rb_sprintf("<is:%"PRIdPTRDIFF">", (union iseq_inline_storage_entry *)op - ISEQ_BODY(iseq)->is_entries);
2799 break;
2800
2801 case TS_CALLDATA:
2802 {
2803 struct rb_call_data *cd = (struct rb_call_data *)op;
2804 const struct rb_callinfo *ci = cd->ci;
2805 VALUE ary = rb_ary_new();
2806 ID mid = vm_ci_mid(ci);
2807
2808 if (mid) {
2809 rb_ary_push(ary, rb_sprintf("mid:%"PRIsVALUE, rb_id2str(mid)));
2810 }
2811
2812 rb_ary_push(ary, rb_sprintf("argc:%d", vm_ci_argc(ci)));
2813
2814 if (vm_ci_flag(ci) & VM_CALL_KWARG) {
2815 const struct rb_callinfo_kwarg *kw_args = vm_ci_kwarg(ci);
2816 VALUE kw_ary = rb_ary_new_from_values(kw_args->keyword_len, kw_args->keywords);
2817 rb_ary_push(ary, rb_sprintf("kw:[%"PRIsVALUE"]", rb_ary_join(kw_ary, rb_str_new2(","))));
2818 }
2819
2820 if (vm_ci_flag(ci)) {
2821 VALUE flags = rb_ary_new();
2822# define CALL_FLAG(n) if (vm_ci_flag(ci) & VM_CALL_##n) rb_ary_push(flags, rb_str_new2(#n))
2823 CALL_FLAG(ARGS_SPLAT);
2824 CALL_FLAG(ARGS_SPLAT_MUT);
2825 CALL_FLAG(ARGS_BLOCKARG);
2826 CALL_FLAG(FCALL);
2827 CALL_FLAG(VCALL);
2828 CALL_FLAG(ARGS_SIMPLE);
2829 CALL_FLAG(TAILCALL);
2830 CALL_FLAG(SUPER);
2831 CALL_FLAG(ZSUPER);
2832 CALL_FLAG(KWARG);
2833 CALL_FLAG(KW_SPLAT);
2834 CALL_FLAG(KW_SPLAT_MUT);
2835 CALL_FLAG(FORWARDING);
2836 CALL_FLAG(OPT_SEND); /* maybe not reachable */
2837 rb_ary_push(ary, rb_ary_join(flags, rb_str_new2("|")));
2838 }
2839
2840 ret = rb_sprintf("<calldata!%"PRIsVALUE">", rb_ary_join(ary, rb_str_new2(", ")));
2841 }
2842 break;
2843
2844 case TS_CDHASH:
2845 ret = rb_str_new2("<cdhash>");
2846 break;
2847
2848 case TS_FUNCPTR:
2849 {
2850#ifdef HAVE_DLADDR
2851 Dl_info info;
2852 if (dladdr((void *)op, &info) && info.dli_sname) {
2853 ret = rb_str_new_cstr(info.dli_sname);
2854 break;
2855 }
2856#endif
2857 ret = rb_str_new2("<funcptr>");
2858 }
2859 break;
2860
2861 case TS_BUILTIN:
2862 {
2863 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)op;
2864 ret = rb_sprintf("<builtin!%s/%d>",
2865 bf->name, bf->argc);
2866 }
2867 break;
2868
2869 default:
2870 rb_bug("unknown operand type: %c", type);
2871 }
2872 return ret;
2873}
2874
2875static VALUE
2876right_strip(VALUE str)
2877{
2878 const char *beg = RSTRING_PTR(str), *end = RSTRING_END(str);
2879 while (end-- > beg && *end == ' ');
2880 rb_str_set_len(str, end - beg + 1);
2881 return str;
2882}
2883
2888int
2889rb_iseq_disasm_insn(VALUE ret, const VALUE *code, size_t pos,
2890 const rb_iseq_t *iseq, VALUE child)
2891{
2892 VALUE insn = code[pos];
2893 int len = insn_len(insn);
2894 int j;
2895 const char *types = insn_op_types(insn);
2896 VALUE str = rb_str_new(0, 0);
2897 const char *insn_name_buff;
2898
2899 insn_name_buff = insn_name(insn);
2900 if (1) {
2901 extern const int rb_vm_max_insn_name_size;
2902 rb_str_catf(str, "%04"PRIuSIZE" %-*s ", pos, rb_vm_max_insn_name_size, insn_name_buff);
2903 }
2904 else {
2905 rb_str_catf(str, "%04"PRIuSIZE" %-28.*s ", pos,
2906 (int)strcspn(insn_name_buff, "_"), insn_name_buff);
2907 }
2908
2909 for (j = 0; types[j]; j++) {
2910 VALUE opstr = rb_insn_operand_intern(iseq, insn, j, code[pos + j + 1],
2911 len, pos, &code[pos + j + 2],
2912 child);
2913 rb_str_concat(str, opstr);
2914
2915 if (types[j + 1]) {
2916 rb_str_cat2(str, ", ");
2917 }
2918 }
2919
2920 {
2921 unsigned int line_no = rb_iseq_line_no(iseq, pos);
2922 unsigned int prev = pos == 0 ? 0 : rb_iseq_line_no(iseq, pos - 1);
2923 if (line_no && line_no != prev) {
2924 rb_len_t slen = RSTRING_LEN(str);
2925 slen = (slen > 70) ? 0 : (70 - slen);
2926 str = rb_str_catf(str, "%*s(%4d)", (int)slen, "", line_no);
2927 }
2928 }
2929
2930 {
2931 rb_event_flag_t events = rb_iseq_event_flags(iseq, pos);
2932 if (events) {
2933 str = rb_str_catf(str, "[%s%s%s%s%s%s%s%s%s%s%s%s]",
2934 events & RUBY_EVENT_LINE ? "Li" : "",
2935 events & RUBY_EVENT_CLASS ? "Cl" : "",
2936 events & RUBY_EVENT_END ? "En" : "",
2937 events & RUBY_EVENT_CALL ? "Ca" : "",
2938 events & RUBY_EVENT_RETURN ? "Re" : "",
2939 events & RUBY_EVENT_C_CALL ? "Cc" : "",
2940 events & RUBY_EVENT_C_RETURN ? "Cr" : "",
2941 events & RUBY_EVENT_B_CALL ? "Bc" : "",
2942 events & RUBY_EVENT_B_RETURN ? "Br" : "",
2943 events & RUBY_EVENT_RESCUE ? "Rs" : "",
2944 events & RUBY_EVENT_COVERAGE_LINE ? "Cli" : "",
2945 events & RUBY_EVENT_COVERAGE_BRANCH ? "Cbr" : "");
2946 }
2947 }
2948
2949 right_strip(str);
2950 if (ret) {
2951 rb_str_cat2(str, "\n");
2952 rb_str_concat(ret, str);
2953 }
2954 else {
2955 printf("%.*s\n", (int)RSTRING_LEN(str), RSTRING_PTR(str));
2956 }
2957 return len;
2958}
2959
2960static const char *
2961catch_type(int type)
2962{
2963 switch (type) {
2964 case CATCH_TYPE_RESCUE:
2965 return "rescue";
2966 case CATCH_TYPE_ENSURE:
2967 return "ensure";
2968 case CATCH_TYPE_RETRY:
2969 return "retry";
2970 case CATCH_TYPE_BREAK:
2971 return "break";
2972 case CATCH_TYPE_REDO:
2973 return "redo";
2974 case CATCH_TYPE_NEXT:
2975 return "next";
2976 default:
2977 rb_bug("unknown catch type: %d", type);
2978 return 0;
2979 }
2980}
2981
2982static VALUE
2983iseq_inspect(const rb_iseq_t *iseq)
2984{
2985 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2986 if (!body->location.label) {
2987 return rb_sprintf("#<ISeq: uninitialized>");
2988 }
2989 else {
2990 const rb_code_location_t *loc = &body->location.code_location;
2991 return rb_sprintf("#<ISeq:%"PRIsVALUE"@%"PRIsVALUE":%d (%d,%d)-(%d,%d)>",
2992 body->location.label, rb_iseq_path(iseq),
2993 loc->beg_pos.lineno,
2994 loc->beg_pos.lineno,
2995 loc->beg_pos.column,
2996 loc->end_pos.lineno,
2997 loc->end_pos.column);
2998 }
2999}
3000
3001static const rb_data_type_t tmp_set = {
3002 "tmpset",
3003 {(void (*)(void *))rb_mark_set, (void (*)(void *))st_free_table, 0, 0,},
3004 0, 0, RUBY_TYPED_THREAD_SAFE_FREE
3005};
3006
3007static VALUE
3008rb_iseq_disasm_recursive(const rb_iseq_t *iseq, VALUE indent)
3009{
3010 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
3011 VALUE *code;
3012 VALUE str = rb_str_new(0, 0);
3013 VALUE child = rb_ary_hidden_new(3);
3014 unsigned int size;
3015 unsigned int i;
3016 rb_len_t l;
3017 size_t n;
3018 enum {header_minlen = 72};
3019 st_table *done_iseq = 0;
3020 VALUE done_iseq_wrapper = Qnil;
3021 const char *indent_str;
3022 rb_len_t indent_len;
3023
3024 size = body->iseq_size;
3025
3026 indent_len = RSTRING_LEN(indent);
3027 indent_str = RSTRING_PTR(indent);
3028
3029 rb_str_cat(str, indent_str, indent_len);
3030 rb_str_cat2(str, "== disasm: ");
3031
3032 rb_str_append(str, iseq_inspect(iseq));
3033 if ((l = RSTRING_LEN(str) - indent_len) < header_minlen) {
3034 rb_str_modify_expand(str, header_minlen - l);
3035 memset(RSTRING_END(str), '=', header_minlen - l);
3036 }
3037 if (ISEQ_BODY(iseq)->builtin_attrs) {
3038#define disasm_builtin_attr(str, iseq, attr) \
3039 if (ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_ ## attr) { \
3040 rb_str_cat2(str, " " #attr); \
3041 }
3042 disasm_builtin_attr(str, iseq, LEAF);
3043 disasm_builtin_attr(str, iseq, SINGLE_NOARG_LEAF);
3044 disasm_builtin_attr(str, iseq, INLINE_BLOCK);
3045 disasm_builtin_attr(str, iseq, C_TRACE);
3046 disasm_builtin_attr(str, iseq, WITHOUT_INTERRUPTS);
3047 disasm_builtin_attr(str, iseq, CALLER_USER_BOX);
3048 disasm_builtin_attr(str, iseq, ALWAYS_INLINE);
3049 }
3050 rb_str_cat2(str, "\n");
3051
3052 /* show catch table information */
3053 if (body->catch_table) {
3054 rb_str_cat(str, indent_str, indent_len);
3055 rb_str_cat2(str, "== catch table\n");
3056 }
3057 if (body->catch_table) {
3058 rb_str_cat_cstr(indent, "| ");
3059 indent_str = RSTRING_PTR(indent);
3060 for (i = 0; i < body->catch_table->size; i++) {
3061 const struct iseq_catch_table_entry *entry =
3062 UNALIGNED_MEMBER_PTR(body->catch_table, entries[i]);
3063 rb_str_cat(str, indent_str, indent_len);
3064 rb_str_catf(str,
3065 "| catch type: %-6s st: %04d ed: %04d sp: %04d cont: %04d\n",
3066 catch_type((int)entry->type), (int)entry->start,
3067 (int)entry->end, (int)entry->sp, (int)entry->cont);
3068 if (entry->iseq && !(done_iseq && st_is_member(done_iseq, (st_data_t)entry->iseq))) {
3069 rb_str_concat(str, rb_iseq_disasm_recursive(rb_iseq_check(entry->iseq), indent));
3070 if (!done_iseq) {
3071 done_iseq = st_init_numtable();
3072 done_iseq_wrapper = TypedData_Wrap_Struct(0, &tmp_set, done_iseq);
3073 }
3074 st_insert(done_iseq, (st_data_t)entry->iseq, (st_data_t)0);
3075 indent_str = RSTRING_PTR(indent);
3076 }
3077 }
3078 rb_str_resize(indent, indent_len);
3079 indent_str = RSTRING_PTR(indent);
3080 }
3081 if (body->catch_table) {
3082 rb_str_cat(str, indent_str, indent_len);
3083 rb_str_cat2(str, "|-------------------------------------"
3084 "-----------------------------------\n");
3085 }
3086
3087 /* show local table information */
3088 if (body->local_table) {
3089 const struct rb_iseq_param_keyword *const keyword = body->param.keyword;
3090 rb_str_cat(str, indent_str, indent_len);
3091 rb_str_catf(str,
3092 "local table (size: %d, argc: %d "
3093 "[opts: %d, rest: %d, post: %d, block: %d, kw: %d@%d, kwrest: %d])\n",
3094 body->local_table_size,
3095 body->param.lead_num,
3096 body->param.opt_num,
3097 body->param.flags.has_rest ? body->param.rest_start : -1,
3098 body->param.post_num,
3099 body->param.flags.has_block ? body->param.block_start : -1,
3100 body->param.flags.has_kw ? keyword->num : -1,
3101 body->param.flags.has_kw ? keyword->required_num : -1,
3102 body->param.flags.has_kwrest ? keyword->rest_start : -1);
3103
3104 for (i = body->local_table_size; i > 0;) {
3105 int li = body->local_table_size - --i - 1;
3106 rb_len_t width;
3107 VALUE name = local_var_name(iseq, 0, i);
3108 char argi[0x100];
3109 char opti[0x100];
3110
3111 opti[0] = '\0';
3112 if (body->param.flags.has_opt) {
3113 int argc = body->param.lead_num;
3114 int opts = body->param.opt_num;
3115 if (li >= argc && li < argc + opts) {
3116 snprintf(opti, sizeof(opti), "Opt=%"PRIdVALUE,
3117 body->param.opt_table[li - argc]);
3118 }
3119 }
3120
3121 snprintf(argi, sizeof(argi), "%s%s%s%s%s%s", /* arg, opts, rest, post, kwrest, block */
3122 (body->param.lead_num > li) ? (body->param.flags.ambiguous_param0 ? "AmbiguousArg" : "Arg") : "",
3123 opti,
3124 (body->param.flags.has_rest && body->param.rest_start == li) ? (body->param.flags.anon_rest ? "AnonRest" : "Rest") : "",
3125 (body->param.flags.has_post && body->param.post_start <= li && li < body->param.post_start + body->param.post_num) ? "Post" : "",
3126 (body->param.flags.has_kwrest && keyword->rest_start == li) ? (body->param.flags.anon_kwrest ? "AnonKwrest" : "Kwrest") : "",
3127 (body->param.flags.has_block && body->param.block_start == li) ? "Block" : "");
3128
3129 rb_str_cat(str, indent_str, indent_len);
3130 rb_str_catf(str, "[%2d] ", i + 1);
3131 width = RSTRING_LEN(str) + 11;
3132 rb_str_append(str, name);
3133 if (*argi) rb_str_catf(str, "<%s>", argi);
3134 if ((width -= RSTRING_LEN(str)) > 0) rb_str_catf(str, "%*s", (int)width, "");
3135 }
3136 rb_str_cat_cstr(right_strip(str), "\n");
3137 }
3138
3139 /* show each line */
3140 code = rb_iseq_original_iseq(iseq);
3141 for (n = 0; n < size;) {
3142 rb_str_cat(str, indent_str, indent_len);
3143 n += rb_iseq_disasm_insn(str, code, n, iseq, child);
3144 }
3145
3146 if (body->mandatory_only_iseq) {
3147 rb_ary_push(child, (VALUE)body->mandatory_only_iseq);
3148 }
3149
3150 for (l = 0; l < RARRAY_LEN(child); l++) {
3151 VALUE isv = rb_ary_entry(child, l);
3152 if (done_iseq && st_is_member(done_iseq, (st_data_t)isv)) continue;
3153 rb_str_cat_cstr(str, "\n");
3154 rb_str_concat(str, rb_iseq_disasm_recursive(rb_iseq_check((rb_iseq_t *)isv), indent));
3155 indent_str = RSTRING_PTR(indent);
3156 }
3157 RB_GC_GUARD(done_iseq_wrapper);
3158
3159 return str;
3160}
3161
3162VALUE
3163rb_iseq_disasm(const rb_iseq_t *iseq)
3164{
3165 VALUE str = rb_iseq_disasm_recursive(iseq, rb_str_new(0, 0));
3166 rb_str_resize(str, RSTRING_LEN(str));
3167 return str;
3168}
3169
3170/*
3171 * Estimates the number of instance variables that will be set on
3172 * a given `class` with the initialize method defined in
3173 * `initialize_iseq`
3174 */
3175attr_index_t
3176rb_estimate_iv_count(VALUE klass, const rb_iseq_t * initialize_iseq)
3177{
3178 set_table iv_names = { 0 };
3179 set_init_embedded_numtable_with_size(&iv_names, 0);
3180
3181 for (unsigned int i = 0; i < ISEQ_BODY(initialize_iseq)->ivc_size; i++) {
3182 IVC cache = (IVC)&ISEQ_BODY(initialize_iseq)->is_entries[i];
3183
3184 if (cache->iv_set_name) {
3185 set_insert(&iv_names, cache->iv_set_name);
3186 }
3187 }
3188
3189 size_t count = iv_names.num_entries;
3190
3191 VALUE superclass = rb_class_superclass(klass);
3192 if (!NIL_P(superclass)) { // BasicObject doesn't have a superclass
3193 count += RCLASS_MAX_IV_COUNT(superclass);
3194 }
3195
3196 set_free_embedded_table(&iv_names);
3197
3198 if (count > (attr_index_t)-1) {
3199 return (attr_index_t)-1;
3200 }
3201
3202 return (attr_index_t)count;
3203}
3204
3205/*
3206 * call-seq:
3207 * iseq.disasm -> str
3208 * iseq.disassemble -> str
3209 *
3210 * Returns the instruction sequence as a +String+ in human readable form.
3211 *
3212 * puts RubyVM::InstructionSequence.compile('1 + 2').disasm
3213 *
3214 * Produces:
3215 *
3216 * == disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>==========
3217 * 0000 trace 1 ( 1)
3218 * 0002 putobject 1
3219 * 0004 putobject 2
3220 * 0006 opt_plus <ic:1>
3221 * 0008 leave
3222 */
3223static VALUE
3224iseqw_disasm(VALUE self)
3225{
3226 return rb_iseq_disasm(iseqw_check(self));
3227}
3228
3229static int
3230iseq_iterate_children(const rb_iseq_t *iseq, void (*iter_func)(const rb_iseq_t *child_iseq, void *data), void *data)
3231{
3232 unsigned int i;
3233 VALUE *code = rb_iseq_original_iseq(iseq);
3234 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
3235 const rb_iseq_t *child;
3236 VALUE all_children = rb_obj_hide(rb_ident_hash_new());
3237
3238 if (body->catch_table) {
3239 for (i = 0; i < body->catch_table->size; i++) {
3240 const struct iseq_catch_table_entry *entry =
3241 UNALIGNED_MEMBER_PTR(body->catch_table, entries[i]);
3242 child = entry->iseq;
3243 if (child) {
3244 if (NIL_P(rb_hash_aref(all_children, (VALUE)child))) {
3245 rb_hash_aset(all_children, (VALUE)child, Qtrue);
3246 (*iter_func)(child, data);
3247 }
3248 }
3249 }
3250 }
3251
3252 for (i=0; i<body->iseq_size;) {
3253 VALUE insn = code[i];
3254 int len = insn_len(insn);
3255 const char *types = insn_op_types(insn);
3256 int j;
3257
3258 for (j=0; types[j]; j++) {
3259 switch (types[j]) {
3260 case TS_ISEQ:
3261 child = (const rb_iseq_t *)code[i+j+1];
3262 if (child) {
3263 if (NIL_P(rb_hash_aref(all_children, (VALUE)child))) {
3264 rb_hash_aset(all_children, (VALUE)child, Qtrue);
3265 (*iter_func)(child, data);
3266 }
3267 }
3268 break;
3269 default:
3270 break;
3271 }
3272 }
3273 i += len;
3274 }
3275
3276 return (int)RHASH_SIZE(all_children);
3277}
3278
3279static void
3280yield_each_children(const rb_iseq_t *child_iseq, void *data)
3281{
3282 rb_yield(iseqw_new(child_iseq));
3283}
3284
3285/*
3286 * call-seq:
3287 * iseq.each_child{|child_iseq| ...} -> iseq
3288 *
3289 * Iterate all direct child instruction sequences.
3290 * Iteration order is implementation/version defined
3291 * so that people should not rely on the order.
3292 */
3293static VALUE
3294iseqw_each_child(VALUE self)
3295{
3296 const rb_iseq_t *iseq = iseqw_check(self);
3297 iseq_iterate_children(iseq, yield_each_children, NULL);
3298 return self;
3299}
3300
3301static void
3302push_event_info(const rb_iseq_t *iseq, rb_event_flag_t events, int line, VALUE ary)
3303{
3304#define C(ev, cstr, l) if (events & ev) rb_ary_push(ary, rb_ary_new_from_args(2, l, ID2SYM(rb_intern(cstr))));
3305 C(RUBY_EVENT_CLASS, "class", rb_iseq_first_lineno(iseq));
3306 C(RUBY_EVENT_CALL, "call", rb_iseq_first_lineno(iseq));
3307 C(RUBY_EVENT_B_CALL, "b_call", rb_iseq_first_lineno(iseq));
3308 C(RUBY_EVENT_LINE, "line", INT2FIX(line));
3309 C(RUBY_EVENT_END, "end", INT2FIX(line));
3310 C(RUBY_EVENT_RETURN, "return", INT2FIX(line));
3311 C(RUBY_EVENT_B_RETURN, "b_return", INT2FIX(line));
3312 C(RUBY_EVENT_RESCUE, "rescue", INT2FIX(line));
3313#undef C
3314}
3315
3316/*
3317 * call-seq:
3318 * iseq.trace_points -> ary
3319 *
3320 * Return trace points in the instruction sequence.
3321 * Return an array of [line, event_symbol] pair.
3322 */
3323static VALUE
3324iseqw_trace_points(VALUE self)
3325{
3326 const rb_iseq_t *iseq = iseqw_check(self);
3327 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
3328 unsigned int i;
3329 VALUE ary = rb_ary_new();
3330
3331 for (i=0; i<body->insns_info.size; i++) {
3332 const struct iseq_insn_info_entry *entry = &body->insns_info.body[i];
3333 if (entry->events) {
3334 push_event_info(iseq, entry->events, entry->line_no, ary);
3335 }
3336 }
3337 return ary;
3338}
3339
3340/*
3341 * Returns the instruction sequence containing the given proc or method.
3342 *
3343 * For example, using irb:
3344 *
3345 * # a proc
3346 * > p = proc { num = 1 + 2 }
3347 * > RubyVM::InstructionSequence.of(p)
3348 * > #=> <RubyVM::InstructionSequence:block in irb_binding@(irb)>
3349 *
3350 * # for a method
3351 * > def foo(bar); puts bar; end
3352 * > RubyVM::InstructionSequence.of(method(:foo))
3353 * > #=> <RubyVM::InstructionSequence:foo@(irb)>
3354 *
3355 * Using ::compile_file:
3356 *
3357 * # /tmp/iseq_of.rb
3358 * def hello
3359 * puts "hello, world"
3360 * end
3361 *
3362 * $a_global_proc = proc { str = 'a' + 'b' }
3363 *
3364 * # in irb
3365 * > require '/tmp/iseq_of.rb'
3366 *
3367 * # first the method hello
3368 * > RubyVM::InstructionSequence.of(method(:hello))
3369 * > #=> #<RubyVM::InstructionSequence:0x007fb73d7cb1d0>
3370 *
3371 * # then the global proc
3372 * > RubyVM::InstructionSequence.of($a_global_proc)
3373 * > #=> #<RubyVM::InstructionSequence:0x007fb73d7caf78>
3374 */
3375static VALUE
3376iseqw_s_of(VALUE klass, VALUE body)
3377{
3378 const rb_iseq_t *iseq = NULL;
3379
3380 if (rb_frame_info_p(body)) {
3381 iseq = rb_get_iseq_from_frame_info(body);
3382 }
3383 else if (rb_obj_is_proc(body)) {
3384 iseq = vm_proc_iseq(body);
3385
3386 if (!rb_obj_is_iseq((VALUE)iseq)) {
3387 iseq = NULL;
3388 }
3389 }
3390 else if (rb_obj_is_method(body)) {
3391 iseq = rb_method_iseq(body);
3392 }
3393 else if (rb_typeddata_is_instance_of(body, &iseqw_data_type)) {
3394 return body;
3395 }
3396
3397 return iseq ? iseqw_new(iseq) : Qnil;
3398}
3399
3400/*
3401 * call-seq:
3402 * InstructionSequence.disasm(body) -> str
3403 * InstructionSequence.disassemble(body) -> str
3404 *
3405 * Takes +body+, a +Method+ or +Proc+ object, and returns a +String+
3406 * with the human readable instructions for +body+.
3407 *
3408 * For a +Method+ object:
3409 *
3410 * # /tmp/method.rb
3411 * def hello
3412 * puts "hello, world"
3413 * end
3414 *
3415 * puts RubyVM::InstructionSequence.disasm(method(:hello))
3416 *
3417 * Produces:
3418 *
3419 * == disasm: <RubyVM::InstructionSequence:hello@/tmp/method.rb>============
3420 * 0000 trace 8 ( 1)
3421 * 0002 trace 1 ( 2)
3422 * 0004 putself
3423 * 0005 dupstring "hello, world"
3424 * 0007 send :puts, 1, nil, 8, <ic:0>
3425 * 0013 trace 16 ( 3)
3426 * 0015 leave ( 2)
3427 *
3428 * For a +Proc+ object:
3429 *
3430 * # /tmp/proc.rb
3431 * p = proc { num = 1 + 2 }
3432 * puts RubyVM::InstructionSequence.disasm(p)
3433 *
3434 * Produces:
3435 *
3436 * == disasm: <RubyVM::InstructionSequence:block in <main>@/tmp/proc.rb>===
3437 * == catch table
3438 * | catch type: redo st: 0000 ed: 0012 sp: 0000 cont: 0000
3439 * | catch type: next st: 0000 ed: 0012 sp: 0000 cont: 0012
3440 * |------------------------------------------------------------------------
3441 * local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1] s1)
3442 * [ 2] num
3443 * 0000 trace 1 ( 1)
3444 * 0002 putobject 1
3445 * 0004 putobject 2
3446 * 0006 opt_plus <ic:1>
3447 * 0008 dup
3448 * 0009 setlocal num, 0
3449 * 0012 leave
3450 *
3451 */
3452static VALUE
3453iseqw_s_disasm(VALUE klass, VALUE body)
3454{
3455 VALUE iseqw = iseqw_s_of(klass, body);
3456 return NIL_P(iseqw) ? Qnil : rb_iseq_disasm(iseqw_check(iseqw));
3457}
3458
3459static VALUE
3460register_label(struct st_table *table, unsigned long idx)
3461{
3462 VALUE sym = rb_str_intern(rb_sprintf("label_%lu", idx));
3463 st_insert(table, idx, sym);
3464 return sym;
3465}
3466
3467static VALUE
3468exception_type2symbol(VALUE type)
3469{
3470 ID id;
3471 switch (type) {
3472 case CATCH_TYPE_RESCUE: CONST_ID(id, "rescue"); break;
3473 case CATCH_TYPE_ENSURE: CONST_ID(id, "ensure"); break;
3474 case CATCH_TYPE_RETRY: CONST_ID(id, "retry"); break;
3475 case CATCH_TYPE_BREAK: CONST_ID(id, "break"); break;
3476 case CATCH_TYPE_REDO: CONST_ID(id, "redo"); break;
3477 case CATCH_TYPE_NEXT: CONST_ID(id, "next"); break;
3478 default:
3479 rb_bug("unknown exception type: %d", (int)type);
3480 }
3481 return ID2SYM(id);
3482}
3483
3484static int
3485cdhash_each(VALUE key, VALUE value, VALUE ary)
3486{
3487 rb_ary_push(ary, obj_resurrect(key));
3488 rb_ary_push(ary, INT2FIX(value));
3489 return ST_CONTINUE;
3490}
3491
3492static const rb_data_type_t label_wrapper = {
3493 "label_wrapper",
3494 {(void (*)(void *))rb_mark_tbl, (void (*)(void *))st_free_table, 0, 0,},
3495 0, 0, RUBY_TYPED_THREAD_SAFE_FREE
3496};
3497
3498#define DECL_ID(name) \
3499 static ID id_##name
3500
3501#define INIT_ID(name) \
3502 id_##name = rb_intern(#name)
3503
3504static VALUE
3505iseq_type_id(enum rb_iseq_type type)
3506{
3507 DECL_ID(top);
3508 DECL_ID(method);
3509 DECL_ID(block);
3510 DECL_ID(class);
3511 DECL_ID(rescue);
3512 DECL_ID(ensure);
3513 DECL_ID(eval);
3514 DECL_ID(main);
3515 DECL_ID(plain);
3516
3517 if (id_top == 0) {
3518 INIT_ID(top);
3519 INIT_ID(method);
3520 INIT_ID(block);
3521 INIT_ID(class);
3522 INIT_ID(rescue);
3523 INIT_ID(ensure);
3524 INIT_ID(eval);
3525 INIT_ID(main);
3526 INIT_ID(plain);
3527 }
3528
3529 switch (type) {
3530 case ISEQ_TYPE_TOP: return id_top;
3531 case ISEQ_TYPE_METHOD: return id_method;
3532 case ISEQ_TYPE_BLOCK: return id_block;
3533 case ISEQ_TYPE_CLASS: return id_class;
3534 case ISEQ_TYPE_RESCUE: return id_rescue;
3535 case ISEQ_TYPE_ENSURE: return id_ensure;
3536 case ISEQ_TYPE_EVAL: return id_eval;
3537 case ISEQ_TYPE_MAIN: return id_main;
3538 case ISEQ_TYPE_PLAIN: return id_plain;
3539 };
3540
3541 rb_bug("unsupported iseq type: %d", (int)type);
3542}
3543
3544static VALUE
3545iseq_data_to_ary(const rb_iseq_t *iseq)
3546{
3547 VALUE iseq_value = (VALUE)iseq;
3548 unsigned int i;
3549 rb_len_t l;
3550 const struct rb_iseq_constant_body *const iseq_body = ISEQ_BODY(iseq);
3551 const struct iseq_insn_info_entry *prev_insn_info;
3552 unsigned int pos;
3553 int last_line = 0;
3554 VALUE *seq, *iseq_original;
3555
3556 VALUE val = rb_ary_new();
3557 ID type; /* Symbol */
3558 VALUE locals = rb_ary_new();
3559 VALUE params = rb_hash_new();
3560 VALUE body = rb_ary_new(); /* [[:insn1, ...], ...] */
3561 VALUE nbody;
3562 VALUE exception = rb_ary_new(); /* [[....]] */
3563 VALUE misc = rb_hash_new();
3564
3565 static ID insn_syms[VM_BARE_INSTRUCTION_SIZE]; /* w/o-trace only */
3566 struct st_table *labels_table = st_init_numtable();
3567 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &label_wrapper, labels_table);
3568
3569 if (insn_syms[0] == 0) {
3570 int i;
3571 for (i=0; i<numberof(insn_syms); i++) {
3572 insn_syms[i] = rb_intern(insn_name(i));
3573 }
3574 }
3575
3576 /* type */
3577 type = iseq_type_id(iseq_body->type);
3578
3579 /* locals */
3580 for (i=0; i<iseq_body->local_table_size; i++) {
3581 ID lid = iseq_body->local_table[i];
3582 if (lid) {
3583 if (lid != idItImplicit && rb_id2str(lid)) {
3584 rb_ary_push(locals, ID2SYM(lid));
3585 }
3586 else { /* hidden variable from id_internal() */
3587 rb_ary_push(locals, ULONG2NUM(iseq_body->local_table_size-i+1));
3588 }
3589 }
3590 else {
3591 rb_ary_push(locals, ID2SYM(rb_intern("#arg_rest")));
3592 }
3593 }
3594
3595 /* params */
3596 {
3597 const struct rb_iseq_param_keyword *const keyword = iseq_body->param.keyword;
3598 int j;
3599
3600 if (iseq_body->param.flags.has_opt) {
3601 int len = iseq_body->param.opt_num + 1;
3602 VALUE arg_opt_labels = rb_ary_new2(len);
3603
3604 for (j = 0; j < len; j++) {
3605 VALUE l = register_label(labels_table, iseq_body->param.opt_table[j]);
3606 rb_ary_push(arg_opt_labels, l);
3607 }
3608 rb_hash_aset(params, ID2SYM(rb_intern("opt")), arg_opt_labels);
3609 }
3610
3611 /* commit */
3612 if (iseq_body->param.flags.has_lead) rb_hash_aset(params, ID2SYM(rb_intern("lead_num")), INT2FIX(iseq_body->param.lead_num));
3613 if (iseq_body->param.flags.has_post) rb_hash_aset(params, ID2SYM(rb_intern("post_num")), INT2FIX(iseq_body->param.post_num));
3614 if (iseq_body->param.flags.has_post) rb_hash_aset(params, ID2SYM(rb_intern("post_start")), INT2FIX(iseq_body->param.post_start));
3615 if (iseq_body->param.flags.has_rest) rb_hash_aset(params, ID2SYM(rb_intern("rest_start")), INT2FIX(iseq_body->param.rest_start));
3616 if (iseq_body->param.flags.has_block) rb_hash_aset(params, ID2SYM(rb_intern("block_start")), INT2FIX(iseq_body->param.block_start));
3617 if (iseq_body->param.flags.has_kw) {
3618 VALUE keywords = rb_ary_new();
3619 int i, j;
3620 for (i=0; i<keyword->required_num; i++) {
3621 rb_ary_push(keywords, ID2SYM(keyword->table[i]));
3622 }
3623 for (j=0; i<keyword->num; i++, j++) {
3624 VALUE key = rb_ary_new_from_args(1, ID2SYM(keyword->table[i]));
3625 if (!UNDEF_P(keyword->default_values[j])) {
3626 rb_ary_push(key, keyword->default_values[j]);
3627 }
3628 rb_ary_push(keywords, key);
3629 }
3630
3631 rb_hash_aset(params, ID2SYM(rb_intern("kwbits")),
3632 INT2FIX(keyword->bits_start));
3633 rb_hash_aset(params, ID2SYM(rb_intern("keyword")), keywords);
3634 }
3635 if (iseq_body->param.flags.has_kwrest) rb_hash_aset(params, ID2SYM(rb_intern("kwrest")), INT2FIX(keyword->rest_start));
3636 if (iseq_body->param.flags.ambiguous_param0) rb_hash_aset(params, ID2SYM(rb_intern("ambiguous_param0")), Qtrue);
3637 if (iseq_body->param.flags.use_block) rb_hash_aset(params, ID2SYM(rb_intern("use_block")), Qtrue);
3638 }
3639
3640 /* body */
3641 iseq_original = rb_iseq_original_iseq((rb_iseq_t *)iseq);
3642
3643 for (seq = iseq_original; seq < iseq_original + iseq_body->iseq_size; ) {
3644 VALUE insn = *seq++;
3645 int j, len = insn_len(insn);
3646 VALUE *nseq = seq + len - 1;
3647 VALUE ary = rb_ary_new2(len);
3648
3649 rb_ary_push(ary, ID2SYM(insn_syms[insn%numberof(insn_syms)]));
3650 for (j=0; j<len-1; j++, seq++) {
3651 enum ruby_insn_type_chars op_type = insn_op_type(insn, j);
3652
3653 switch (op_type) {
3654 case TS_OFFSET: {
3655 unsigned long idx = nseq - iseq_original + *seq;
3656 rb_ary_push(ary, register_label(labels_table, idx));
3657 break;
3658 }
3659 case TS_LINDEX:
3660 case TS_NUM:
3661 rb_ary_push(ary, INT2FIX(*seq));
3662 break;
3663 case TS_VALUE:
3664 rb_ary_push(ary, obj_resurrect(*seq));
3665 break;
3666 case TS_ISEQ:
3667 {
3668 const rb_iseq_t *iseq = (rb_iseq_t *)*seq;
3669 if (iseq) {
3670 VALUE val = iseq_data_to_ary(rb_iseq_check(iseq));
3671 rb_ary_push(ary, val);
3672 }
3673 else {
3674 rb_ary_push(ary, Qnil);
3675 }
3676 }
3677 break;
3678 case TS_IC:
3679 {
3680 VALUE list = rb_ary_new();
3681 const ID *ids = ((IC)*seq)->segments;
3682 while (*ids) {
3683 rb_ary_push(list, ID2SYM(*ids++));
3684 }
3685 rb_ary_push(ary, list);
3686 }
3687 break;
3688 case TS_IVC:
3689 case TS_ICVARC:
3690 case TS_ISE:
3691 {
3692 union iseq_inline_storage_entry *is = (union iseq_inline_storage_entry *)*seq;
3693 rb_ary_push(ary, INT2FIX(is - ISEQ_IS_ENTRY_START(ISEQ_BODY(iseq), op_type)));
3694 }
3695 break;
3696 case TS_CALLDATA:
3697 {
3698 struct rb_call_data *cd = (struct rb_call_data *)*seq;
3699 const struct rb_callinfo *ci = cd->ci;
3700 VALUE e = rb_hash_new();
3701 int argc = vm_ci_argc(ci);
3702
3703 ID mid = vm_ci_mid(ci);
3704 rb_hash_aset(e, ID2SYM(rb_intern("mid")), mid ? ID2SYM(mid) : Qnil);
3705 rb_hash_aset(e, ID2SYM(rb_intern("flag")), UINT2NUM(vm_ci_flag(ci)));
3706
3707 if (vm_ci_flag(ci) & VM_CALL_KWARG) {
3708 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
3709 int i;
3710 VALUE kw = rb_ary_new2((rb_len_t)kwarg->keyword_len);
3711
3712 argc -= kwarg->keyword_len;
3713 for (i = 0; i < kwarg->keyword_len; i++) {
3714 rb_ary_push(kw, kwarg->keywords[i]);
3715 }
3716 rb_hash_aset(e, ID2SYM(rb_intern("kw_arg")), kw);
3717 }
3718
3719 rb_hash_aset(e, ID2SYM(rb_intern("orig_argc")),
3720 INT2FIX(argc));
3721 rb_ary_push(ary, e);
3722 }
3723 break;
3724 case TS_ID:
3725 rb_ary_push(ary, ID2SYM(*seq));
3726 break;
3727 case TS_CDHASH:
3728 {
3729 VALUE cdhash = *seq;
3730 VALUE val = rb_ary_new();
3731 int i;
3732
3733 st_foreach(rb_imemo_cdhash_tbl(cdhash), cdhash_each, val);
3734
3735 for (i=0; i<RARRAY_LEN(val); i+=2) {
3736 VALUE pos = FIX2INT(rb_ary_entry(val, i+1));
3737 unsigned long idx = nseq - iseq_original + pos;
3738
3739 rb_ary_store(val, i+1,
3740 register_label(labels_table, idx));
3741 }
3742 rb_ary_push(ary, val);
3743 }
3744 break;
3745 case TS_FUNCPTR:
3746 {
3747#if SIZEOF_VALUE <= SIZEOF_LONG
3748 VALUE val = LONG2NUM((SIGNED_VALUE)*seq);
3749#else
3750 VALUE val = LL2NUM((SIGNED_VALUE)*seq);
3751#endif
3752 rb_ary_push(ary, val);
3753 }
3754 break;
3755 case TS_BUILTIN:
3756 {
3757 VALUE val = rb_hash_new();
3758#if SIZEOF_VALUE <= SIZEOF_LONG
3759 VALUE func_ptr = LONG2NUM((SIGNED_VALUE)((RB_BUILTIN)*seq)->func_ptr);
3760#else
3761 VALUE func_ptr = LL2NUM((SIGNED_VALUE)((RB_BUILTIN)*seq)->func_ptr);
3762#endif
3763 rb_hash_aset(val, ID2SYM(rb_intern("func_ptr")), func_ptr);
3764 rb_hash_aset(val, ID2SYM(rb_intern("argc")), INT2NUM(((RB_BUILTIN)*seq)->argc));
3765 rb_hash_aset(val, ID2SYM(rb_intern("index")), INT2NUM(((RB_BUILTIN)*seq)->index));
3766 rb_hash_aset(val, ID2SYM(rb_intern("name")), rb_str_new_cstr(((RB_BUILTIN)*seq)->name));
3767 rb_ary_push(ary, val);
3768 }
3769 break;
3770 default:
3771 rb_bug("unknown operand: %c", insn_op_type(insn, j));
3772 }
3773 }
3774 rb_ary_push(body, ary);
3775 }
3776
3777 nbody = body;
3778
3779 /* exception */
3780 if (iseq_body->catch_table) for (i=0; i<iseq_body->catch_table->size; i++) {
3781 VALUE ary = rb_ary_new();
3782 const struct iseq_catch_table_entry *entry =
3783 UNALIGNED_MEMBER_PTR(iseq_body->catch_table, entries[i]);
3784 rb_ary_push(ary, exception_type2symbol(entry->type));
3785 if (entry->iseq) {
3786 rb_ary_push(ary, iseq_data_to_ary(rb_iseq_check(entry->iseq)));
3787 }
3788 else {
3789 rb_ary_push(ary, Qnil);
3790 }
3791 rb_ary_push(ary, register_label(labels_table, entry->start));
3792 rb_ary_push(ary, register_label(labels_table, entry->end));
3793 rb_ary_push(ary, register_label(labels_table, entry->cont));
3794 rb_ary_push(ary, UINT2NUM(entry->sp));
3795 rb_ary_push(exception, ary);
3796 }
3797
3798 /* make body with labels and insert line number */
3799 body = rb_ary_new();
3800 prev_insn_info = NULL;
3801#ifdef USE_ISEQ_NODE_ID
3802 VALUE node_ids = rb_ary_new();
3803 const uint8_t *nid_ptr = iseq_body->insns_info.node_ids;
3804 const uint8_t *nid_end = nid_ptr ? nid_ptr + iseq_body->insns_info.node_ids_size : NULL;
3805 int node_id = 0;
3806#endif
3807
3808 for (l=0, pos=0; l<RARRAY_LEN(nbody); l++) {
3809 const struct iseq_insn_info_entry *info;
3810 VALUE ary = RARRAY_AREF(nbody, l);
3811 st_data_t label;
3812
3813 if (st_lookup(labels_table, pos, &label)) {
3814 rb_ary_push(body, (VALUE)label);
3815 }
3816
3817 info = get_insn_info(iseq, pos);
3818#ifdef USE_ISEQ_NODE_ID
3819 VM_ASSERT(nid_ptr && nid_ptr < nid_end);
3820 if (nid_ptr && nid_ptr < nid_end) {
3821 node_id += node_id_stream_read(&nid_ptr, nid_end);
3822 }
3823 rb_ary_push(node_ids, INT2FIX(node_id));
3824#endif
3825
3826 if (prev_insn_info != info) {
3827 int line = info->line_no;
3828 rb_event_flag_t events = info->events;
3829
3830 if (line > 0 && last_line != line) {
3831 rb_ary_push(body, INT2FIX(line));
3832 last_line = line;
3833 }
3834#define CHECK_EVENT(ev) if (events & ev) rb_ary_push(body, ID2SYM(rb_intern(#ev)));
3835 CHECK_EVENT(RUBY_EVENT_LINE);
3836 CHECK_EVENT(RUBY_EVENT_CLASS);
3837 CHECK_EVENT(RUBY_EVENT_END);
3838 CHECK_EVENT(RUBY_EVENT_CALL);
3839 CHECK_EVENT(RUBY_EVENT_RETURN);
3840 CHECK_EVENT(RUBY_EVENT_B_CALL);
3841 CHECK_EVENT(RUBY_EVENT_B_RETURN);
3842 CHECK_EVENT(RUBY_EVENT_RESCUE);
3843#undef CHECK_EVENT
3844 prev_insn_info = info;
3845 }
3846
3847 rb_ary_push(body, ary);
3848 pos += RARRAY_LENINT(ary); /* reject too huge data */
3849 }
3850 RB_GC_GUARD(nbody);
3851 RB_GC_GUARD(labels_wrapper);
3852
3853 rb_hash_aset(misc, ID2SYM(rb_intern("arg_size")), INT2FIX(iseq_body->param.size));
3854 rb_hash_aset(misc, ID2SYM(rb_intern("local_size")), INT2FIX(iseq_body->local_table_size));
3855 rb_hash_aset(misc, ID2SYM(rb_intern("stack_max")), INT2FIX(iseq_body->stack_max));
3856 rb_hash_aset(misc, ID2SYM(rb_intern("node_id")), INT2FIX(iseq_body->location.node_id));
3857 rb_hash_aset(misc, ID2SYM(rb_intern("source_hash")), iseq_body->source_hash ? ULL2NUM(iseq_body->source_hash) : Qnil);
3858 rb_hash_aset(misc, ID2SYM(rb_intern("code_location")),
3859 rb_ary_new_from_args(4,
3860 INT2FIX(iseq_body->location.code_location.beg_pos.lineno),
3861 INT2FIX(iseq_body->location.code_location.beg_pos.column),
3862 INT2FIX(iseq_body->location.code_location.end_pos.lineno),
3863 INT2FIX(iseq_body->location.code_location.end_pos.column)));
3864#ifdef USE_ISEQ_NODE_ID
3865 rb_hash_aset(misc, ID2SYM(rb_intern("node_ids")), node_ids);
3866#endif
3867 rb_hash_aset(misc, ID2SYM(rb_intern("parser")), iseq_body->prism ? ID2SYM(rb_intern("prism")) : ID2SYM(rb_intern("parse.y")));
3868
3869 /*
3870 * [:magic, :major_version, :minor_version, :format_type, :misc,
3871 * :name, :path, :absolute_path, :start_lineno, :type, :locals, :args,
3872 * :catch_table, :bytecode]
3873 */
3874 rb_ary_push(val, rb_str_new2("YARVInstructionSequence/SimpleDataFormat"));
3875 rb_ary_push(val, INT2FIX(ISEQ_MAJOR_VERSION)); /* major */
3876 rb_ary_push(val, INT2FIX(ISEQ_MINOR_VERSION)); /* minor */
3877 rb_ary_push(val, INT2FIX(1));
3878 rb_ary_push(val, misc);
3879 rb_ary_push(val, iseq_body->location.label);
3880 rb_ary_push(val, rb_iseq_path(iseq));
3881 rb_ary_push(val, rb_iseq_realpath(iseq));
3882 rb_ary_push(val, RB_INT2NUM(iseq_body->location.first_lineno));
3883 rb_ary_push(val, ID2SYM(type));
3884 rb_ary_push(val, locals);
3885 rb_ary_push(val, params);
3886 rb_ary_push(val, exception);
3887 rb_ary_push(val, body);
3888
3889 RB_GC_GUARD(iseq_value);
3890
3891 return val;
3892}
3893
3894VALUE
3895rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
3896{
3897 int i, r;
3898 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
3899 const struct rb_iseq_param_keyword *const keyword = body->param.keyword;
3900 VALUE a, args = rb_ary_new2(body->param.size);
3901 ID req, opt, rest, block, key, keyrest;
3902#define PARAM_TYPE(type) rb_ary_push(a = rb_ary_new2(2), ID2SYM(type))
3903#define PARAM_ID(i) body->local_table[(i)]
3904#define PARAM(i, type) ( \
3905 PARAM_TYPE(type), \
3906 PARAM_ID(i) != idItImplicit && rb_id2str(PARAM_ID(i)) ? \
3907 rb_ary_push(a, ID2SYM(PARAM_ID(i))) : \
3908 a)
3909
3910 CONST_ID(req, "req");
3911 CONST_ID(opt, "opt");
3912
3913 if (body->param.flags.forwardable) {
3914 // [[:rest, :*], [:keyrest, :**], [:block, :&]]
3915 CONST_ID(rest, "rest");
3916 CONST_ID(keyrest, "keyrest");
3917 CONST_ID(block, "block");
3918 rb_ary_push(args, rb_ary_new_from_args(2, ID2SYM(rest), ID2SYM(idMULT)));
3919 rb_ary_push(args, rb_ary_new_from_args(2, ID2SYM(keyrest), ID2SYM(idPow)));
3920 rb_ary_push(args, rb_ary_new_from_args(2, ID2SYM(block), ID2SYM(idAnd)));
3921 }
3922
3923 if (is_proc) {
3924 for (i = 0; i < body->param.lead_num; i++) {
3925 rb_ary_push(args, PARAM(i, opt));
3926 }
3927 }
3928 else {
3929 for (i = 0; i < body->param.lead_num; i++) {
3930 rb_ary_push(args, PARAM(i, req));
3931 }
3932 }
3933 r = body->param.lead_num + body->param.opt_num;
3934 for (; i < r; i++) {
3935 rb_ary_push(args, PARAM(i, opt));
3936 }
3937 if (body->param.flags.has_rest) {
3938 CONST_ID(rest, "rest");
3939 rb_ary_push(args, PARAM(body->param.rest_start, rest));
3940 }
3941 r = body->param.post_start + body->param.post_num;
3942 if (is_proc) {
3943 for (i = body->param.post_start; i < r; i++) {
3944 rb_ary_push(args, PARAM(i, opt));
3945 }
3946 }
3947 else {
3948 for (i = body->param.post_start; i < r; i++) {
3949 rb_ary_push(args, PARAM(i, req));
3950 }
3951 }
3952 if (body->param.flags.accepts_no_kwarg) {
3953 ID nokey;
3954 CONST_ID(nokey, "nokey");
3955 PARAM_TYPE(nokey);
3956 rb_ary_push(args, a);
3957 }
3958 if (body->param.flags.has_kw) {
3959 i = 0;
3960 if (keyword->required_num > 0) {
3961 ID keyreq;
3962 CONST_ID(keyreq, "keyreq");
3963 for (; i < keyword->required_num; i++) {
3964 PARAM_TYPE(keyreq);
3965 if (rb_id2str(keyword->table[i])) {
3966 rb_ary_push(a, ID2SYM(keyword->table[i]));
3967 }
3968 rb_ary_push(args, a);
3969 }
3970 }
3971 CONST_ID(key, "key");
3972 for (; i < keyword->num; i++) {
3973 PARAM_TYPE(key);
3974 if (rb_id2str(keyword->table[i])) {
3975 rb_ary_push(a, ID2SYM(keyword->table[i]));
3976 }
3977 rb_ary_push(args, a);
3978 }
3979 }
3980 if (body->param.flags.has_kwrest || body->param.flags.ruby2_keywords) {
3981 ID param;
3982 CONST_ID(keyrest, "keyrest");
3983 PARAM_TYPE(keyrest);
3984 if (body->param.flags.has_kwrest &&
3985 rb_id2str(param = PARAM_ID(keyword->rest_start))) {
3986 rb_ary_push(a, ID2SYM(param));
3987 }
3988 else if (body->param.flags.ruby2_keywords) {
3989 rb_ary_push(a, ID2SYM(idPow));
3990 }
3991 rb_ary_push(args, a);
3992 }
3993 if (body->param.flags.accepts_no_block) {
3994 ID noblock;
3995 CONST_ID(noblock, "noblock");
3996 PARAM_TYPE(noblock);
3997 rb_ary_push(args, a);
3998 }
3999 else if (body->param.flags.has_block) {
4000 CONST_ID(block, "block");
4001 rb_ary_push(args, PARAM(body->param.block_start, block));
4002 }
4003 return args;
4004}
4005
4006VALUE
4007rb_iseq_defined_string(enum defined_type type)
4008{
4009 static const char expr_names[][18] = {
4010 "nil",
4011 "instance-variable",
4012 "local-variable",
4013 "global-variable",
4014 "class variable",
4015 "constant",
4016 "method",
4017 "yield",
4018 "super",
4019 "self",
4020 "true",
4021 "false",
4022 "assignment",
4023 "expression",
4024 };
4025 const char *estr;
4026
4027 if ((unsigned)(type - 1) >= (unsigned)numberof(expr_names)) rb_bug("unknown defined type %d", type);
4028 estr = expr_names[type - 1];
4029 return rb_fstring_cstr(estr);
4030}
4031
4032// A map from encoded_insn to insn_data: decoded insn number, its len,
4033// decoded ZJIT insn number, non-trace version of encoded insn,
4034// trace version, and zjit version.
4035static st_table *encoded_insn_data;
4036typedef struct insn_data_struct {
4037 int insn;
4038 int insn_len;
4039 void *notrace_encoded_insn;
4040 void *trace_encoded_insn;
4041#if USE_ZJIT
4042 int zjit_insn;
4043 void *zjit_encoded_insn;
4044#endif
4045} insn_data_t;
4046static insn_data_t insn_data[VM_BARE_INSTRUCTION_SIZE];
4047
4048void
4049rb_free_encoded_insn_data(void)
4050{
4051 st_free_table(encoded_insn_data);
4052}
4053
4054// Initialize a table to decode bare, trace, and zjit instructions.
4055// This function also determines which instructions are used when TracePoint is enabled.
4056void
4057rb_vm_encoded_insn_data_table_init(void)
4058{
4059#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
4060 const void * const *table = rb_vm_get_insns_address_table();
4061#define INSN_CODE(insn) ((VALUE)table[insn])
4062#else
4063#define INSN_CODE(insn) ((VALUE)(insn))
4064#endif
4065 encoded_insn_data = st_init_numtable_with_size(VM_BARE_INSTRUCTION_SIZE);
4066
4067 for (int insn = 0; insn < VM_BARE_INSTRUCTION_SIZE; insn++) {
4068 insn_data[insn].insn = insn;
4069 insn_data[insn].insn_len = insn_len(insn);
4070
4071 // When tracing :return events, we convert opt_invokebuiltin_delegate_leave + leave into
4072 // opt_invokebuiltin_delegate + trace_leave, presumably because we don't want to fire
4073 // :return events before invokebuiltin. https://github.com/ruby/ruby/pull/3256
4074 int notrace_insn = (insn != BIN(opt_invokebuiltin_delegate_leave)) ? insn : BIN(opt_invokebuiltin_delegate);
4075 insn_data[insn].notrace_encoded_insn = (void *)INSN_CODE(notrace_insn);
4076 insn_data[insn].trace_encoded_insn = (void *)INSN_CODE(notrace_insn + VM_BARE_INSTRUCTION_SIZE);
4077
4078 st_data_t key1 = (st_data_t)INSN_CODE(insn);
4079 st_data_t key2 = (st_data_t)INSN_CODE(insn + VM_BARE_INSTRUCTION_SIZE);
4080 st_add_direct(encoded_insn_data, key1, (st_data_t)&insn_data[insn]);
4081 st_add_direct(encoded_insn_data, key2, (st_data_t)&insn_data[insn]);
4082
4083#if USE_ZJIT
4084 int zjit_insn = vm_bare_insn_to_zjit_insn(insn);
4085 insn_data[insn].zjit_insn = zjit_insn;
4086 insn_data[insn].zjit_encoded_insn = (insn != zjit_insn) ? (void *)INSN_CODE(zjit_insn) : 0;
4087
4088 if (insn != zjit_insn) {
4089 st_data_t key3 = (st_data_t)INSN_CODE(zjit_insn);
4090 st_add_direct(encoded_insn_data, key3, (st_data_t)&insn_data[insn]);
4091 }
4092#endif
4093 }
4094}
4095
4096// Decode an insn address to an insn. This returns bare instructions
4097// even if they're trace/zjit instructions. Use rb_vm_insn_addr2opcode
4098// to decode trace/zjit instructions as is.
4099int
4100rb_vm_insn_addr2insn(const void *addr)
4101{
4102 st_data_t key = (st_data_t)addr;
4103 st_data_t val;
4104
4105 if (st_lookup(encoded_insn_data, key, &val)) {
4106 insn_data_t *e = (insn_data_t *)val;
4107 return (int)e->insn;
4108 }
4109
4110 rb_bug("rb_vm_insn_addr2insn: invalid insn address: %p", addr);
4111}
4112
4113// Decode an insn address to an insn. Unlike rb_vm_insn_addr2insn,
4114// this function can return trace/zjit opcode variants.
4115int
4116rb_vm_insn_addr2opcode(const void *addr)
4117{
4118 st_data_t key = (st_data_t)addr;
4119 st_data_t val;
4120
4121 if (st_lookup(encoded_insn_data, key, &val)) {
4122 insn_data_t *e = (insn_data_t *)val;
4123 int opcode = e->insn;
4124 if (addr == e->trace_encoded_insn) {
4125 opcode += VM_BARE_INSTRUCTION_SIZE;
4126 }
4127#if USE_ZJIT
4128 else if (addr == e->zjit_encoded_insn) {
4129 opcode = e->zjit_insn;
4130 }
4131#endif
4132 return opcode;
4133 }
4134
4135 rb_bug("rb_vm_insn_addr2opcode: invalid insn address: %p", addr);
4136}
4137
4138// Decode `ISEQ_BODY(iseq)->iseq_encoded[i]` to an insn. This returns
4139// bare instructions even if they're trace/zjit instructions. Use
4140// rb_vm_insn_addr2opcode to decode trace/zjit instructions as is.
4141int
4142rb_vm_insn_decode(const VALUE encoded)
4143{
4144 return rb_vm_insn_addr2insn((void *)encoded);
4145}
4146
4147// Turn on or off tracing for a given instruction address
4148static inline int
4149encoded_iseq_trace_instrument(VALUE *iseq_encoded_insn, rb_event_flag_t turnon, bool remain_traced)
4150{
4151 st_data_t key = (st_data_t)*iseq_encoded_insn;
4152 st_data_t val;
4153
4154 if (st_lookup(encoded_insn_data, key, &val)) {
4155 insn_data_t *e = (insn_data_t *)val;
4156 if (remain_traced && key == (st_data_t)e->trace_encoded_insn) {
4157 turnon = 1;
4158 }
4159 *iseq_encoded_insn = (VALUE) (turnon ? e->trace_encoded_insn : e->notrace_encoded_insn);
4160 return e->insn_len;
4161 }
4162
4163 rb_bug("trace_instrument: invalid insn address: %p", (void *)*iseq_encoded_insn);
4164}
4165
4166// Turn off tracing for an instruction at pos after tracing event flags are cleared
4167static void
4168rb_iseq_trace_flag_cleared(const rb_iseq_t *iseq, size_t pos)
4169{
4170 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
4171 VALUE *iseq_encoded = (VALUE *)body->iseq_encoded;
4172 encoded_iseq_trace_instrument(&iseq_encoded[pos], 0, false);
4173}
4174
4175// We need to fire call events on instructions with b_call events if the block
4176// is running as a method. So, if we are listening for call events, then
4177// instructions that have b_call events need to become trace variants.
4178// Use this function when making decisions about recompiling to trace variants.
4179static inline rb_event_flag_t
4180add_bmethod_events(rb_event_flag_t events)
4181{
4182 if (events & RUBY_EVENT_CALL) {
4183 events |= RUBY_EVENT_B_CALL;
4184 }
4185 if (events & RUBY_EVENT_RETURN) {
4186 events |= RUBY_EVENT_B_RETURN;
4187 }
4188 return events;
4189}
4190
4191// Note, to support call/return events for bmethods, turnon_event can have more events than tpval.
4192static int
4193iseq_add_local_tracepoint(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval, unsigned int target_line, rb_ractor_t *r)
4194{
4195 unsigned int pc;
4196 int n = 0;
4197 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
4198 VALUE *iseq_encoded = (VALUE *)body->iseq_encoded;
4199 rb_iseq_t *iseq_mut = (rb_iseq_t*)iseq;
4200
4201 VM_ASSERT(ISEQ_EXECUTABLE_P(iseq));
4202 ASSERT_vm_locking_with_barrier();
4203
4204 for (pc=0; pc<body->iseq_size;) {
4205 const struct iseq_insn_info_entry *entry = get_insn_info(iseq, pc);
4206 rb_event_flag_t pc_events = entry->events;
4207 rb_event_flag_t target_events = turnon_events;
4208 unsigned int line = (int)entry->line_no;
4209
4210 if (target_line == 0 || target_line == line) {
4211 /* ok */
4212 }
4213 else {
4214 target_events &= ~RUBY_EVENT_LINE;
4215 }
4216
4217 if (pc_events & target_events) {
4218 n++;
4219 }
4220 pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & (target_events | iseq->aux.exec.global_trace_events), true);
4221 }
4222
4223 if (n > 0) {
4224 rb_hook_list_t *hook_list = rb_iseq_local_hooks(iseq, r, true);
4225 rb_hook_list_connect_local_tracepoint(hook_list, tpval, target_line);
4226 iseq_mut->aux.exec.local_hooks_cnt++;
4227 }
4228
4229 return n;
4230}
4231
4233 rb_event_flag_t turnon_events;
4234 VALUE tpval;
4235 unsigned int target_line;
4236 int n;
4237 rb_ractor_t *r;
4238};
4239
4240static void
4241iseq_add_local_tracepoint_i(const rb_iseq_t *iseq, void *p)
4242{
4244 data->n += iseq_add_local_tracepoint(iseq, data->turnon_events, data->tpval, data->target_line, data->r);
4245 iseq_iterate_children(iseq, iseq_add_local_tracepoint_i, p);
4246}
4247
4248int
4249rb_iseq_add_local_tracepoint_recursively(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval, unsigned int target_line, bool target_bmethod)
4250{
4251 ASSERT_vm_locking_with_barrier();
4253 if (target_bmethod) {
4254 turnon_events = add_bmethod_events(turnon_events);
4255 }
4256 data.turnon_events = turnon_events;
4257 data.tpval = tpval;
4258 data.target_line = target_line;
4259 data.n = 0;
4260 data.r = GET_RACTOR();
4261
4262 iseq_add_local_tracepoint_i(iseq, (void *)&data);
4263 if (0) {
4264 VALUE disasm = rb_iseq_disasm(iseq);
4265 fprintf(stderr, "Iseq disasm:\n:%.*s",
4266 RSTRING_LENINT(disasm), RSTRING_PTR(disasm));
4267 }
4268 return data.n;
4269}
4270
4271static int
4272iseq_remove_local_tracepoint(const rb_iseq_t *iseq, VALUE tpval, rb_ractor_t *r)
4273{
4274 int n = 0;
4275 unsigned int num_hooks_left;
4276 unsigned int pc;
4277 const struct rb_iseq_constant_body *body;
4278 rb_iseq_t *iseq_mut = (rb_iseq_t*)iseq;
4279 rb_hook_list_t *hook_list;
4280 VALUE *iseq_encoded;
4281 ASSERT_vm_locking_with_barrier();
4282
4283 hook_list = rb_iseq_local_hooks(iseq, r, false);
4284
4285 if (hook_list) {
4286 rb_event_flag_t local_events = 0;
4287
4288 rb_event_flag_t prev_events = hook_list->events;
4289 if (rb_hook_list_remove_local_tracepoint(hook_list, tpval)) {
4290 RUBY_ASSERT(iseq->aux.exec.local_hooks_cnt > 0);
4291 iseq_mut->aux.exec.local_hooks_cnt--;
4292 local_events = hook_list->events; // remaining events for this ractor
4293 num_hooks_left = rb_hook_list_count(hook_list);
4294 if (local_events == 0 && prev_events != 0) {
4295 st_delete(rb_ractor_targeted_hooks(r), (st_data_t*)&iseq, NULL);
4296 rb_hook_list_free(hook_list);
4297 }
4298
4299 if (iseq->aux.exec.local_hooks_cnt == num_hooks_left) {
4300 body = ISEQ_BODY(iseq);
4301 iseq_encoded = (VALUE *)body->iseq_encoded;
4302 local_events = add_bmethod_events(local_events);
4303 for (pc = 0; pc<body->iseq_size;) {
4304 rb_event_flag_t pc_events = rb_iseq_event_flags(iseq, pc);
4305 pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & (local_events | iseq->aux.exec.global_trace_events), false);
4306 }
4307 }
4308
4309 n++;
4310 }
4311 }
4312 return n;
4313}
4314
4316 VALUE tpval;
4317 int n;
4318 rb_ractor_t *r;
4319};
4320
4321static void
4322iseq_remove_local_tracepoint_i(const rb_iseq_t *iseq, void *p)
4323{
4325 data->n += iseq_remove_local_tracepoint(iseq, data->tpval, data->r);
4326 iseq_iterate_children(iseq, iseq_remove_local_tracepoint_i, p);
4327}
4328
4329int
4330rb_iseq_remove_local_tracepoint_recursively(const rb_iseq_t *iseq, VALUE tpval, rb_ractor_t *r)
4331{
4333 ASSERT_vm_locking_with_barrier();
4334 data.tpval = tpval;
4335 data.n = 0;
4336 data.r = r;
4337
4338 iseq_remove_local_tracepoint_i(iseq, (void *)&data);
4339 return data.n;
4340}
4341
4342void
4343rb_iseq_trace_set(const rb_iseq_t *iseq, rb_event_flag_t turnon_events)
4344{
4345 if (iseq->aux.exec.global_trace_events == turnon_events) {
4346 return;
4347 }
4348
4349 if (!ISEQ_EXECUTABLE_P(iseq)) {
4350 /* this is building ISeq */
4351 return;
4352 }
4353 else {
4354 // NOTE: this does not need VM barrier if it's a new ISEQ
4355 unsigned int pc;
4356 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
4357
4358 VALUE *iseq_encoded = (VALUE *)body->iseq_encoded;
4359 rb_event_flag_t enabled_events;
4360 rb_hook_list_t *local_hooks = rb_iseq_local_hooks(iseq, GET_RACTOR(), false);
4361 rb_event_flag_t local_events = local_hooks ? local_hooks->events : 0;
4362 ((rb_iseq_t *)iseq)->aux.exec.global_trace_events = turnon_events;
4363 enabled_events = add_bmethod_events(turnon_events | local_events);
4364
4365 for (pc=0; pc<body->iseq_size;) {
4366 rb_event_flag_t pc_events = rb_iseq_event_flags(iseq, pc);
4367 pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & enabled_events, true);
4368 }
4369 }
4370}
4371
4372void rb_vm_cc_general(const struct rb_callcache *cc);
4373
4374static bool
4375clear_attr_cc(VALUE v)
4376{
4377 ASSERT_vm_locking_with_barrier();
4378 if (imemo_type_p(v, imemo_callcache) && vm_cc_ivar_p((const struct rb_callcache *)v)) {
4379 rb_vm_cc_general((struct rb_callcache *)v);
4380 return true;
4381 }
4382 else {
4383 return false;
4384 }
4385}
4386
4387static bool
4388clear_bf_cc(VALUE v)
4389{
4390 ASSERT_vm_locking_with_barrier();
4391 if (imemo_type_p(v, imemo_callcache) && vm_cc_bf_p((const struct rb_callcache *)v)) {
4392 rb_vm_cc_general((struct rb_callcache *)v);
4393 return true;
4394 }
4395 else {
4396 return false;
4397 }
4398}
4399
4400static int
4401clear_attr_ccs_i(void *vstart, void *vend, size_t stride, void *data)
4402{
4403 VALUE v = (VALUE)vstart;
4404 for (; v != (VALUE)vend; v += stride) {
4405 void *ptr = rb_asan_poisoned_object_p(v);
4406 rb_asan_unpoison_object(v, false);
4407 clear_attr_cc(v);
4408 asan_poison_object_if(ptr, v);
4409 }
4410 return 0;
4411}
4412
4413void
4414rb_clear_attr_ccs(void)
4415{
4416 rb_objspace_each_objects(clear_attr_ccs_i, NULL);
4417}
4418
4419static int
4420clear_bf_ccs_i(void *vstart, void *vend, size_t stride, void *data)
4421{
4422 VALUE v = (VALUE)vstart;
4423 for (; v != (VALUE)vend; v += stride) {
4424 void *ptr = rb_asan_poisoned_object_p(v);
4425 rb_asan_unpoison_object(v, false);
4426 clear_bf_cc(v);
4427 asan_poison_object_if(ptr, v);
4428 }
4429 return 0;
4430}
4431
4432void
4433rb_clear_bf_ccs(void)
4434{
4435 rb_objspace_each_objects(clear_bf_ccs_i, NULL);
4436}
4437
4438static int
4439trace_set_i(void *vstart, void *vend, size_t stride, void *data)
4440{
4441 rb_event_flag_t turnon_events = *(rb_event_flag_t *)data;
4442
4443 VALUE v = (VALUE)vstart;
4444 for (; v != (VALUE)vend; v += stride) {
4445 void *ptr = rb_asan_poisoned_object_p(v);
4446 rb_asan_unpoison_object(v, false);
4447
4448 if (rb_obj_is_iseq(v)) {
4449 rb_iseq_trace_set(rb_iseq_check((rb_iseq_t *)v), turnon_events);
4450 }
4451 else if (clear_attr_cc(v)) {
4452 }
4453 else if (clear_bf_cc(v)) {
4454 }
4455
4456 asan_poison_object_if(ptr, v);
4457 }
4458 return 0;
4459}
4460
4461void
4462rb_iseq_trace_set_all(rb_event_flag_t turnon_events)
4463{
4464 rb_objspace_each_objects(trace_set_i, &turnon_events);
4465}
4466
4467VALUE
4468rb_iseqw_local_variables(VALUE iseqval)
4469{
4470 return rb_iseq_local_variables(iseqw_check(iseqval));
4471}
4472
4473/*
4474 * call-seq:
4475 * iseq.to_binary(extra_data = nil) -> binary str
4476 *
4477 * Returns serialized iseq binary format data as a String object.
4478 * A corresponding iseq object is created by
4479 * RubyVM::InstructionSequence.load_from_binary() method.
4480 *
4481 * String extra_data will be saved with binary data.
4482 * You can access this data with
4483 * RubyVM::InstructionSequence.load_from_binary_extra_data(binary).
4484 *
4485 * Note that the translated binary data is not portable.
4486 * You can not move this binary data to another machine.
4487 * You can not use the binary data which is created by another
4488 * version/another architecture of Ruby.
4489 */
4490static VALUE
4491iseqw_to_binary(int argc, VALUE *argv, VALUE self)
4492{
4493 VALUE opt = !rb_check_arity(argc, 0, 1) ? Qnil : argv[0];
4494 return rb_iseq_ibf_dump(iseqw_check(self), opt);
4495}
4496
4497/*
4498 * call-seq:
4499 * RubyVM::InstructionSequence.load_from_binary(binary) -> iseq
4500 *
4501 * Load an iseq object from binary format String object
4502 * created by RubyVM::InstructionSequence.to_binary.
4503 *
4504 * This loader does not have a verifier, so that loading broken/modified
4505 * binary causes critical problem.
4506 *
4507 * You should not load binary data provided by others.
4508 * You should only use binary data translated by yourself.
4509 */
4510static VALUE
4511iseqw_s_load_from_binary(VALUE self, VALUE str)
4512{
4513 return iseqw_new(rb_iseq_ibf_load(str));
4514}
4515
4516VALUE
4517rb_iseq_load_from_binary(const char *ptr, size_t len)
4518{
4519 return iseqw_new(rb_iseq_ibf_load_bytes(ptr, len));
4520}
4521
4522/*
4523 * call-seq:
4524 * RubyVM::InstructionSequence.load_from_binary_extra_data(binary) -> str
4525 *
4526 * Load extra data embed into binary format String object.
4527 */
4528static VALUE
4529iseqw_s_load_from_binary_extra_data(VALUE self, VALUE str)
4530{
4531 return rb_iseq_ibf_load_extra_data(str);
4532}
4533
4534#if VM_INSN_INFO_TABLE_IMPL == 2
4535
4536/* An implementation of succinct bit-vector for insn_info table.
4537 *
4538 * A succinct bit-vector is a small and efficient data structure that provides
4539 * a bit-vector augmented with an index for O(1) rank operation:
4540 *
4541 * rank(bv, n): the number of 1's within a range from index 0 to index n
4542 *
4543 * This can be used to lookup insn_info table from PC.
4544 * For example, consider the following iseq and insn_info_table:
4545 *
4546 * iseq insn_info_table
4547 * PC insn+operand position lineno event
4548 * 0: insn1 0: 1 [Li]
4549 * 2: insn2 2: 2 [Li] <= (A)
4550 * 5: insn3 8: 3 [Li] <= (B)
4551 * 8: insn4
4552 *
4553 * In this case, a succinct bit-vector whose indexes 0, 2, 8 is "1" and
4554 * other indexes is "0", i.e., "101000001", is created.
4555 * To lookup the lineno of insn2, calculate rank("10100001", 2) = 2, so
4556 * the line (A) is the entry in question.
4557 * To lookup the lineno of insn4, calculate rank("10100001", 8) = 3, so
4558 * the line (B) is the entry in question.
4559 *
4560 * A naive implementation of succinct bit-vector works really well
4561 * not only for large size but also for small size. However, it has
4562 * tiny overhead for very small size. So, this implementation consist
4563 * of two parts: one part is the "immediate" table that keeps rank result
4564 * as a raw table, and the other part is a normal succinct bit-vector.
4565 */
4566
4567#define IMMEDIATE_TABLE_SIZE 54 /* a multiple of 9, and < 128 */
4568
4569struct succ_index_table {
4570 uint64_t imm_part[IMMEDIATE_TABLE_SIZE / 9];
4571 struct succ_dict_block {
4572 unsigned int rank;
4573 uint64_t small_block_ranks; /* 9 bits * 7 = 63 bits */
4574 uint64_t bits[512/64];
4575 } succ_part[FLEX_ARY_LEN];
4576};
4577
4578#define imm_block_rank_set(v, i, r) (v) |= (uint64_t)(r) << (7 * (i))
4579#define imm_block_rank_get(v, i) (((int)((v) >> ((i) * 7))) & 0x7f)
4580#define small_block_rank_set(v, i, r) (v) |= (uint64_t)(r) << (9 * ((i) - 1))
4581#define small_block_rank_get(v, i) ((i) == 0 ? 0 : (((int)((v) >> (((i) - 1) * 9))) & 0x1ff))
4582
4583static struct succ_index_table *
4584succ_index_table_create(int max_pos, int *data, int size)
4585{
4586 const int imm_size = (max_pos < IMMEDIATE_TABLE_SIZE ? max_pos + 8 : IMMEDIATE_TABLE_SIZE) / 9;
4587 const int succ_size = (max_pos < IMMEDIATE_TABLE_SIZE ? 0 : (max_pos - IMMEDIATE_TABLE_SIZE + 511)) / 512;
4588 struct succ_index_table *sd =
4589 rb_xcalloc_mul_add_mul(
4590 imm_size, sizeof(uint64_t),
4591 succ_size, sizeof(struct succ_dict_block));
4592 int i, j, k, r;
4593
4594 r = 0;
4595 for (j = 0; j < imm_size; j++) {
4596 for (i = 0; i < 9; i++) {
4597 if (r < size && data[r] == j * 9 + i) r++;
4598 imm_block_rank_set(sd->imm_part[j], i, r);
4599 }
4600 }
4601 for (k = 0; k < succ_size; k++) {
4602 struct succ_dict_block *sd_block = &sd->succ_part[k];
4603 int small_rank = 0;
4604 sd_block->rank = r;
4605 for (j = 0; j < 8; j++) {
4606 uint64_t bits = 0;
4607 if (j) small_block_rank_set(sd_block->small_block_ranks, j, small_rank);
4608 for (i = 0; i < 64; i++) {
4609 if (r < size && data[r] == k * 512 + j * 64 + i + IMMEDIATE_TABLE_SIZE) {
4610 bits |= ((uint64_t)1) << i;
4611 r++;
4612 }
4613 }
4614 sd_block->bits[j] = bits;
4615 small_rank += rb_popcount64(bits);
4616 }
4617 }
4618 return sd;
4619}
4620
4621static unsigned int *
4622succ_index_table_invert(int max_pos, struct succ_index_table *sd, int size)
4623{
4624 const int imm_size = (max_pos < IMMEDIATE_TABLE_SIZE ? max_pos + 8 : IMMEDIATE_TABLE_SIZE) / 9;
4625 const int succ_size = (max_pos < IMMEDIATE_TABLE_SIZE ? 0 : (max_pos - IMMEDIATE_TABLE_SIZE + 511)) / 512;
4626 unsigned int *positions = ALLOC_N(unsigned int, size), *p;
4627 int i, j, k, r = -1;
4628 p = positions;
4629 for (j = 0; j < imm_size; j++) {
4630 for (i = 0; i < 9; i++) {
4631 int nr = imm_block_rank_get(sd->imm_part[j], i);
4632 if (r != nr) *p++ = j * 9 + i;
4633 r = nr;
4634 }
4635 }
4636 for (k = 0; k < succ_size; k++) {
4637 for (j = 0; j < 8; j++) {
4638 for (i = 0; i < 64; i++) {
4639 if (sd->succ_part[k].bits[j] & (((uint64_t)1) << i)) {
4640 *p++ = k * 512 + j * 64 + i + IMMEDIATE_TABLE_SIZE;
4641 }
4642 }
4643 }
4644 }
4645 return positions;
4646}
4647
4648static int
4649succ_index_lookup(const struct succ_index_table *sd, int x)
4650{
4651 if (x < IMMEDIATE_TABLE_SIZE) {
4652 const int i = x / 9;
4653 const int j = x % 9;
4654 return imm_block_rank_get(sd->imm_part[i], j);
4655 }
4656 else {
4657 const int block_index = (x - IMMEDIATE_TABLE_SIZE) / 512;
4658 const struct succ_dict_block *block = &sd->succ_part[block_index];
4659 const int block_bit_index = (x - IMMEDIATE_TABLE_SIZE) % 512;
4660 const int small_block_index = block_bit_index / 64;
4661 const int small_block_popcount = small_block_rank_get(block->small_block_ranks, small_block_index);
4662 const int popcnt = rb_popcount64(block->bits[small_block_index] << (63 - block_bit_index % 64));
4663
4664 return block->rank + small_block_popcount + popcnt;
4665 }
4666}
4667#endif
4668
4669
4670/*
4671 * call-seq:
4672 * iseq.script_lines -> array or nil
4673 *
4674 * It returns recorded script lines if it is available.
4675 * The script lines are not limited to the iseq range, but
4676 * are entire lines of the source file.
4677 *
4678 * Note that this is an API for ruby internal use, debugging,
4679 * and research. Do not use this for any other purpose.
4680 * The compatibility is not guaranteed.
4681 */
4682static VALUE
4683iseqw_script_lines(VALUE self)
4684{
4685 const rb_iseq_t *iseq = iseqw_check(self);
4686 return ISEQ_SCRIPT_LINES(iseq);
4687}
4688
4689/* Returns the hash of the source this iseq was compiled from, or nil if it
4690 * is unavailable. */
4691static VALUE
4692iseqw_source_hash(VALUE self)
4693{
4694 const rb_iseq_t *iseq = iseqw_check(self);
4695 if (!ISEQ_BODY(iseq)->source_hash) return Qnil;
4696 return ULL2NUM(ISEQ_BODY(iseq)->source_hash);
4697}
4698
4699/* Returns the node id of the AST node this iseq corresponds to. */
4700static VALUE
4701iseqw_node_id(VALUE self)
4702{
4703 const rb_iseq_t *iseq = iseqw_check(self);
4704 return INT2NUM(ISEQ_BODY(iseq)->location.node_id);
4705}
4706
4707/*
4708 * Document-class: RubyVM::InstructionSequence
4709 *
4710 * The InstructionSequence class represents a compiled sequence of
4711 * instructions for the Virtual Machine used in MRI. Not all implementations of Ruby
4712 * may implement this class, and for the implementations that implement it,
4713 * the methods defined and behavior of the methods can change in any version.
4714 *
4715 * With it, you can get a handle to the instructions that make up a method or
4716 * a proc, compile strings of Ruby code down to VM instructions, and
4717 * disassemble instruction sequences to strings for easy inspection. It is
4718 * mostly useful if you want to learn how YARV works, but it also lets
4719 * you control various settings for the Ruby iseq compiler.
4720 *
4721 * You can find the source for the VM instructions in +insns.def+ in the Ruby
4722 * source.
4723 *
4724 * The instruction sequence results will almost certainly change as Ruby
4725 * changes, so example output in this documentation may be different from what
4726 * you see.
4727 *
4728 * Of course, this class is MRI specific.
4729 */
4730
4731void
4732Init_ISeq(void)
4733{
4734 /* declare ::RubyVM::InstructionSequence */
4735 rb_cISeq = rb_define_class_under(rb_cRubyVM, "InstructionSequence", rb_cObject);
4736 rb_undef_alloc_func(rb_cISeq);
4737 rb_define_method(rb_cISeq, "inspect", iseqw_inspect, 0);
4738 rb_define_method(rb_cISeq, "disasm", iseqw_disasm, 0);
4739 rb_define_method(rb_cISeq, "disassemble", iseqw_disasm, 0);
4740 rb_define_method(rb_cISeq, "to_a", iseqw_to_a, 0);
4741 rb_define_method(rb_cISeq, "eval", iseqw_eval, 0);
4742
4743 rb_define_method(rb_cISeq, "to_binary", iseqw_to_binary, -1);
4744 rb_define_singleton_method(rb_cISeq, "load_from_binary", iseqw_s_load_from_binary, 1);
4745 rb_define_singleton_method(rb_cISeq, "load_from_binary_extra_data", iseqw_s_load_from_binary_extra_data, 1);
4746
4747 /* location APIs */
4748 rb_define_method(rb_cISeq, "path", iseqw_path, 0);
4749 rb_define_method(rb_cISeq, "absolute_path", iseqw_absolute_path, 0);
4750 rb_define_method(rb_cISeq, "label", iseqw_label, 0);
4751 rb_define_method(rb_cISeq, "base_label", iseqw_base_label, 0);
4752 rb_define_method(rb_cISeq, "first_lineno", iseqw_first_lineno, 0);
4753 rb_define_method(rb_cISeq, "trace_points", iseqw_trace_points, 0);
4754 rb_define_method(rb_cISeq, "each_child", iseqw_each_child, 0);
4755
4756#if 0 /* TBD */
4757 rb_define_private_method(rb_cISeq, "marshal_dump", iseqw_marshal_dump, 0);
4758 rb_define_private_method(rb_cISeq, "marshal_load", iseqw_marshal_load, 1);
4759 /* disable this feature because there is no verifier. */
4760 rb_define_singleton_method(rb_cISeq, "load", iseq_s_load, -1);
4761#endif
4762 (void)iseq_s_load;
4763
4764 rb_define_singleton_method(rb_cISeq, "compile", iseqw_s_compile, -1);
4765 rb_define_singleton_method(rb_cISeq, "compile_parsey", iseqw_s_compile_parsey, -1);
4766 rb_define_singleton_method(rb_cISeq, "compile_prism", iseqw_s_compile_prism, -1);
4767 rb_define_singleton_method(rb_cISeq, "compile_file_prism", iseqw_s_compile_file_prism, -1);
4768 rb_define_singleton_method(rb_cISeq, "new", iseqw_s_compile, -1);
4769 rb_define_singleton_method(rb_cISeq, "compile_file", iseqw_s_compile_file, -1);
4770 rb_define_singleton_method(rb_cISeq, "compile_option", iseqw_s_compile_option_get, 0);
4771 rb_define_singleton_method(rb_cISeq, "compile_option=", iseqw_s_compile_option_set, 1);
4772 rb_define_singleton_method(rb_cISeq, "disasm", iseqw_s_disasm, 1);
4773 rb_define_singleton_method(rb_cISeq, "disassemble", iseqw_s_disasm, 1);
4774 rb_define_singleton_method(rb_cISeq, "of", iseqw_s_of, 1);
4775
4776 // script lines
4777 rb_define_method(rb_cISeq, "script_lines", iseqw_script_lines, 0);
4778 rb_define_method(rb_cISeq, "source_hash", iseqw_source_hash, 0);
4779 rb_define_method(rb_cISeq, "node_id", iseqw_node_id, 0);
4780
4781 rb_undef_method(CLASS_OF(rb_cISeq), "translate");
4782 rb_undef_method(CLASS_OF(rb_cISeq), "load_iseq");
4783}
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_private_method(klass, mid, func, arity)
Defines klass#mid and makes it private.
#define RUBY_EVENT_END
Encountered an end of a class clause.
Definition event.h:40
#define RUBY_EVENT_C_CALL
A method, written in C, is called.
Definition event.h:43
#define RUBY_EVENT_B_RETURN
Encountered a next statement.
Definition event.h:56
#define RUBY_EVENT_CLASS
Encountered a new class.
Definition event.h:39
#define RUBY_EVENT_LINE
Encountered a new line.
Definition event.h:38
#define RUBY_EVENT_RETURN
Encountered a return statement.
Definition event.h:42
#define RUBY_EVENT_C_RETURN
Return from a method, written in C.
Definition event.h:44
#define RUBY_EVENT_B_CALL
Encountered an yield statement.
Definition event.h:55
uint32_t rb_event_flag_t
Represents event(s).
Definition event.h:108
#define RUBY_EVENT_CALL
A method, written in Ruby, is called.
Definition event.h:41
#define RUBY_EVENT_RESCUE
Encountered a rescue statement.
Definition event.h:61
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
Definition class.c:2863
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
Definition class.c:3350
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1700
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:400
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1708
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define ULONG2NUM
Old name of RB_ULONG2NUM.
Definition long.h:60
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define LL2NUM
Old name of RB_LL2NUM.
Definition long_long.h:30
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define FL_TEST_RAW
Old name of RB_FL_TEST_RAW.
Definition fl_type.h:128
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define ULL2NUM
Old name of RB_ULL2NUM.
Definition long_long.h:31
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:678
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1457
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1474
VALUE rb_class_superclass(VALUE klass)
Queries the parent of the given class.
Definition object.c:2330
VALUE rb_cObject
Object class.
Definition object.c:60
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:94
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:240
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:675
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:492
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1148
VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcall(), except it takes the method arguments as a C array.
Definition vm_eval.c:1106
VALUE rb_iseq_load_from_binary(const char *ptr, size_t len)
Load an iseq object from binary format String object created by RubyVM::InstructionSequence....
Definition iseq.c:4517
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_resurrect(VALUE ary)
I guess there is no use case of this function in extension libraries, but this is a routine identical...
VALUE rb_ary_entry(VALUE ary, rb_len_t off)
Queries an element of an array.
void rb_ary_store(VALUE ary, rb_len_t key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_hidden_new(rb_len_t capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
VALUE rb_ary_new_from_values(rb_len_t n, const VALUE *elts)
Identical to rb_ary_new_from_args(), except how objects are passed.
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
Definition io.c:7515
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5985
int rb_is_local_id(ID id)
Classifies the given ID, then sees if it is a local variable.
Definition symbol.c:1265
VALUE rb_obj_is_method(VALUE recv)
Queries if the given object is a method.
Definition proc.c:2459
VALUE rb_obj_is_proc(VALUE recv)
Queries if the given object is a proc.
Definition proc.c:386
void rb_str_modify_expand(VALUE str, rb_len_t capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
Definition string.c:2841
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3938
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1523
#define rb_exc_new_cstr(exc, str)
Identical to rb_exc_new(), except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1695
void rb_str_set_len(VALUE str, rb_len_t len)
Overwrites the length of the string.
Definition string.c:3525
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:2052
VALUE rb_str_cat(VALUE dst, const char *src, rb_len_t srclen)
Destructively appends the passed contents to the string.
Definition string.c:3706
VALUE rb_str_resurrect(VALUE str)
Like rb_str_dup(), but always create an instance of rb_cString regardless of the given object's class...
Definition string.c:2070
VALUE rb_str_inspect(VALUE str)
Generates a "readable" version of the receiver.
Definition string.c:8237
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4354
VALUE rb_str_concat(VALUE dst, VALUE src)
Identical to rb_str_append(), except it also accepts an integer as a codepoint.
Definition string.c:4174
#define rb_str_cat_cstr(buf, str)
Identical to rb_str_cat(), except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1681
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1539
VALUE rb_str_intern(VALUE str)
Identical to rb_to_symbol(), except it assumes the receiver being an instance of RString.
Definition symbol.c:1085
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:516
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3715
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
Definition vm_method.c:1865
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
Definition vm_eval.c:716
ID rb_check_id(volatile VALUE *namep)
Detects if the given name is already interned or not.
Definition symbol.c:1289
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:1148
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
Definition io.c:3049
int len
Length of the buffer.
Definition io.h:8
#define RB_OBJ_SET_SHAREABLE(obj)
Wrapper of rb_obj_set_shareable().
Definition ractor.h:290
#define RB_OBJ_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
Definition ractor.h:255
static VALUE RB_OBJ_SET_FROZEN_SHAREABLE(VALUE obj)
Freezes and marks the object as shareable.
Definition ractor.h:301
VALUE rb_ractor_make_shareable(VALUE obj)
Destructively transforms the passed object so that multiple Ractors can share it.
Definition ractor.c:2012
#define RB_NUM2INT
Just another name of rb_num2int_inline.
Definition int.h:38
#define RB_INT2NUM
Just another name of rb_int2num_inline.
Definition int.h:37
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1403
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define RB_ZALLOC(type)
Shorthand of RB_ZALLOC_N with n=1.
Definition memory.h:249
VALUE type(ANYARGS)
ANYARGS-ed function type.
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:50
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:280
#define RARRAY_AREF(a, i)
References an object in an array.
Definition rarray.h:421
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition rbasic.h:166
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition rhash.h:57
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition rstring.h:438
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:409
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:81
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:773
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:557
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:604
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h:90
#define RTEST
This is an old name of RB_TEST.
Definition iseq.h:360
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
Definition vm_core.h:289
Definition vm_core.h:297
Definition vm_core.h:292
Definition iseq.h:334
A line and column in a string.
uint32_t column
The column in bytes.
int32_t line
The line number.
A list of offsets of the start of lines in a string.
size_t size
The number of offsets in the list.
This struct represents a slice in the source code, defined by an offset and a length.
Definition ast.h:579
uint32_t start
The offset of the location from the start of the source.
Definition ast.h:581
uint32_t length
The length of the location.
Definition ast.h:584
uint32_t node_id
The unique identifier for this node, which is deterministic based on the source.
Definition ast.h:1109
pm_location_t location
This is the location of the node in the source.
Definition ast.h:1115
pm_scope_node_t node
The resulting scope node that will hold the generated AST.
pm_options_t * options
The options that will be passed to the parser.
uint64_t source_hash
The source hash of the parsed source, propagated to every iseq.
VALUE * script_lines
This is a pointer to the list of script lines for the ISEQs that will be associated with this scope n...
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:242
Definition st.h:79
Definition vm_core.h:301
long rb_len_t
A signed integer type for lengths and indices of objects such as String and Array.
Definition value.h:142
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition value_type.h:425
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376
ruby_value_type
C-level type of an object.
Definition value_type.h:113