Ruby: compile.c Source File

Ruby 4.0.5p0 (2026-05-20 revision 64336ffd0ee9e1f4c05891695a3d7b49cb709721)

compile.c
1/**********************************************************************
2
3 compile.c - ruby node tree -> VM instruction sequence
4
5 $Author$
6 created at: 04/01/01 03:42:15 JST
7
8 Copyright (C) 2004-2007 Koichi Sasada
9
10**********************************************************************/
11
12#include "ruby/internal/config.h"
13#include <math.h>
14
15#ifdef HAVE_DLADDR
16# include <dlfcn.h>
17#endif
18
19#include "encindex.h"
20#include "id_table.h"
21#include "internal.h"
22#include "internal/array.h"
23#include "internal/compile.h"
24#include "internal/complex.h"
25#include "internal/encoding.h"
26#include "internal/error.h"
27#include "internal/gc.h"
28#include "internal/hash.h"
29#include "internal/io.h"
30#include "internal/numeric.h"
31#include "internal/object.h"
32#include "internal/rational.h"
33#include "internal/re.h"
34#include "internal/ruby_parser.h"
35#include "internal/symbol.h"
36#include "internal/thread.h"
37#include "internal/variable.h"
38#include "iseq.h"
39#include "ruby/ractor.h"
40#include "ruby/re.h"
41#include "ruby/util.h"
42#include "vm_core.h"
43#include "vm_callinfo.h"
44#include "vm_debug.h"
45#include "yjit.h"
46
47#include "builtin.h"
48#include "insns.inc"
49#include "insns_info.inc"
50
51#define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
52
53 typedef struct iseq_link_element {
54 enum {
55 ISEQ_ELEMENT_ANCHOR,
56 ISEQ_ELEMENT_LABEL,
57 ISEQ_ELEMENT_INSN,
58 ISEQ_ELEMENT_ADJUST,
59 ISEQ_ELEMENT_TRACE,
60 } type;
61 struct iseq_link_element *next;
62 struct iseq_link_element *prev;
63} LINK_ELEMENT;
64
65 typedef struct iseq_link_anchor {
66 LINK_ELEMENT anchor;
67 LINK_ELEMENT *last;
68} LINK_ANCHOR;
69
70typedef enum {
71 LABEL_RESCUE_NONE,
72 LABEL_RESCUE_BEG,
73 LABEL_RESCUE_END,
74 LABEL_RESCUE_TYPE_MAX
75} LABEL_RESCUE_TYPE;
76
77 typedef struct iseq_label_data {
78 LINK_ELEMENT link;
79 int label_no;
80 int position;
81 int sc_state;
82 int sp;
83 int refcnt;
84 unsigned int set: 1;
85 unsigned int rescued: 2;
86 unsigned int unremovable: 1;
87} LABEL;
88
89 typedef struct iseq_insn_data {
90 LINK_ELEMENT link;
91 enum ruby_vminsn_type insn_id;
92 int operand_size;
93 int sc_state;
94 VALUE *operands;
95 struct {
96 int line_no;
97 int node_id;
98 rb_event_flag_t events;
99 } insn_info;
100} INSN;
101
102 typedef struct iseq_adjust_data {
103 LINK_ELEMENT link;
104 LABEL *label;
105 int line_no;
106} ADJUST;
107
108 typedef struct iseq_trace_data {
109 LINK_ELEMENT link;
110 rb_event_flag_t event;
111 long data;
112} TRACE;
113
114 struct ensure_range {
115 LABEL *begin;
116 LABEL *end;
117 struct ensure_range *next;
118};
119
120 struct iseq_compile_data_ensure_node_stack {
121 const void *ensure_node;
122 struct iseq_compile_data_ensure_node_stack *prev;
123 struct ensure_range *erange;
124};
125
126const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
127
140
141#ifndef CPDEBUG
142#define CPDEBUG 0
143#endif
144
145#if CPDEBUG >= 0
146#define compile_debug CPDEBUG
147#else
148#define compile_debug ISEQ_COMPILE_DATA(iseq)->option->debug_level
149#endif
150
151#if CPDEBUG
152
153#define compile_debug_print_indent(level) \
154 ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
155
156#define debugp(header, value) (void) \
157 (compile_debug_print_indent(1) && \
158 ruby_debug_print_value(1, compile_debug, (header), (value)))
159
160#define debugi(header, id) (void) \
161 (compile_debug_print_indent(1) && \
162 ruby_debug_print_id(1, compile_debug, (header), (id)))
163
164#define debugp_param(header, value) (void) \
165 (compile_debug_print_indent(1) && \
166 ruby_debug_print_value(1, compile_debug, (header), (value)))
167
168#define debugp_verbose(header, value) (void) \
169 (compile_debug_print_indent(2) && \
170 ruby_debug_print_value(2, compile_debug, (header), (value)))
171
172#define debugp_verbose_node(header, value) (void) \
173 (compile_debug_print_indent(10) && \
174 ruby_debug_print_value(10, compile_debug, (header), (value)))
175
176#define debug_node_start(node) ((void) \
177 (compile_debug_print_indent(1) && \
178 (ruby_debug_print_node(1, CPDEBUG, "", (const NODE *)(node)), gl_node_level)), \
179 gl_node_level++)
180
181#define debug_node_end() gl_node_level --
182
183#else
184
185#define debugi(header, id) ((void)0)
186#define debugp(header, value) ((void)0)
187#define debugp_verbose(header, value) ((void)0)
188#define debugp_verbose_node(header, value) ((void)0)
189#define debugp_param(header, value) ((void)0)
190#define debug_node_start(node) ((void)0)
191#define debug_node_end() ((void)0)
192#endif
193
194#if CPDEBUG > 1 || CPDEBUG < 0
195#undef printf
196#define printf ruby_debug_printf
197#define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
198#define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
199#else
200#define debugs if(0)printf
201#define debug_compile(msg, v) (v)
202#endif
203
204#define LVAR_ERRINFO (1)
205
206/* create new label */
207#define NEW_LABEL(l) new_label_body(iseq, (l))
208#define LABEL_FORMAT "<L%03d>"
209
210#define NEW_ISEQ(node, name, type, line_no) \
211 new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
212
213#define NEW_CHILD_ISEQ(node, name, type, line_no) \
214 new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
215
216#define NEW_CHILD_ISEQ_WITH_CALLBACK(callback_func, name, type, line_no) \
217 new_child_iseq_with_callback(iseq, (callback_func), (name), iseq, (type), (line_no))
218
219/* add instructions */
220#define ADD_SEQ(seq1, seq2) \
221 APPEND_LIST((seq1), (seq2))
222
223/* add an instruction */
224#define ADD_INSN(seq, line_node, insn) \
225 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 0))
226
227/* add an instruction with the given line number and node id */
228#define ADD_SYNTHETIC_INSN(seq, line_no, node_id, insn) \
229 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line_no), (node_id), BIN(insn), 0))
230
231/* insert an instruction before next */
232#define INSERT_BEFORE_INSN(next, line_no, node_id, insn) \
233 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
234
235/* insert an instruction after prev */
236#define INSERT_AFTER_INSN(prev, line_no, node_id, insn) \
237 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
238
239/* add an instruction with some operands (1, 2, 3, 5) */
240#define ADD_INSN1(seq, line_node, insn, op1) \
241 ADD_ELEM((seq), (LINK_ELEMENT *) \
242 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 1, (VALUE)(op1)))
243
244/* insert an instruction with some operands (1, 2, 3, 5) before next */
245#define INSERT_BEFORE_INSN1(next, line_no, node_id, insn, op1) \
246 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
247 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
248
249/* insert an instruction with some operands (1, 2, 3, 5) after prev */
250#define INSERT_AFTER_INSN1(prev, line_no, node_id, insn, op1) \
251 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
252 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
253
254#define LABEL_REF(label) ((label)->refcnt++)
255
256/* add an instruction with label operand (alias of ADD_INSN1) */
257#define ADD_INSNL(seq, line_node, insn, label) (ADD_INSN1(seq, line_node, insn, label), LABEL_REF(label))
258
259#define ADD_INSN2(seq, line_node, insn, op1, op2) \
260 ADD_ELEM((seq), (LINK_ELEMENT *) \
261 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
262
263#define ADD_INSN3(seq, line_node, insn, op1, op2, op3) \
264 ADD_ELEM((seq), (LINK_ELEMENT *) \
265 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
266
267/* Specific Insn factory */
268#define ADD_SEND(seq, line_node, id, argc) \
269 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
270
271#define ADD_SEND_WITH_FLAG(seq, line_node, id, argc, flag) \
272 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)(flag), NULL)
273
274#define ADD_SEND_WITH_BLOCK(seq, line_node, id, argc, block) \
275 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
276
277#define ADD_CALL_RECEIVER(seq, line_node) \
278 ADD_INSN((seq), (line_node), putself)
279
280#define ADD_CALL(seq, line_node, id, argc) \
281 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
282
283#define ADD_CALL_WITH_BLOCK(seq, line_node, id, argc, block) \
284 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
285
286#define ADD_SEND_R(seq, line_node, id, argc, block, flag, keywords) \
287 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords)))
288
289#define ADD_TRACE(seq, event) \
290 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
291#define ADD_TRACE_WITH_DATA(seq, event, data) \
292 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
293
294static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
295static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
296
297#define ADD_GETLOCAL(seq, line_node, idx, level) iseq_add_getlocal(iseq, (seq), (line_node), (idx), (level))
298#define ADD_SETLOCAL(seq, line_node, idx, level) iseq_add_setlocal(iseq, (seq), (line_node), (idx), (level))
299
300/* add label */
301#define ADD_LABEL(seq, label) \
302 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
303
304#define APPEND_LABEL(seq, before, label) \
305 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
306
307#define ADD_ADJUST(seq, line_node, label) \
308 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), nd_line(line_node)))
309
310#define ADD_ADJUST_RESTORE(seq, label) \
311 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
312
313#define LABEL_UNREMOVABLE(label) \
314 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
315#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
316 VALUE _e = rb_ary_new3(5, (type), \
317 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
318 (VALUE)(iseqv), (VALUE)(lc) | 1); \
319 LABEL_UNREMOVABLE(ls); \
320 LABEL_REF(le); \
321 LABEL_REF(lc); \
322 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
323 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_hidden_new(3)); \
324 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
325} while (0)
326
327/* compile node */
328#define COMPILE(anchor, desc, node) \
329 (debug_compile("== " desc "\n", \
330 iseq_compile_each(iseq, (anchor), (node), 0)))
331
332/* compile node, this node's value will be popped */
333#define COMPILE_POPPED(anchor, desc, node) \
334 (debug_compile("== " desc "\n", \
335 iseq_compile_each(iseq, (anchor), (node), 1)))
336
337/* compile node, which is popped when 'popped' is true */
338#define COMPILE_(anchor, desc, node, popped) \
339 (debug_compile("== " desc "\n", \
340 iseq_compile_each(iseq, (anchor), (node), (popped))))
341
342#define COMPILE_RECV(anchor, desc, node, recv) \
343 (private_recv_p(node) ? \
344 (ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
345 COMPILE(anchor, desc, recv) ? 0 : -1)
346
347#define OPERAND_AT(insn, idx) \
348 (((INSN*)(insn))->operands[(idx)])
349
350#define INSN_OF(insn) \
351 (((INSN*)(insn))->insn_id)
352
353#define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
354#define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
355#define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
356#define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
357#define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
358#define IS_NEXT_INSN_ID(link, insn) \
359 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
360
361/* error */
362#if CPDEBUG > 0
363 RBIMPL_ATTR_NORETURN()
364#endif
365 RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
366static void
367append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...)
368{
369 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
370 VALUE file = rb_iseq_path(iseq);
371 VALUE err = err_info == Qtrue ? Qfalse : err_info;
372 va_list args;
373
374 va_start(args, fmt);
375 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
376 va_end(args);
377 if (NIL_P(err_info)) {
378 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
379 rb_set_errinfo(err);
380 }
381 else if (!err_info) {
382 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, Qtrue);
383 }
384 if (compile_debug) {
385 if (SPECIAL_CONST_P(err)) err = rb_eSyntaxError;
386 rb_exc_fatal(err);
387 }
388}
389
390#if 0
391static void
392compile_bug(rb_iseq_t *iseq, int line, const char *fmt, ...)
393{
394 va_list args;
395 va_start(args, fmt);
396 rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
397 va_end(args);
398 abort();
399}
400#endif
401
402#define COMPILE_ERROR append_compile_error
403
404#define ERROR_ARGS_AT(n) iseq, nd_line(n),
405#define ERROR_ARGS ERROR_ARGS_AT(node)
406
407#define EXPECT_NODE(prefix, node, ndtype, errval) \
408do { \
409 const NODE *error_node = (node); \
410 enum node_type error_type = nd_type(error_node); \
411 if (error_type != (ndtype)) { \
412 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
413 prefix ": " #ndtype " is expected, but %s", \
414 ruby_node_name(error_type)); \
415 return errval; \
416 } \
417} while (0)
418
419#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
420do { \
421 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
422 prefix ": must be " #ndtype ", but 0"); \
423 return errval; \
424} while (0)
425
426#define UNKNOWN_NODE(prefix, node, errval) \
427do { \
428 const NODE *error_node = (node); \
429 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
430 ruby_node_name(nd_type(error_node))); \
431 return errval; \
432} while (0)
433
434#define COMPILE_OK 1
435#define COMPILE_NG 0
436
437#define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
438#define NO_CHECK(sub) (void)(sub)
439#define BEFORE_RETURN
440
441#define DECL_ANCHOR(name) \
442 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},&name[0].anchor}}
443#define INIT_ANCHOR(name) \
444 ((name->last = &name->anchor)->next = NULL) /* re-initialize */
445
446static inline VALUE
447freeze_hide_obj(VALUE obj)
448{
449 OBJ_FREEZE(obj);
450 RBASIC_CLEAR_CLASS(obj);
451 return obj;
452}
453
454#include "optinsn.inc"
455#if OPT_INSTRUCTIONS_UNIFICATION
456#include "optunifs.inc"
457#endif
458
459/* for debug */
460#if CPDEBUG < 0
461#define ISEQ_ARG iseq,
462#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
463#else
464#define ISEQ_ARG
465#define ISEQ_ARG_DECLARE
466#endif
467
468#if CPDEBUG
469#define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
470#endif
471
472static void dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest);
473static void dump_disasm_list(const LINK_ELEMENT *elem);
474
475static int insn_data_length(INSN *iobj);
476static int calc_sp_depth(int depth, INSN *iobj);
477
478static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...);
479static LABEL *new_label_body(rb_iseq_t *iseq, long line);
480static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
481static TRACE *new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data);
482
483
484static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, const NODE *n, int);
485static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
486static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
487static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
488static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
489
490static int iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args);
491static int iseq_set_exception_local_table(rb_iseq_t *iseq);
492static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
493
494static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
495static int iseq_set_exception_table(rb_iseq_t *iseq);
496static int iseq_set_optargs_table(rb_iseq_t *iseq);
497static int iseq_set_parameters_lvar_state(const rb_iseq_t *iseq);
498
499static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore);
500static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
501
502/*
503 * To make Array to LinkedList, use link_anchor
504 */
505
506static void
507verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *const anchor)
508{
509#if CPDEBUG
510 int flag = 0;
511 LINK_ELEMENT *list, *plist;
512
513 if (!compile_debug) return;
514
515 list = anchor->anchor.next;
516 plist = &anchor->anchor;
517 while (list) {
518 if (plist != list->prev) {
519 flag += 1;
520 }
521 plist = list;
522 list = list->next;
523 }
524
525 if (anchor->last != plist && anchor->last != 0) {
526 flag |= 0x70000;
527 }
528
529 if (flag != 0) {
530 rb_bug("list verify error: %08x (%s)", flag, info);
531 }
532#endif
533}
534#if CPDEBUG < 0
535#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
536#endif
537
538static void
539verify_call_cache(rb_iseq_t *iseq)
540{
541#if CPDEBUG
542 VALUE *original = rb_iseq_original_iseq(iseq);
543 size_t i = 0;
544 while (i < ISEQ_BODY(iseq)->iseq_size) {
545 VALUE insn = original[i];
546 const char *types = insn_op_types(insn);
547
548 for (int j=0; types[j]; j++) {
549 if (types[j] == TS_CALLDATA) {
550 struct rb_call_data *cd = (struct rb_call_data *)original[i+j+1];
551 const struct rb_callinfo *ci = cd->ci;
552 const struct rb_callcache *cc = cd->cc;
553 if (cc != vm_cc_empty()) {
554 vm_ci_dump(ci);
555 rb_bug("call cache is not initialized by vm_cc_empty()");
556 }
557 }
558 }
559 i += insn_len(insn);
560 }
561
562 for (unsigned int i=0; i<ISEQ_BODY(iseq)->ci_size; i++) {
563 struct rb_call_data *cd = &ISEQ_BODY(iseq)->call_data[i];
564 const struct rb_callinfo *ci = cd->ci;
565 const struct rb_callcache *cc = cd->cc;
566 if (cc != NULL && cc != vm_cc_empty()) {
567 vm_ci_dump(ci);
568 rb_bug("call cache is not initialized by vm_cc_empty()");
569 }
570 }
571#endif
572}
573
574/*
575 * elem1, elem2 => elem1, elem2, elem
576 */
577static void
578ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *elem)
579{
580 elem->prev = anchor->last;
581 anchor->last->next = elem;
582 anchor->last = elem;
583 verify_list("add", anchor);
584}
585
586/*
587 * elem1, before, elem2 => elem1, before, elem, elem2
588 */
589static void
590APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
591{
592 elem->prev = before;
593 elem->next = before->next;
594 elem->next->prev = elem;
595 before->next = elem;
596 if (before == anchor->last) anchor->last = elem;
597 verify_list("add", anchor);
598}
599#if CPDEBUG < 0
600#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
601#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
602#endif
603
604static int
605branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
606{
607 if (!ISEQ_COVERAGE(iseq)) return 0;
608 if (!ISEQ_BRANCH_COVERAGE(iseq)) return 0;
609 if (first_line <= 0) return 0;
610 return 1;
611}
612
613static VALUE
614setup_branch(const rb_code_location_t *loc, const char *type, VALUE structure, VALUE key)
615{
616 const int first_lineno = loc->beg_pos.lineno, first_column = loc->beg_pos.column;
617 const int last_lineno = loc->end_pos.lineno, last_column = loc->end_pos.column;
618 VALUE branch = rb_ary_hidden_new(6);
619
620 rb_hash_aset(structure, key, branch);
621 rb_ary_push(branch, ID2SYM(rb_intern(type)));
622 rb_ary_push(branch, INT2FIX(first_lineno));
623 rb_ary_push(branch, INT2FIX(first_column));
624 rb_ary_push(branch, INT2FIX(last_lineno));
625 rb_ary_push(branch, INT2FIX(last_column));
626 return branch;
627}
628
629static VALUE
630decl_branch_base(rb_iseq_t *iseq, VALUE key, const rb_code_location_t *loc, const char *type)
631{
632 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return Qundef;
633
634 /*
635 * if !structure[node]
636 * structure[node] = [type, first_lineno, first_column, last_lineno, last_column, branches = {}]
637 * else
638 * branches = structure[node][5]
639 * end
640 */
641
642 VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
643 VALUE branch_base = rb_hash_aref(structure, key);
644 VALUE branches;
645
646 if (NIL_P(branch_base)) {
647 branch_base = setup_branch(loc, type, structure, key);
648 branches = rb_hash_new();
649 rb_obj_hide(branches);
650 rb_ary_push(branch_base, branches);
651 }
652 else {
653 branches = RARRAY_AREF(branch_base, 5);
654 }
655
656 return branches;
657}
658
659static NODE
660generate_dummy_line_node(int lineno, int node_id)
661{
662 NODE dummy = { 0 };
663 nd_set_line(&dummy, lineno);
664 nd_set_node_id(&dummy, node_id);
665 return dummy;
666}
667
668static void
669add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const rb_code_location_t *loc, int node_id, int branch_id, const char *type, VALUE branches)
670{
671 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return;
672
673 /*
674 * if !branches[branch_id]
675 * branches[branch_id] = [type, first_lineno, first_column, last_lineno, last_column, counter_idx]
676 * else
677 * counter_idx= branches[branch_id][5]
678 * end
679 */
680
681 VALUE key = INT2FIX(branch_id);
682 VALUE branch = rb_hash_aref(branches, key);
683 long counter_idx;
684
685 if (NIL_P(branch)) {
686 branch = setup_branch(loc, type, branches, key);
687 VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
688 counter_idx = RARRAY_LEN(counters);
689 rb_ary_push(branch, LONG2FIX(counter_idx));
690 rb_ary_push(counters, INT2FIX(0));
691 }
692 else {
693 counter_idx = FIX2LONG(RARRAY_AREF(branch, 5));
694 }
695
696 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
697 ADD_SYNTHETIC_INSN(seq, loc->end_pos.lineno, node_id, nop);
698}
699
700#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
701
702static int
703validate_label(st_data_t name, st_data_t label, st_data_t arg)
704{
705 rb_iseq_t *iseq = (rb_iseq_t *)arg;
706 LABEL *lobj = (LABEL *)label;
707 if (!lobj->link.next) {
708 do {
709 COMPILE_ERROR(iseq, lobj->position,
710 "%"PRIsVALUE": undefined label",
711 rb_sym2str((VALUE)name));
712 } while (0);
713 }
714 return ST_CONTINUE;
715}
716
717static void
718validate_labels(rb_iseq_t *iseq, st_table *labels_table)
719{
720 st_foreach(labels_table, validate_label, (st_data_t)iseq);
721 st_free_table(labels_table);
722}
723
724static NODE *
725get_nd_recv(const NODE *node)
726{
727 switch (nd_type(node)) {
728 case NODE_CALL:
729 return RNODE_CALL(node)->nd_recv;
730 case NODE_OPCALL:
731 return RNODE_OPCALL(node)->nd_recv;
732 case NODE_FCALL:
733 return 0;
734 case NODE_QCALL:
735 return RNODE_QCALL(node)->nd_recv;
736 case NODE_VCALL:
737 return 0;
738 case NODE_ATTRASGN:
739 return RNODE_ATTRASGN(node)->nd_recv;
740 case NODE_OP_ASGN1:
741 return RNODE_OP_ASGN1(node)->nd_recv;
742 case NODE_OP_ASGN2:
743 return RNODE_OP_ASGN2(node)->nd_recv;
744 default:
745 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
746 }
747}
748
749static ID
750get_node_call_nd_mid(const NODE *node)
751{
752 switch (nd_type(node)) {
753 case NODE_CALL:
754 return RNODE_CALL(node)->nd_mid;
755 case NODE_OPCALL:
756 return RNODE_OPCALL(node)->nd_mid;
757 case NODE_FCALL:
758 return RNODE_FCALL(node)->nd_mid;
759 case NODE_QCALL:
760 return RNODE_QCALL(node)->nd_mid;
761 case NODE_VCALL:
762 return RNODE_VCALL(node)->nd_mid;
763 case NODE_ATTRASGN:
764 return RNODE_ATTRASGN(node)->nd_mid;
765 default:
766 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
767 }
768}
769
770static NODE *
771get_nd_args(const NODE *node)
772{
773 switch (nd_type(node)) {
774 case NODE_CALL:
775 return RNODE_CALL(node)->nd_args;
776 case NODE_OPCALL:
777 return RNODE_OPCALL(node)->nd_args;
778 case NODE_FCALL:
779 return RNODE_FCALL(node)->nd_args;
780 case NODE_QCALL:
781 return RNODE_QCALL(node)->nd_args;
782 case NODE_VCALL:
783 return 0;
784 case NODE_ATTRASGN:
785 return RNODE_ATTRASGN(node)->nd_args;
786 default:
787 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
788 }
789}
790
791static ID
792get_node_colon_nd_mid(const NODE *node)
793{
794 switch (nd_type(node)) {
795 case NODE_COLON2:
796 return RNODE_COLON2(node)->nd_mid;
797 case NODE_COLON3:
798 return RNODE_COLON3(node)->nd_mid;
799 default:
800 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
801 }
802}
803
804static ID
805get_nd_vid(const NODE *node)
806{
807 switch (nd_type(node)) {
808 case NODE_LASGN:
809 return RNODE_LASGN(node)->nd_vid;
810 case NODE_DASGN:
811 return RNODE_DASGN(node)->nd_vid;
812 case NODE_IASGN:
813 return RNODE_IASGN(node)->nd_vid;
814 case NODE_CVASGN:
815 return RNODE_CVASGN(node)->nd_vid;
816 default:
817 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
818 }
819}
820
821static NODE *
822get_nd_value(const NODE *node)
823{
824 switch (nd_type(node)) {
825 case NODE_LASGN:
826 return RNODE_LASGN(node)->nd_value;
827 case NODE_DASGN:
828 return RNODE_DASGN(node)->nd_value;
829 default:
830 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
831 }
832}
833
834static VALUE
835get_string_value(const NODE *node)
836{
837 switch (nd_type(node)) {
838 case NODE_STR:
839 return RB_OBJ_SET_SHAREABLE(rb_node_str_string_val(node));
840 case NODE_FILE:
841 return RB_OBJ_SET_SHAREABLE(rb_node_file_path_val(node));
842 default:
843 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
844 }
845}
846
847 VALUE
848rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
849{
850 DECL_ANCHOR(ret);
851 INIT_ANCHOR(ret);
852
853 (*ifunc->func)(iseq, ret, ifunc->data);
854
855 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
856
857 CHECK(iseq_setup_insn(iseq, ret));
858 return iseq_setup(iseq, ret);
859}
860
861static bool drop_unreachable_return(LINK_ANCHOR *ret);
862
863 VALUE
864rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
865{
866 DECL_ANCHOR(ret);
867 INIT_ANCHOR(ret);
868
869 if (node == 0) {
870 NO_CHECK(COMPILE(ret, "nil", node));
871 iseq_set_local_table(iseq, 0, 0);
872 }
873 /* assume node is T_NODE */
874 else if (nd_type_p(node, NODE_SCOPE)) {
875 /* iseq type of top, method, class, block */
876 iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl, (NODE *)RNODE_SCOPE(node)->nd_args);
877 iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
878 iseq_set_parameters_lvar_state(iseq);
879
880 switch (ISEQ_BODY(iseq)->type) {
881 case ISEQ_TYPE_BLOCK:
882 {
883 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
884 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
885
886 start->rescued = LABEL_RESCUE_BEG;
887 end->rescued = LABEL_RESCUE_END;
888
889 ADD_TRACE(ret, RUBY_EVENT_B_CALL);
890 ADD_SYNTHETIC_INSN(ret, ISEQ_BODY(iseq)->location.first_lineno, -1, nop);
891 ADD_LABEL(ret, start);
892 CHECK(COMPILE(ret, "block body", RNODE_SCOPE(node)->nd_body));
893 ADD_LABEL(ret, end);
894 ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
895 ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
896
897 /* wide range catch handler must put at last */
898 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
899 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
900 break;
901 }
902 case ISEQ_TYPE_CLASS:
903 {
904 ADD_TRACE(ret, RUBY_EVENT_CLASS);
905 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
906 ADD_TRACE(ret, RUBY_EVENT_END);
907 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
908 break;
909 }
910 case ISEQ_TYPE_METHOD:
911 {
912 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
913 ADD_TRACE(ret, RUBY_EVENT_CALL);
914 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
915 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
916 ADD_TRACE(ret, RUBY_EVENT_RETURN);
917 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
918 break;
919 }
920 default: {
921 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
922 break;
923 }
924 }
925 }
926 else {
927 const char *m;
928#define INVALID_ISEQ_TYPE(type) \
929 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
930 switch (ISEQ_BODY(iseq)->type) {
931 case INVALID_ISEQ_TYPE(METHOD);
932 case INVALID_ISEQ_TYPE(CLASS);
933 case INVALID_ISEQ_TYPE(BLOCK);
934 case INVALID_ISEQ_TYPE(EVAL);
935 case INVALID_ISEQ_TYPE(MAIN);
936 case INVALID_ISEQ_TYPE(TOP);
937#undef INVALID_ISEQ_TYPE /* invalid iseq types end */
938 case ISEQ_TYPE_RESCUE:
939 iseq_set_exception_local_table(iseq);
940 CHECK(COMPILE(ret, "rescue", node));
941 break;
942 case ISEQ_TYPE_ENSURE:
943 iseq_set_exception_local_table(iseq);
944 CHECK(COMPILE_POPPED(ret, "ensure", node));
945 break;
946 case ISEQ_TYPE_PLAIN:
947 CHECK(COMPILE(ret, "ensure", node));
948 break;
949 default:
950 COMPILE_ERROR(ERROR_ARGS "unknown scope: %d", ISEQ_BODY(iseq)->type);
951 return COMPILE_NG;
952 invalid_iseq_type:
953 COMPILE_ERROR(ERROR_ARGS "compile/ISEQ_TYPE_%s should not be reached", m);
954 return COMPILE_NG;
955 }
956 }
957
958 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE || ISEQ_BODY(iseq)->type == ISEQ_TYPE_ENSURE) {
959 NODE dummy_line_node = generate_dummy_line_node(0, -1);
960 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
961 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0) /* continue throw */ );
962 }
963 else if (!drop_unreachable_return(ret)) {
964 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
965 }
966
967#if OPT_SUPPORT_JOKE
968 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
969 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
970 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
971 validate_labels(iseq, labels_table);
972 }
973#endif
974 CHECK(iseq_setup_insn(iseq, ret));
975 return iseq_setup(iseq, ret);
976}
977
978static int
979rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
980{
981#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
982 const void * const *table = rb_vm_get_insns_address_table();
983 unsigned int i;
984 VALUE *encoded = (VALUE *)ISEQ_BODY(iseq)->iseq_encoded;
985
986 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
987 int insn = (int)ISEQ_BODY(iseq)->iseq_encoded[i];
988 int len = insn_len(insn);
989 encoded[i] = (VALUE)table[insn];
990 i += len;
991 }
992 FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
993#endif
994
995#if USE_YJIT
996 rb_yjit_live_iseq_count++;
997 rb_yjit_iseq_alloc_count++;
998#endif
999
1000 return COMPILE_OK;
1001}
1002
1003 VALUE *
1004rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
1005{
1006 VALUE *original_code;
1007
1008 if (ISEQ_ORIGINAL_ISEQ(iseq)) return ISEQ_ORIGINAL_ISEQ(iseq);
1009 original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, ISEQ_BODY(iseq)->iseq_size);
1010 MEMCPY(original_code, ISEQ_BODY(iseq)->iseq_encoded, VALUE, ISEQ_BODY(iseq)->iseq_size);
1011
1012#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1013 {
1014 unsigned int i;
1015
1016 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
1017 const void *addr = (const void *)original_code[i];
1018 const int insn = rb_vm_insn_addr2insn(addr);
1019
1020 original_code[i] = insn;
1021 i += insn_len(insn);
1022 }
1023 }
1024#endif
1025 return original_code;
1026}
1027
1028/*********************************************/
1029/* definition of data structure for compiler */
1030/*********************************************/
1031
1032/*
1033 * On 32-bit SPARC, GCC by default generates SPARC V7 code that may require
1034 * 8-byte word alignment. On the other hand, Oracle Solaris Studio seems to
1035 * generate SPARCV8PLUS code with unaligned memory access instructions.
1036 * That is why the STRICT_ALIGNMENT is defined only with GCC.
1037 */
1038#if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
1039 #define STRICT_ALIGNMENT
1040#endif
1041
1042/*
1043 * Some OpenBSD platforms (including sparc64) require strict alignment.
1044 */
1045#if defined(__OpenBSD__)
1046 #include <sys/endian.h>
1047 #ifdef __STRICT_ALIGNMENT
1048 #define STRICT_ALIGNMENT
1049 #endif
1050#endif
1051
1052#ifdef STRICT_ALIGNMENT
1053 #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
1054 #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
1055 #else
1056 #define ALIGNMENT_SIZE SIZEOF_VALUE
1057 #endif
1058 #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
1059 #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
1060 /* Note: ALIGNMENT_SIZE == (2 ** N) is expected. */
1061#else
1062 #define PADDING_SIZE_MAX 0
1063#endif /* STRICT_ALIGNMENT */
1064
1065#ifdef STRICT_ALIGNMENT
1066/* calculate padding size for aligned memory access */
1067static size_t
1068calc_padding(void *ptr, size_t size)
1069{
1070 size_t mis;
1071 size_t padding = 0;
1072
1073 mis = (size_t)ptr & ALIGNMENT_SIZE_MASK;
1074 if (mis > 0) {
1075 padding = ALIGNMENT_SIZE - mis;
1076 }
1077/*
1078 * On 32-bit sparc or equivalents, when a single VALUE is requested
1079 * and padding == sizeof(VALUE), it is clear that no padding is needed.
1080 */
1081#if ALIGNMENT_SIZE > SIZEOF_VALUE
1082 if (size == sizeof(VALUE) && padding == sizeof(VALUE)) {
1083 padding = 0;
1084 }
1085#endif
1086
1087 return padding;
1088}
1089#endif /* STRICT_ALIGNMENT */
1090
1091static void *
1092compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size)
1093{
1094 void *ptr = 0;
1095 struct iseq_compile_data_storage *storage = *arena;
1096#ifdef STRICT_ALIGNMENT
1097 size_t padding = calc_padding((void *)&storage->buff[storage->pos], size);
1098#else
1099 const size_t padding = 0; /* expected to be optimized by compiler */
1100#endif /* STRICT_ALIGNMENT */
1101
1102 if (size >= INT_MAX - padding) rb_memerror();
1103 if (storage->pos + size + padding > storage->size) {
1104 unsigned int alloc_size = storage->size;
1105
1106 while (alloc_size < size + PADDING_SIZE_MAX) {
1107 if (alloc_size >= INT_MAX / 2) rb_memerror();
1108 alloc_size *= 2;
1109 }
1110 storage->next = (void *)ALLOC_N(char, alloc_size +
1111 offsetof(struct iseq_compile_data_storage, buff));
1112 storage = *arena = storage->next;
1113 storage->next = 0;
1114 storage->pos = 0;
1115 storage->size = alloc_size;
1116#ifdef STRICT_ALIGNMENT
1117 padding = calc_padding((void *)&storage->buff[storage->pos], size);
1118#endif /* STRICT_ALIGNMENT */
1119 }
1120
1121#ifdef STRICT_ALIGNMENT
1122 storage->pos += (int)padding;
1123#endif /* STRICT_ALIGNMENT */
1124
1125 ptr = (void *)&storage->buff[storage->pos];
1126 storage->pos += (int)size;
1127 return ptr;
1128}
1129
1130static void *
1131compile_data_alloc(rb_iseq_t *iseq, size_t size)
1132{
1133 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
1134 return compile_data_alloc_with_arena(arena, size);
1135}
1136
1137static inline void *
1138compile_data_alloc2(rb_iseq_t *iseq, size_t x, size_t y)
1139{
1140 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1141 return compile_data_alloc(iseq, size);
1142}
1143
1144static inline void *
1145compile_data_calloc2(rb_iseq_t *iseq, size_t x, size_t y)
1146{
1147 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1148 void *p = compile_data_alloc(iseq, size);
1149 memset(p, 0, size);
1150 return p;
1151}
1152
1153static INSN *
1154compile_data_alloc_insn(rb_iseq_t *iseq)
1155{
1156 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
1157 return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN));
1158}
1159
1160static LABEL *
1161compile_data_alloc_label(rb_iseq_t *iseq)
1162{
1163 return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
1164}
1165
1166static ADJUST *
1167compile_data_alloc_adjust(rb_iseq_t *iseq)
1168{
1169 return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
1170}
1171
1172static TRACE *
1173compile_data_alloc_trace(rb_iseq_t *iseq)
1174{
1175 return (TRACE *)compile_data_alloc(iseq, sizeof(TRACE));
1176}
1177
1178/*
1179 * elem1, elemX => elem1, elem2, elemX
1180 */
1181static void
1182ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1183{
1184 elem2->next = elem1->next;
1185 elem2->prev = elem1;
1186 elem1->next = elem2;
1187 if (elem2->next) {
1188 elem2->next->prev = elem2;
1189 }
1190}
1191
1192/*
1193 * elem1, elemX => elemX, elem2, elem1
1194 */
1195static void
1196ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1197{
1198 elem2->prev = elem1->prev;
1199 elem2->next = elem1;
1200 elem1->prev = elem2;
1201 if (elem2->prev) {
1202 elem2->prev->next = elem2;
1203 }
1204}
1205
1206/*
1207 * elemX, elem1, elemY => elemX, elem2, elemY
1208 */
1209static void
1210ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1211{
1212 elem2->prev = elem1->prev;
1213 elem2->next = elem1->next;
1214 if (elem1->prev) {
1215 elem1->prev->next = elem2;
1216 }
1217 if (elem1->next) {
1218 elem1->next->prev = elem2;
1219 }
1220}
1221
1222static void
1223ELEM_REMOVE(LINK_ELEMENT *elem)
1224{
1225 elem->prev->next = elem->next;
1226 if (elem->next) {
1227 elem->next->prev = elem->prev;
1228 }
1229}
1230
1231static LINK_ELEMENT *
1232FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
1233{
1234 return anchor->anchor.next;
1235}
1236
1237static LINK_ELEMENT *
1238LAST_ELEMENT(LINK_ANCHOR *const anchor)
1239{
1240 return anchor->last;
1241}
1242
1243static LINK_ELEMENT *
1244ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1245{
1246 while (elem) {
1247 switch (elem->type) {
1248 case ISEQ_ELEMENT_INSN:
1249 case ISEQ_ELEMENT_ADJUST:
1250 return elem;
1251 default:
1252 elem = elem->next;
1253 }
1254 }
1255 return NULL;
1256}
1257
1258static int
1259LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1260{
1261 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1262 if (first_insn != NULL &&
1263 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1264 return TRUE;
1265 }
1266 else {
1267 return FALSE;
1268 }
1269}
1270
1271static int
1272LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1273{
1274 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1275 return TRUE;
1276 }
1277 else {
1278 return FALSE;
1279 }
1280}
1281
1282/*
1283 * anc1: e1, e2, e3
1284 * anc2: e4, e5
1285 *#=>
1286 * anc1: e1, e2, e3, e4, e5
1287 * anc2: e4, e5 (broken)
1288 */
1289static void
1290APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1291{
1292 if (anc2->anchor.next) {
1293 /* LINK_ANCHOR must not loop */
1294 RUBY_ASSERT(anc2->last != &anc2->anchor);
1295 anc1->last->next = anc2->anchor.next;
1296 anc2->anchor.next->prev = anc1->last;
1297 anc1->last = anc2->last;
1298 }
1299 else {
1300 RUBY_ASSERT(anc2->last == &anc2->anchor);
1301 }
1302 verify_list("append", anc1);
1303}
1304#if CPDEBUG < 0
1305#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1306#endif
1307
1308#if CPDEBUG && 0
1309static void
1310debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *cur)
1311{
1312 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1313 printf("----\n");
1314 printf("anch: %p, frst: %p, last: %p\n", (void *)&anchor->anchor,
1315 (void *)anchor->anchor.next, (void *)anchor->last);
1316 while (list) {
1317 printf("curr: %p, next: %p, prev: %p, type: %d\n", (void *)list, (void *)list->next,
1318 (void *)list->prev, (int)list->type);
1319 list = list->next;
1320 }
1321 printf("----\n");
1322
1323 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1324 verify_list("debug list", anchor);
1325}
1326#if CPDEBUG < 0
1327#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1328#endif
1329#else
1330#define debug_list(anc, cur) ((void)0)
1331#endif
1332
1333static TRACE *
1334new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1335{
1336 TRACE *trace = compile_data_alloc_trace(iseq);
1337
1338 trace->link.type = ISEQ_ELEMENT_TRACE;
1339 trace->link.next = NULL;
1340 trace->event = event;
1341 trace->data = data;
1342
1343 return trace;
1344}
1345
1346static LABEL *
1347new_label_body(rb_iseq_t *iseq, long line)
1348{
1349 LABEL *labelobj = compile_data_alloc_label(iseq);
1350
1351 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1352 labelobj->link.next = 0;
1353
1354 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1355 labelobj->sc_state = 0;
1356 labelobj->sp = -1;
1357 labelobj->refcnt = 0;
1358 labelobj->set = 0;
1359 labelobj->rescued = LABEL_RESCUE_NONE;
1360 labelobj->unremovable = 0;
1361 labelobj->position = -1;
1362 return labelobj;
1363}
1364
1365static ADJUST *
1366new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1367{
1368 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1369 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1370 adjust->link.next = 0;
1371 adjust->label = label;
1372 adjust->line_no = line;
1373 LABEL_UNREMOVABLE(label);
1374 return adjust;
1375}
1376
1377static void
1378iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE *, VALUE), VALUE data)
1379{
1380 const char *types = insn_op_types(insn->insn_id);
1381 for (int j = 0; types[j]; j++) {
1382 char type = types[j];
1383 switch (type) {
1384 case TS_CDHASH:
1385 case TS_ISEQ:
1386 case TS_VALUE:
1387 case TS_IC: // constant path array
1388 case TS_CALLDATA: // ci is stored.
1389 func(&OPERAND_AT(insn, j), data);
1390 break;
1391 default:
1392 break;
1393 }
1394 }
1395}
1396
1397static void
1398iseq_insn_each_object_write_barrier(VALUE * obj, VALUE iseq)
1399{
1400 RB_OBJ_WRITTEN(iseq, Qundef, *obj);
1401 RUBY_ASSERT(SPECIAL_CONST_P(*obj) ||
1402 RBASIC_CLASS(*obj) == 0 || // hidden
1403 RB_OBJ_SHAREABLE_P(*obj));
1404}
1405
1406static INSN *
1407new_insn_core(rb_iseq_t *iseq, int line_no, int node_id, int insn_id, int argc, VALUE *argv)
1408{
1409 INSN *iobj = compile_data_alloc_insn(iseq);
1410
1411 /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1412
1413 iobj->link.type = ISEQ_ELEMENT_INSN;
1414 iobj->link.next = 0;
1415 iobj->insn_id = insn_id;
1416 iobj->insn_info.line_no = line_no;
1417 iobj->insn_info.node_id = node_id;
1418 iobj->insn_info.events = 0;
1419 iobj->operands = argv;
1420 iobj->operand_size = argc;
1421 iobj->sc_state = 0;
1422
1423 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1424
1425 return iobj;
1426}
1427
1428static INSN *
1429new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...)
1430{
1431 VALUE *operands = 0;
1432 va_list argv;
1433 if (argc > 0) {
1434 int i;
1435 va_start(argv, argc);
1436 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1437 for (i = 0; i < argc; i++) {
1438 VALUE v = va_arg(argv, VALUE);
1439 operands[i] = v;
1440 }
1441 va_end(argv);
1442 }
1443 return new_insn_core(iseq, line_no, node_id, insn_id, argc, operands);
1444}
1445
1446static INSN *
1447insn_replace_with_operands(rb_iseq_t *iseq, INSN *iobj, enum ruby_vminsn_type insn_id, int argc, ...)
1448{
1449 VALUE *operands = 0;
1450 va_list argv;
1451 if (argc > 0) {
1452 int i;
1453 va_start(argv, argc);
1454 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1455 for (i = 0; i < argc; i++) {
1456 VALUE v = va_arg(argv, VALUE);
1457 operands[i] = v;
1458 }
1459 va_end(argv);
1460 }
1461
1462 iobj->insn_id = insn_id;
1463 iobj->operand_size = argc;
1464 iobj->operands = operands;
1465 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1466
1467 return iobj;
1468}
1469
1470static const struct rb_callinfo *
1471new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1472{
1473 VM_ASSERT(argc >= 0);
1474
1475 if (kw_arg) {
1476 flag |= VM_CALL_KWARG;
1477 argc += kw_arg->keyword_len;
1478 }
1479
1480 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING))
1481 && !has_blockiseq) {
1482 flag |= VM_CALL_ARGS_SIMPLE;
1483 }
1484
1485 ISEQ_BODY(iseq)->ci_size++;
1486 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1487 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1488 return ci;
1489}
1490
1491static INSN *
1492new_insn_send(rb_iseq_t *iseq, int line_no, int node_id, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_callinfo_kwarg *keywords)
1493{
1494 VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
1495 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1496 operands[0] = ci;
1497 operands[1] = (VALUE)blockiseq;
1498 if (blockiseq) {
1499 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1500 }
1501
1502 INSN *insn;
1503
1504 if (vm_ci_flag((struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
1505 insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
1506 }
1507 else {
1508 insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1509 }
1510
1511 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1512 RB_GC_GUARD(ci);
1513 return insn;
1514}
1515
1516static rb_iseq_t *
1517new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1518 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1519{
1520 rb_iseq_t *ret_iseq;
1521 VALUE ast_value = rb_ruby_ast_new(node);
1522
1523 debugs("[new_child_iseq]> ---------------------------------------\n");
1524 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1525 ret_iseq = rb_iseq_new_with_opt(ast_value, name,
1526 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1527 line_no, parent,
1528 isolated_depth ? isolated_depth + 1 : 0,
1529 type, ISEQ_COMPILE_DATA(iseq)->option,
1530 ISEQ_BODY(iseq)->variable.script_lines);
1531 debugs("[new_child_iseq]< ---------------------------------------\n");
1532 return ret_iseq;
1533}
1534
1535static rb_iseq_t *
1536new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1537 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1538{
1539 rb_iseq_t *ret_iseq;
1540
1541 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1542 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1543 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1544 line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1545 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1546 return ret_iseq;
1547}
1548
1549static void
1550set_catch_except_p(rb_iseq_t *iseq)
1551{
1552 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1553 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1554 if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1555 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1556 set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1557 }
1558 }
1559}
1560
1561/* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1562 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1563 if catch table exists. But we want to optimize while loop, which always has catch
1564 table entries for break/next/redo.
1565
1566 So this function sets true for limited ISeqs with break/next/redo catch table entries
1567 whose child ISeq would really raise an exception. */
1568static void
1569update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
1570{
1571 unsigned int pos;
1572 size_t i;
1573 int insn;
1574 const struct iseq_catch_table *ct = body->catch_table;
1575
1576 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1577 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1578 pos = 0;
1579 while (pos < body->iseq_size) {
1580 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1581 if (insn == BIN(throw)) {
1582 set_catch_except_p(iseq);
1583 break;
1584 }
1585 pos += insn_len(insn);
1586 }
1587
1588 if (ct == NULL)
1589 return;
1590
1591 for (i = 0; i < ct->size; i++) {
1592 const struct iseq_catch_table_entry *entry =
1593 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1594 if (entry->type != CATCH_TYPE_BREAK
1595 && entry->type != CATCH_TYPE_NEXT
1596 && entry->type != CATCH_TYPE_REDO) {
1597 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1598 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1599 break;
1600 }
1601 }
1602}
1603
1604static void
1605iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1606{
1607 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1608 if (NIL_P(catch_table_ary)) return;
1609 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1610 const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
1611 for (i = 0; i < tlen; i++) {
1612 const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
1613 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1614 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1615 LINK_ELEMENT *e;
1616
1617 enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1618
1619 if (ct != CATCH_TYPE_BREAK
1620 && ct != CATCH_TYPE_NEXT
1621 && ct != CATCH_TYPE_REDO) {
1622
1623 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1624 if (e == cont) {
1625 INSN *nop = new_insn_core(iseq, 0, -1, BIN(nop), 0, 0);
1626 ELEM_INSERT_NEXT(end, &nop->link);
1627 break;
1628 }
1629 }
1630 }
1631 }
1632
1633 RB_GC_GUARD(catch_table_ary);
1634}
1635
1636static int
1637iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1638{
1639 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1640 return COMPILE_NG;
1641
1642 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1643
1644 if (compile_debug > 5)
1645 dump_disasm_list(FIRST_ELEMENT(anchor));
1646
1647 debugs("[compile step 3.1 (iseq_optimize)]\n");
1648 iseq_optimize(iseq, anchor);
1649
1650 if (compile_debug > 5)
1651 dump_disasm_list(FIRST_ELEMENT(anchor));
1652
1653 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1654 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1655 iseq_insns_unification(iseq, anchor);
1656 if (compile_debug > 5)
1657 dump_disasm_list(FIRST_ELEMENT(anchor));
1658 }
1659
1660 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1661 iseq_insert_nop_between_end_and_cont(iseq);
1662 if (compile_debug > 5)
1663 dump_disasm_list(FIRST_ELEMENT(anchor));
1664
1665 return COMPILE_OK;
1666}
1667
1668static int
1669iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1670{
1671 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1672 return COMPILE_NG;
1673
1674 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1675 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1676 if (compile_debug > 5)
1677 dump_disasm_list(FIRST_ELEMENT(anchor));
1678
1679 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1680 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1681
1682 debugs("[compile step 4.3 (set_optargs_table)] \n");
1683 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1684
1685 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1686 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1687
1688 debugs("[compile step 6 (update_catch_except_flags)] \n");
1689 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1690 update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1691
1692 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1693 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1694 if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1695 xfree(ISEQ_BODY(iseq)->catch_table);
1696 ISEQ_BODY(iseq)->catch_table = NULL;
1697 }
1698
1699#if VM_INSN_INFO_TABLE_IMPL == 2
1700 if (ISEQ_BODY(iseq)->insns_info.succ_index_table == NULL) {
1701 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1702 rb_iseq_insns_info_encode_positions(iseq);
1703 }
1704#endif
1705
1706 if (compile_debug > 1) {
1707 VALUE str = rb_iseq_disasm(iseq);
1708 printf("%s\n", StringValueCStr(str));
1709 }
1710 verify_call_cache(iseq);
1711 debugs("[compile step: finish]\n");
1712
1713 return COMPILE_OK;
1714}
1715
1716static int
1717iseq_set_exception_local_table(rb_iseq_t *iseq)
1718{
1719 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1720 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1721 ISEQ_BODY(iseq)->lvar_states = NULL; // $! is read-only, so don't need lvar_states
1722 return COMPILE_OK;
1723}
1724
1725static int
1726get_lvar_level(const rb_iseq_t *iseq)
1727{
1728 int lev = 0;
1729 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1730 lev++;
1731 iseq = ISEQ_BODY(iseq)->parent_iseq;
1732 }
1733 return lev;
1734}
1735
1736static int
1737get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1738{
1739 unsigned int i;
1740
1741 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1742 if (ISEQ_BODY(iseq)->local_table[i] == id) {
1743 return (int)i;
1744 }
1745 }
1746 return -1;
1747}
1748
1749static int
1750get_local_var_idx(const rb_iseq_t *iseq, ID id)
1751{
1752 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1753
1754 if (idx < 0) {
1755 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1756 "get_local_var_idx: %d", idx);
1757 }
1758
1759 return idx;
1760}
1761
1762static int
1763get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1764{
1765 int lv = 0, idx = -1;
1766 const rb_iseq_t *const topmost_iseq = iseq;
1767
1768 while (iseq) {
1769 idx = get_dyna_var_idx_at_raw(iseq, id);
1770 if (idx >= 0) {
1771 break;
1772 }
1773 iseq = ISEQ_BODY(iseq)->parent_iseq;
1774 lv++;
1775 }
1776
1777 if (idx < 0) {
1778 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1779 "get_dyna_var_idx: -1");
1780 }
1781
1782 *level = lv;
1783 *ls = ISEQ_BODY(iseq)->local_table_size;
1784 return idx;
1785}
1786
1787static int
1788iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1789{
1790 const struct rb_iseq_constant_body *body;
1791 while (level > 0) {
1792 iseq = ISEQ_BODY(iseq)->parent_iseq;
1793 level--;
1794 }
1795 body = ISEQ_BODY(iseq);
1796 if (body->local_iseq == iseq && /* local variables */
1797 body->param.flags.has_block &&
1798 body->local_table_size - body->param.block_start == idx) {
1799 return TRUE;
1800 }
1801 else {
1802 return FALSE;
1803 }
1804}
1805
1806static int
1807iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1808{
1809 int level, ls;
1810 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1811 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1812 *pidx = ls - idx;
1813 *plevel = level;
1814 return TRUE;
1815 }
1816 else {
1817 return FALSE;
1818 }
1819}
1820
1821static void
1822access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1823{
1824 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1825
1826 if (isolated_depth && level >= isolated_depth) {
1827 if (id == rb_intern("yield")) {
1828 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1829 }
1830 else {
1831 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable '%s' from isolated Proc", rb_id2name(id));
1832 }
1833 }
1834
1835 for (int i=0; i<level; i++) {
1836 VALUE val;
1837 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1838
1839 if (!ovs) {
1840 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1841 }
1842
1843 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1844 if (write && !val) {
1845 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1846 }
1847 }
1848 else {
1849 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1850 }
1851
1852 iseq = ISEQ_BODY(iseq)->parent_iseq;
1853 }
1854}
1855
1856static ID
1857iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1858{
1859 for (int i=0; i<level; i++) {
1860 iseq = ISEQ_BODY(iseq)->parent_iseq;
1861 }
1862
1863 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1864 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1865 return id;
1866}
1867
1868static void
1869update_lvar_state(const rb_iseq_t *iseq, int level, int idx)
1870{
1871 for (int i=0; i<level; i++) {
1872 iseq = ISEQ_BODY(iseq)->parent_iseq;
1873 }
1874
1875 enum lvar_state *states = ISEQ_BODY(iseq)->lvar_states;
1876 int table_idx = ISEQ_BODY(iseq)->local_table_size - idx;
1877 switch (states[table_idx]) {
1878 case lvar_uninitialized:
1879 states[table_idx] = lvar_initialized;
1880 break;
1881 case lvar_initialized:
1882 states[table_idx] = lvar_reassigned;
1883 break;
1884 case lvar_reassigned:
1885 /* nothing */
1886 break;
1887 default:
1888 rb_bug("unreachable");
1889 }
1890}
1891
1892static int
1893iseq_set_parameters_lvar_state(const rb_iseq_t *iseq)
1894{
1895 for (unsigned int i=0; i<ISEQ_BODY(iseq)->param.size; i++) {
1896 ISEQ_BODY(iseq)->lvar_states[i] = lvar_initialized;
1897 }
1898
1899 int lead_num = ISEQ_BODY(iseq)->param.lead_num;
1900 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
1901 for (int i=0; i<opt_num; i++) {
1902 ISEQ_BODY(iseq)->lvar_states[lead_num + i] = lvar_uninitialized;
1903 }
1904
1905 return COMPILE_OK;
1906}
1907
1908static void
1909iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1910{
1911 if (iseq_local_block_param_p(iseq, idx, level)) {
1912 ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1913 }
1914 else {
1915 ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1916 }
1917 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1918}
1919
1920static void
1921iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1922{
1923 if (iseq_local_block_param_p(iseq, idx, level)) {
1924 ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1925 }
1926 else {
1927 ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1928 }
1929 update_lvar_state(iseq, level, idx);
1930 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1931}
1932
1933
1934
1935static void
1936iseq_calc_param_size(rb_iseq_t *iseq)
1937{
1938 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1939 if (body->param.flags.has_opt ||
1940 body->param.flags.has_post ||
1941 body->param.flags.has_rest ||
1942 body->param.flags.has_block ||
1943 body->param.flags.has_kw ||
1944 body->param.flags.has_kwrest) {
1945
1946 if (body->param.flags.has_block) {
1947 body->param.size = body->param.block_start + 1;
1948 }
1949 else if (body->param.flags.has_kwrest) {
1950 body->param.size = body->param.keyword->rest_start + 1;
1951 }
1952 else if (body->param.flags.has_kw) {
1953 body->param.size = body->param.keyword->bits_start + 1;
1954 }
1955 else if (body->param.flags.has_post) {
1956 body->param.size = body->param.post_start + body->param.post_num;
1957 }
1958 else if (body->param.flags.has_rest) {
1959 body->param.size = body->param.rest_start + 1;
1960 }
1961 else if (body->param.flags.has_opt) {
1962 body->param.size = body->param.lead_num + body->param.opt_num;
1963 }
1964 else {
1965 UNREACHABLE;
1966 }
1967 }
1968 else {
1969 body->param.size = body->param.lead_num;
1970 }
1971}
1972
1973static int
1974iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
1975 const struct rb_args_info *args, int arg_size)
1976{
1977 const rb_node_kw_arg_t *node = args->kw_args;
1978 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1979 struct rb_iseq_param_keyword *keyword;
1980 const VALUE default_values = rb_ary_hidden_new(1);
1981 const VALUE complex_mark = rb_str_tmp_new(0);
1982 int kw = 0, rkw = 0, di = 0, i;
1983
1984 body->param.flags.has_kw = TRUE;
1985 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1986
1987 while (node) {
1988 kw++;
1989 node = node->nd_next;
1990 }
1991 arg_size += kw;
1992 keyword->bits_start = arg_size++;
1993
1994 node = args->kw_args;
1995 while (node) {
1996 const NODE *val_node = get_nd_value(node->nd_body);
1997 VALUE dv;
1998
1999 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
2000 ++rkw;
2001 }
2002 else {
2003 switch (nd_type(val_node)) {
2004 case NODE_SYM:
2005 dv = rb_node_sym_string_val(val_node);
2006 break;
2007 case NODE_REGX:
2008 dv = rb_node_regx_string_val(val_node);
2009 break;
2010 case NODE_LINE:
2011 dv = rb_node_line_lineno_val(val_node);
2012 break;
2013 case NODE_INTEGER:
2014 dv = rb_node_integer_literal_val(val_node);
2015 break;
2016 case NODE_FLOAT:
2017 dv = rb_node_float_literal_val(val_node);
2018 break;
2019 case NODE_RATIONAL:
2020 dv = rb_node_rational_literal_val(val_node);
2021 break;
2022 case NODE_IMAGINARY:
2023 dv = rb_node_imaginary_literal_val(val_node);
2024 break;
2025 case NODE_ENCODING:
2026 dv = rb_node_encoding_val(val_node);
2027 break;
2028 case NODE_NIL:
2029 dv = Qnil;
2030 break;
2031 case NODE_TRUE:
2032 dv = Qtrue;
2033 break;
2034 case NODE_FALSE:
2035 dv = Qfalse;
2036 break;
2037 default:
2038 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
2039 dv = complex_mark;
2040 }
2041
2042 keyword->num = ++di;
2043 rb_ary_push(default_values, dv);
2044 }
2045
2046 node = node->nd_next;
2047 }
2048
2049 keyword->num = kw;
2050
2051 if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
2052 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2053 keyword->rest_start = arg_size++;
2054 body->param.flags.has_kwrest = TRUE;
2055
2056 if (kw_id == idPow) body->param.flags.anon_kwrest = TRUE;
2057 }
2058 keyword->required_num = rkw;
2059 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
2060
2061 if (RARRAY_LEN(default_values)) {
2062 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
2063
2064 for (i = 0; i < RARRAY_LEN(default_values); i++) {
2065 VALUE dv = RARRAY_AREF(default_values, i);
2066 if (dv == complex_mark) dv = Qundef;
2067 if (!SPECIAL_CONST_P(dv)) rb_ractor_make_shareable(dv);
2068 RB_OBJ_WRITE(iseq, &dvs[i], dv);
2069 }
2070
2071 keyword->default_values = dvs;
2072 }
2073 return arg_size;
2074}
2075
2076static void
2077iseq_set_use_block(rb_iseq_t *iseq)
2078{
2079 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2080 if (!body->param.flags.use_block) {
2081 body->param.flags.use_block = 1;
2082
2083 rb_vm_t *vm = GET_VM();
2084
2085 if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
2086 st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
2087 set_insert(vm->unused_block_warning_table, key);
2088 }
2089 }
2090}
2091
2092static int
2093iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
2094{
2095 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
2096
2097 if (node_args) {
2098 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2099 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2100 ID rest_id = 0;
2101 int last_comma = 0;
2102 ID block_id = 0;
2103 int arg_size;
2104
2105 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
2106
2107 body->param.lead_num = arg_size = (int)args->pre_args_num;
2108 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
2109 debugs(" - argc: %d\n", body->param.lead_num);
2110
2111 rest_id = args->rest_arg;
2112 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2113 last_comma = 1;
2114 rest_id = 0;
2115 }
2116 block_id = args->block_arg;
2117
2118 bool optimized_forward = (args->forwarding && args->pre_args_num == 0 && !args->opt_args);
2119
2120 if (optimized_forward) {
2121 rest_id = 0;
2122 block_id = 0;
2123 }
2124
2125 if (args->opt_args) {
2126 const rb_node_opt_arg_t *node = args->opt_args;
2127 LABEL *label;
2128 VALUE labels = rb_ary_hidden_new(1);
2129 VALUE *opt_table;
2130 int i = 0, j;
2131
2132 while (node) {
2133 label = NEW_LABEL(nd_line(RNODE(node)));
2134 rb_ary_push(labels, (VALUE)label | 1);
2135 ADD_LABEL(optargs, label);
2136 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
2137 node = node->nd_next;
2138 i += 1;
2139 }
2140
2141 /* last label */
2142 label = NEW_LABEL(nd_line(node_args));
2143 rb_ary_push(labels, (VALUE)label | 1);
2144 ADD_LABEL(optargs, label);
2145
2146 opt_table = ALLOC_N(VALUE, i+1);
2147
2148 MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
2149 for (j = 0; j < i+1; j++) {
2150 opt_table[j] &= ~1;
2151 }
2152 rb_ary_clear(labels);
2153
2154 body->param.flags.has_opt = TRUE;
2155 body->param.opt_num = i;
2156 body->param.opt_table = opt_table;
2157 arg_size += i;
2158 }
2159
2160 if (rest_id) {
2161 body->param.rest_start = arg_size++;
2162 body->param.flags.has_rest = TRUE;
2163 if (rest_id == '*') body->param.flags.anon_rest = TRUE;
2164 RUBY_ASSERT(body->param.rest_start != -1);
2165 }
2166
2167 if (args->first_post_arg) {
2168 body->param.post_start = arg_size;
2169 body->param.post_num = args->post_args_num;
2170 body->param.flags.has_post = TRUE;
2171 arg_size += args->post_args_num;
2172
2173 if (body->param.flags.has_rest) { /* TODO: why that? */
2174 body->param.post_start = body->param.rest_start + 1;
2175 }
2176 }
2177
2178 if (args->kw_args) {
2179 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2180 }
2181 else if (args->kw_rest_arg && !optimized_forward) {
2182 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2183 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2184 keyword->rest_start = arg_size++;
2185 body->param.keyword = keyword;
2186 body->param.flags.has_kwrest = TRUE;
2187
2188 static ID anon_kwrest = 0;
2189 if (!anon_kwrest) anon_kwrest = rb_intern("**");
2190 if (kw_id == anon_kwrest) body->param.flags.anon_kwrest = TRUE;
2191 }
2192 else if (args->no_kwarg) {
2193 body->param.flags.accepts_no_kwarg = TRUE;
2194 }
2195
2196 if (block_id) {
2197 body->param.block_start = arg_size++;
2198 body->param.flags.has_block = TRUE;
2199 iseq_set_use_block(iseq);
2200 }
2201
2202 // Only optimize specifically methods like this: `foo(...)`
2203 if (optimized_forward) {
2204 body->param.flags.use_block = 1;
2205 body->param.flags.forwardable = TRUE;
2206 arg_size = 1;
2207 }
2208
2209 iseq_calc_param_size(iseq);
2210 body->param.size = arg_size;
2211
2212 if (args->pre_init) { /* m_init */
2213 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
2214 }
2215 if (args->post_init) { /* p_init */
2216 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
2217 }
2218
2219 if (body->type == ISEQ_TYPE_BLOCK) {
2220 if (body->param.flags.has_opt == FALSE &&
2221 body->param.flags.has_post == FALSE &&
2222 body->param.flags.has_rest == FALSE &&
2223 body->param.flags.has_kw == FALSE &&
2224 body->param.flags.has_kwrest == FALSE) {
2225
2226 if (body->param.lead_num == 1 && last_comma == 0) {
2227 /* {|a|} */
2228 body->param.flags.ambiguous_param0 = TRUE;
2229 }
2230 }
2231 }
2232 }
2233
2234 return COMPILE_OK;
2235}
2236
2237static int
2238iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args)
2239{
2240 unsigned int size = tbl ? tbl->size : 0;
2241 unsigned int offset = 0;
2242
2243 if (node_args) {
2244 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2245
2246 // If we have a function that only has `...` as the parameter,
2247 // then its local table should only be `...`
2248 // FIXME: I think this should be fixed in the AST rather than special case here.
2249 if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
2250 CHECK(size >= 3);
2251 size -= 3;
2252 offset += 3;
2253 }
2254 }
2255
2256 if (size > 0) {
2257 ID *ids = ALLOC_N(ID, size);
2258 MEMCPY(ids, tbl->ids + offset, ID, size);
2259 ISEQ_BODY(iseq)->local_table = ids;
2260
2261 enum lvar_state *states = ALLOC_N(enum lvar_state, size);
2262 // fprintf(stderr, "iseq:%p states:%p size:%d\n", iseq, states, (int)size);
2263 for (unsigned int i=0; i<size; i++) {
2264 states[i] = lvar_uninitialized;
2265 // fprintf(stderr, "id:%s\n", rb_id2name(ISEQ_BODY(iseq)->local_table[i]));
2266 }
2267 ISEQ_BODY(iseq)->lvar_states = states;
2268 }
2269 ISEQ_BODY(iseq)->local_table_size = size;
2270
2271 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2272 return COMPILE_OK;
2273}
2274
2275int
2276rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
2277{
2278 int tval, tlit;
2279
2280 if (val == lit) {
2281 return 0;
2282 }
2283 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2284 return val != lit;
2285 }
2286 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2287 return -1;
2288 }
2289 else if (tlit != tval) {
2290 return -1;
2291 }
2292 else if (tlit == T_SYMBOL) {
2293 return val != lit;
2294 }
2295 else if (tlit == T_STRING) {
2296 return rb_str_hash_cmp(lit, val);
2297 }
2298 else if (tlit == T_BIGNUM) {
2299 long x = FIX2LONG(rb_big_cmp(lit, val));
2300
2301 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2302 * There is no need to call rb_fix2int here. */
2303 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2304 return (int)x;
2305 }
2306 else if (tlit == T_FLOAT) {
2307 return rb_float_cmp(lit, val);
2308 }
2309 else if (tlit == T_RATIONAL) {
2310 const struct RRational *rat1 = RRATIONAL(val);
2311 const struct RRational *rat2 = RRATIONAL(lit);
2312 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2313 }
2314 else if (tlit == T_COMPLEX) {
2315 const struct RComplex *comp1 = RCOMPLEX(val);
2316 const struct RComplex *comp2 = RCOMPLEX(lit);
2317 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2318 }
2319 else if (tlit == T_REGEXP) {
2320 return rb_reg_equal(val, lit) ? 0 : -1;
2321 }
2322 else {
2323 UNREACHABLE_RETURN(-1);
2324 }
2325}
2326
2327st_index_t
2328rb_iseq_cdhash_hash(VALUE a)
2329{
2330 switch (OBJ_BUILTIN_TYPE(a)) {
2331 case -1:
2332 case T_SYMBOL:
2333 return (st_index_t)a;
2334 case T_STRING:
2335 return rb_str_hash(a);
2336 case T_BIGNUM:
2337 return FIX2LONG(rb_big_hash(a));
2338 case T_FLOAT:
2339 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2340 case T_RATIONAL:
2341 return rb_rational_hash(a);
2342 case T_COMPLEX:
2343 return rb_complex_hash(a);
2344 case T_REGEXP:
2345 return NUM2LONG(rb_reg_hash(a));
2346 default:
2347 UNREACHABLE_RETURN(0);
2348 }
2349}
2350
2351static const struct st_hash_type cdhash_type = {
2352 rb_iseq_cdhash_cmp,
2353 rb_iseq_cdhash_hash,
2354};
2355
2356 struct cdhash_set_label_struct {
2357 VALUE hash;
2358 int pos;
2359 int len;
2360};
2361
2362static int
2363cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
2364{
2365 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2366 LABEL *lobj = (LABEL *)(val & ~1);
2367 rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
2368 return ST_CONTINUE;
2369}
2370
2371
2372static inline VALUE
2373get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2374{
2375 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2376}
2377
2378static inline VALUE
2379get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2380{
2381 VALUE val;
2382 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2383 if (tbl) {
2384 if (rb_id_table_lookup(tbl,id,&val)) {
2385 return val;
2386 }
2387 }
2388 else {
2389 tbl = rb_id_table_create(1);
2390 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2391 }
2392 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2393 rb_id_table_insert(tbl,id,val);
2394 return val;
2395}
2396
2397#define BADINSN_DUMP(anchor, list, dest) \
2398 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2399
2400#define BADINSN_ERROR \
2401 (xfree(generated_iseq), \
2402 xfree(insns_info), \
2403 BADINSN_DUMP(anchor, list, NULL), \
2404 COMPILE_ERROR)
2405
2406static int
2407fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2408{
2409 int stack_max = 0, sp = 0, line = 0;
2410 LINK_ELEMENT *list;
2411
2412 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2413 if (IS_LABEL(list)) {
2414 LABEL *lobj = (LABEL *)list;
2415 lobj->set = TRUE;
2416 }
2417 }
2418
2419 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2420 switch (list->type) {
2421 case ISEQ_ELEMENT_INSN:
2422 {
2423 int j, len, insn;
2424 const char *types;
2425 VALUE *operands;
2426 INSN *iobj = (INSN *)list;
2427
2428 /* update sp */
2429 sp = calc_sp_depth(sp, iobj);
2430 if (sp < 0) {
2431 BADINSN_DUMP(anchor, list, NULL);
2432 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2433 "argument stack underflow (%d)", sp);
2434 return -1;
2435 }
2436 if (sp > stack_max) {
2437 stack_max = sp;
2438 }
2439
2440 line = iobj->insn_info.line_no;
2441 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2442 operands = iobj->operands;
2443 insn = iobj->insn_id;
2444 types = insn_op_types(insn);
2445 len = insn_len(insn);
2446
2447 /* operand check */
2448 if (iobj->operand_size != len - 1) {
2449 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2450 BADINSN_DUMP(anchor, list, NULL);
2451 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2452 "operand size miss! (%d for %d)",
2453 iobj->operand_size, len - 1);
2454 return -1;
2455 }
2456
2457 for (j = 0; types[j]; j++) {
2458 if (types[j] == TS_OFFSET) {
2459 /* label(destination position) */
2460 LABEL *lobj = (LABEL *)operands[j];
2461 if (!lobj->set) {
2462 BADINSN_DUMP(anchor, list, NULL);
2463 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2464 "unknown label: "LABEL_FORMAT, lobj->label_no);
2465 return -1;
2466 }
2467 if (lobj->sp == -1) {
2468 lobj->sp = sp;
2469 }
2470 else if (lobj->sp != sp) {
2471 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2472 RSTRING_PTR(rb_iseq_path(iseq)), line,
2473 lobj->label_no, lobj->sp, sp);
2474 }
2475 }
2476 }
2477 break;
2478 }
2479 case ISEQ_ELEMENT_LABEL:
2480 {
2481 LABEL *lobj = (LABEL *)list;
2482 if (lobj->sp == -1) {
2483 lobj->sp = sp;
2484 }
2485 else {
2486 if (lobj->sp != sp) {
2487 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2488 RSTRING_PTR(rb_iseq_path(iseq)), line,
2489 lobj->label_no, lobj->sp, sp);
2490 }
2491 sp = lobj->sp;
2492 }
2493 break;
2494 }
2495 case ISEQ_ELEMENT_TRACE:
2496 {
2497 /* ignore */
2498 break;
2499 }
2500 case ISEQ_ELEMENT_ADJUST:
2501 {
2502 ADJUST *adjust = (ADJUST *)list;
2503 int orig_sp = sp;
2504
2505 sp = adjust->label ? adjust->label->sp : 0;
2506 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2507 BADINSN_DUMP(anchor, list, NULL);
2508 COMPILE_ERROR(iseq, adjust->line_no,
2509 "iseq_set_sequence: adjust bug %d < %d",
2510 orig_sp, sp);
2511 return -1;
2512 }
2513 break;
2514 }
2515 default:
2516 BADINSN_DUMP(anchor, list, NULL);
2517 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2518 return -1;
2519 }
2520 }
2521 return stack_max;
2522}
2523
2524static int
2525add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2526 int insns_info_index, int code_index, const INSN *iobj)
2527{
2528 if (insns_info_index == 0 ||
2529 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2530#ifdef USE_ISEQ_NODE_ID
2531 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2532#endif
2533 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2534 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2535#ifdef USE_ISEQ_NODE_ID
2536 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2537#endif
2538 insns_info[insns_info_index].events = iobj->insn_info.events;
2539 positions[insns_info_index] = code_index;
2540 return TRUE;
2541 }
2542 return FALSE;
2543}
2544
2545static int
2546add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2547 int insns_info_index, int code_index, const ADJUST *adjust)
2548{
2549 insns_info[insns_info_index].line_no = adjust->line_no;
2550 insns_info[insns_info_index].node_id = -1;
2551 insns_info[insns_info_index].events = 0;
2552 positions[insns_info_index] = code_index;
2553 return TRUE;
2554}
2555
2556static ID *
2557array_to_idlist(VALUE arr)
2558{
2559 RUBY_ASSERT(RB_TYPE_P(arr, T_ARRAY));
2560 long size = RARRAY_LEN(arr);
2561 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2562 for (long i = 0; i < size; i++) {
2563 VALUE sym = RARRAY_AREF(arr, i);
2564 ids[i] = SYM2ID(sym);
2565 }
2566 ids[size] = 0;
2567 return ids;
2568}
2569
2570static VALUE
2571idlist_to_array(const ID *ids)
2572{
2573 VALUE arr = rb_ary_new();
2574 while (*ids) {
2575 rb_ary_push(arr, ID2SYM(*ids++));
2576 }
2577 return arr;
2578}
2579
2583static int
2584iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2585{
2586 struct iseq_insn_info_entry *insns_info;
2587 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2588 unsigned int *positions;
2589 LINK_ELEMENT *list;
2590 VALUE *generated_iseq;
2591 rb_event_flag_t events = 0;
2592 long data = 0;
2593
2594 int insn_num, code_index, insns_info_index, sp = 0;
2595 int stack_max = fix_sp_depth(iseq, anchor);
2596
2597 if (stack_max < 0) return COMPILE_NG;
2598
2599 /* fix label position */
2600 insn_num = code_index = 0;
2601 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2602 switch (list->type) {
2603 case ISEQ_ELEMENT_INSN:
2604 {
2605 INSN *iobj = (INSN *)list;
2606 /* update sp */
2607 sp = calc_sp_depth(sp, iobj);
2608 insn_num++;
2609 events = iobj->insn_info.events |= events;
2610 if (ISEQ_COVERAGE(iseq)) {
2611 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2612 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2613 int line = iobj->insn_info.line_no - 1;
2614 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2615 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2616 }
2617 }
2618 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2619 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2620 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2621 }
2622 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2623 }
2624 }
2625 code_index += insn_data_length(iobj);
2626 events = 0;
2627 data = 0;
2628 break;
2629 }
2630 case ISEQ_ELEMENT_LABEL:
2631 {
2632 LABEL *lobj = (LABEL *)list;
2633 lobj->position = code_index;
2634 if (lobj->sp != sp) {
2635 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2636 RSTRING_PTR(rb_iseq_path(iseq)),
2637 lobj->label_no, lobj->sp, sp);
2638 }
2639 sp = lobj->sp;
2640 break;
2641 }
2642 case ISEQ_ELEMENT_TRACE:
2643 {
2644 TRACE *trace = (TRACE *)list;
2645 events |= trace->event;
2646 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2647 break;
2648 }
2649 case ISEQ_ELEMENT_ADJUST:
2650 {
2651 ADJUST *adjust = (ADJUST *)list;
2652 if (adjust->line_no != -1) {
2653 int orig_sp = sp;
2654 sp = adjust->label ? adjust->label->sp : 0;
2655 if (orig_sp - sp > 0) {
2656 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2657 code_index++; /* insn */
2658 insn_num++;
2659 }
2660 }
2661 break;
2662 }
2663 default: break;
2664 }
2665 }
2666
2667 /* make instruction sequence */
2668 generated_iseq = ALLOC_N(VALUE, code_index);
2669 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2670 positions = ALLOC_N(unsigned int, insn_num);
2671 if (ISEQ_IS_SIZE(body)) {
2672 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2673 }
2674 else {
2675 body->is_entries = NULL;
2676 }
2677
2678 if (body->ci_size) {
2679 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2680 }
2681 else {
2682 body->call_data = NULL;
2683 }
2684 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2685
2686 // Calculate the bitmask buffer size.
2687 // Round the generated_iseq size up to the nearest multiple
2688 // of the number of bits in an unsigned long.
2689
2690 // Allocate enough room for the bitmask list
2691 iseq_bits_t * mark_offset_bits;
2692 int code_size = code_index;
2693
2694 bool needs_bitmap = false;
2695
2696 if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
2697 mark_offset_bits = &ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2698 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = true;
2699 }
2700 else {
2701 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
2702 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = mark_offset_bits;
2703 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = false;
2704 }
2705
2706 ISEQ_COMPILE_DATA(iseq)->iseq_encoded = (void *)generated_iseq;
2707 ISEQ_COMPILE_DATA(iseq)->iseq_size = code_index;
2708
2709 list = FIRST_ELEMENT(anchor);
2710 insns_info_index = code_index = sp = 0;
2711
2712 while (list) {
2713 switch (list->type) {
2714 case ISEQ_ELEMENT_INSN:
2715 {
2716 int j, len, insn;
2717 const char *types;
2718 VALUE *operands;
2719 INSN *iobj = (INSN *)list;
2720
2721 /* update sp */
2722 sp = calc_sp_depth(sp, iobj);
2723 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2724 operands = iobj->operands;
2725 insn = iobj->insn_id;
2726 generated_iseq[code_index] = insn;
2727 types = insn_op_types(insn);
2728 len = insn_len(insn);
2729
2730 for (j = 0; types[j]; j++) {
2731 char type = types[j];
2732
2733 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2734 switch (type) {
2735 case TS_OFFSET:
2736 {
2737 /* label(destination position) */
2738 LABEL *lobj = (LABEL *)operands[j];
2739 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2740 break;
2741 }
2742 case TS_CDHASH:
2743 {
2744 VALUE map = operands[j];
2745 struct cdhash_set_label_struct data;
2746 data.hash = map;
2747 data.pos = code_index;
2748 data.len = len;
2749 rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2750
2751 rb_hash_rehash(map);
2752 freeze_hide_obj(map);
2753 rb_ractor_make_shareable(map);
2754 generated_iseq[code_index + 1 + j] = map;
2755 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2756 RB_OBJ_WRITTEN(iseq, Qundef, map);
2757 needs_bitmap = true;
2758 break;
2759 }
2760 case TS_LINDEX:
2761 case TS_NUM: /* ulong */
2762 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2763 break;
2764 case TS_ISEQ: /* iseq */
2765 case TS_VALUE: /* VALUE */
2766 {
2767 VALUE v = operands[j];
2768 generated_iseq[code_index + 1 + j] = v;
2769 /* to mark ruby object */
2770 if (!SPECIAL_CONST_P(v)) {
2771 RB_OBJ_WRITTEN(iseq, Qundef, v);
2772 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2773 needs_bitmap = true;
2774 }
2775 break;
2776 }
2777 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2778 case TS_IC: /* inline cache: constants */
2779 {
2780 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2781 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2782 if (UNLIKELY(ic_index >= body->ic_size)) {
2783 BADINSN_DUMP(anchor, &iobj->link, 0);
2784 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2785 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2786 ic_index, ISEQ_IS_SIZE(body));
2787 }
2788
2789 ic->segments = array_to_idlist(operands[j]);
2790
2791 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2792 }
2793 break;
2794 case TS_IVC: /* inline ivar cache */
2795 {
2796 unsigned int ic_index = FIX2UINT(operands[j]);
2797
2798 IVC cache = ((IVC)&body->is_entries[ic_index]);
2799
2800 if (insn == BIN(setinstancevariable)) {
2801 cache->iv_set_name = SYM2ID(operands[j - 1]);
2802 }
2803 else {
2804 cache->iv_set_name = 0;
2805 }
2806
2807 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
2808 }
2809 case TS_ISE: /* inline storage entry: `once` insn */
2810 case TS_ICVARC: /* inline cvar cache */
2811 {
2812 unsigned int ic_index = FIX2UINT(operands[j]);
2813 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2814 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2815 BADINSN_DUMP(anchor, &iobj->link, 0);
2816 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2817 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2818 ic_index, ISEQ_IS_SIZE(body));
2819 }
2820 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2821
2822 break;
2823 }
2824 case TS_CALLDATA:
2825 {
2826 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2827 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2828 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2829 cd->ci = source_ci;
2830 cd->cc = vm_cc_empty();
2831 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2832 break;
2833 }
2834 case TS_ID: /* ID */
2835 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2836 break;
2837 case TS_FUNCPTR:
2838 generated_iseq[code_index + 1 + j] = operands[j];
2839 break;
2840 case TS_BUILTIN:
2841 generated_iseq[code_index + 1 + j] = operands[j];
2842 break;
2843 default:
2844 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2845 "unknown operand type: %c", type);
2846 return COMPILE_NG;
2847 }
2848 }
2849 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2850 code_index += len;
2851 break;
2852 }
2853 case ISEQ_ELEMENT_LABEL:
2854 {
2855 LABEL *lobj = (LABEL *)list;
2856 if (lobj->sp != sp) {
2857 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2858 RSTRING_PTR(rb_iseq_path(iseq)),
2859 lobj->label_no, lobj->sp, sp);
2860 }
2861 sp = lobj->sp;
2862 break;
2863 }
2864 case ISEQ_ELEMENT_ADJUST:
2865 {
2866 ADJUST *adjust = (ADJUST *)list;
2867 int orig_sp = sp;
2868
2869 if (adjust->label) {
2870 sp = adjust->label->sp;
2871 }
2872 else {
2873 sp = 0;
2874 }
2875
2876 if (adjust->line_no != -1) {
2877 const int diff = orig_sp - sp;
2878 if (diff > 0) {
2879 if (insns_info_index == 0) {
2880 COMPILE_ERROR(iseq, adjust->line_no,
2881 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2882 }
2883 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2884 }
2885 if (diff > 1) {
2886 generated_iseq[code_index++] = BIN(adjuststack);
2887 generated_iseq[code_index++] = orig_sp - sp;
2888 }
2889 else if (diff == 1) {
2890 generated_iseq[code_index++] = BIN(pop);
2891 }
2892 else if (diff < 0) {
2893 int label_no = adjust->label ? adjust->label->label_no : -1;
2894 xfree(generated_iseq);
2895 xfree(insns_info);
2896 xfree(positions);
2897 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2898 xfree(mark_offset_bits);
2899 }
2900 debug_list(anchor, list);
2901 COMPILE_ERROR(iseq, adjust->line_no,
2902 "iseq_set_sequence: adjust bug to %d %d < %d",
2903 label_no, orig_sp, sp);
2904 return COMPILE_NG;
2905 }
2906 }
2907 break;
2908 }
2909 default:
2910 /* ignore */
2911 break;
2912 }
2913 list = list->next;
2914 }
2915
2916 body->iseq_encoded = (void *)generated_iseq;
2917 body->iseq_size = code_index;
2918 body->stack_max = stack_max;
2919
2920 if (ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit) {
2921 body->mark_bits.single = ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2922 }
2923 else {
2924 if (needs_bitmap) {
2925 body->mark_bits.list = mark_offset_bits;
2926 }
2927 else {
2928 body->mark_bits.list = NULL;
2929 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = NULL;
2930 ruby_xfree(mark_offset_bits);
2931 }
2932 }
2933
2934 /* get rid of memory leak when REALLOC failed */
2935 body->insns_info.body = insns_info;
2936 body->insns_info.positions = positions;
2937
2938 REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
2939 body->insns_info.body = insns_info;
2940 REALLOC_N(positions, unsigned int, insns_info_index);
2941 body->insns_info.positions = positions;
2942 body->insns_info.size = insns_info_index;
2943
2944 return COMPILE_OK;
2945}
2946
2947static int
2948label_get_position(LABEL *lobj)
2949{
2950 return lobj->position;
2951}
2952
2953static int
2954label_get_sp(LABEL *lobj)
2955{
2956 return lobj->sp;
2957}
2958
2959static int
2960iseq_set_exception_table(rb_iseq_t *iseq)
2961{
2962 const VALUE *tptr, *ptr;
2963 unsigned int tlen, i;
2964 struct iseq_catch_table_entry *entry;
2965
2966 ISEQ_BODY(iseq)->catch_table = NULL;
2967
2968 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
2969 if (NIL_P(catch_table_ary)) return COMPILE_OK;
2970 tlen = (int)RARRAY_LEN(catch_table_ary);
2971 tptr = RARRAY_CONST_PTR(catch_table_ary);
2972
2973 if (tlen > 0) {
2974 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2975 table->size = tlen;
2976
2977 for (i = 0; i < table->size; i++) {
2978 int pos;
2979 ptr = RARRAY_CONST_PTR(tptr[i]);
2980 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2981 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
2982 pos = label_get_position((LABEL *)(ptr[1] & ~1));
2983 RUBY_ASSERT(pos >= 0);
2984 entry->start = (unsigned int)pos;
2985 pos = label_get_position((LABEL *)(ptr[2] & ~1));
2986 RUBY_ASSERT(pos >= 0);
2987 entry->end = (unsigned int)pos;
2988 entry->iseq = (rb_iseq_t *)ptr[3];
2989 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2990
2991 /* stack depth */
2992 if (ptr[4]) {
2993 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2994 entry->cont = label_get_position(lobj);
2995 entry->sp = label_get_sp(lobj);
2996
2997 /* TODO: Dirty Hack! Fix me */
2998 if (entry->type == CATCH_TYPE_RESCUE ||
2999 entry->type == CATCH_TYPE_BREAK ||
3000 entry->type == CATCH_TYPE_NEXT) {
3001 RUBY_ASSERT(entry->sp > 0);
3002 entry->sp--;
3003 }
3004 }
3005 else {
3006 entry->cont = 0;
3007 }
3008 }
3009 ISEQ_BODY(iseq)->catch_table = table;
3010 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
3011 }
3012
3013 RB_GC_GUARD(catch_table_ary);
3014
3015 return COMPILE_OK;
3016}
3017
3018/*
3019 * set optional argument table
3020 * def foo(a, b=expr1, c=expr2)
3021 * =>
3022 * b:
3023 * expr1
3024 * c:
3025 * expr2
3026 */
3027static int
3028iseq_set_optargs_table(rb_iseq_t *iseq)
3029{
3030 int i;
3031 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
3032
3033 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
3034 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
3035 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
3036 }
3037 }
3038 return COMPILE_OK;
3039}
3040
3041static LINK_ELEMENT *
3042get_destination_insn(INSN *iobj)
3043{
3044 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
3045 LINK_ELEMENT *list;
3046 rb_event_flag_t events = 0;
3047
3048 list = lobj->link.next;
3049 while (list) {
3050 switch (list->type) {
3051 case ISEQ_ELEMENT_INSN:
3052 case ISEQ_ELEMENT_ADJUST:
3053 goto found;
3054 case ISEQ_ELEMENT_LABEL:
3055 /* ignore */
3056 break;
3057 case ISEQ_ELEMENT_TRACE:
3058 {
3059 TRACE *trace = (TRACE *)list;
3060 events |= trace->event;
3061 }
3062 break;
3063 default: break;
3064 }
3065 list = list->next;
3066 }
3067 found:
3068 if (list && IS_INSN(list)) {
3069 INSN *iobj = (INSN *)list;
3070 iobj->insn_info.events |= events;
3071 }
3072 return list;
3073}
3074
3075static LINK_ELEMENT *
3076get_next_insn(INSN *iobj)
3077{
3078 LINK_ELEMENT *list = iobj->link.next;
3079
3080 while (list) {
3081 if (IS_INSN(list) || IS_ADJUST(list)) {
3082 return list;
3083 }
3084 list = list->next;
3085 }
3086 return 0;
3087}
3088
3089static LINK_ELEMENT *
3090get_prev_insn(INSN *iobj)
3091{
3092 LINK_ELEMENT *list = iobj->link.prev;
3093
3094 while (list) {
3095 if (IS_INSN(list) || IS_ADJUST(list)) {
3096 return list;
3097 }
3098 list = list->prev;
3099 }
3100 return 0;
3101}
3102
3103static void
3104unref_destination(INSN *iobj, int pos)
3105{
3106 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3107 --lobj->refcnt;
3108 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3109}
3110
3111static bool
3112replace_destination(INSN *dobj, INSN *nobj)
3113{
3114 VALUE n = OPERAND_AT(nobj, 0);
3115 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3116 LABEL *nl = (LABEL *)n;
3117 if (dl == nl) return false;
3118 --dl->refcnt;
3119 ++nl->refcnt;
3120 OPERAND_AT(dobj, 0) = n;
3121 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3122 return true;
3123}
3124
3125static LABEL*
3126find_destination(INSN *i)
3127{
3128 int pos, len = insn_len(i->insn_id);
3129 for (pos = 0; pos < len; ++pos) {
3130 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3131 return (LABEL *)OPERAND_AT(i, pos);
3132 }
3133 }
3134 return 0;
3135}
3136
3137static int
3138remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
3139{
3140 LINK_ELEMENT *first = i, *end;
3141 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
3142
3143 if (!i) return 0;
3144 unref_counts = ALLOCA_N(int, nlabels);
3145 MEMZERO(unref_counts, int, nlabels);
3146 end = i;
3147 do {
3148 LABEL *lab;
3149 if (IS_INSN(i)) {
3150 if (IS_INSN_ID(i, leave)) {
3151 end = i;
3152 break;
3153 }
3154 else if ((lab = find_destination((INSN *)i)) != 0) {
3155 unref_counts[lab->label_no]++;
3156 }
3157 }
3158 else if (IS_LABEL(i)) {
3159 lab = (LABEL *)i;
3160 if (lab->unremovable) return 0;
3161 if (lab->refcnt > unref_counts[lab->label_no]) {
3162 if (i == first) return 0;
3163 break;
3164 }
3165 continue;
3166 }
3167 else if (IS_TRACE(i)) {
3168 /* do nothing */
3169 }
3170 else if (IS_ADJUST(i)) {
3171 return 0;
3172 }
3173 end = i;
3174 } while ((i = i->next) != 0);
3175 i = first;
3176 do {
3177 if (IS_INSN(i)) {
3178 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3179 VALUE insn = INSN_OF(i);
3180 int pos, len = insn_len(insn);
3181 for (pos = 0; pos < len; ++pos) {
3182 switch (insn_op_types(insn)[pos]) {
3183 case TS_OFFSET:
3184 unref_destination((INSN *)i, pos);
3185 break;
3186 case TS_CALLDATA:
3187 --(body->ci_size);
3188 break;
3189 }
3190 }
3191 }
3192 ELEM_REMOVE(i);
3193 } while ((i != end) && (i = i->next) != 0);
3194 return 1;
3195}
3196
3197static int
3198iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3199{
3200 switch (OPERAND_AT(iobj, 0)) {
3201 case INT2FIX(0): /* empty array */
3202 ELEM_REMOVE(&iobj->link);
3203 return TRUE;
3204 case INT2FIX(1): /* single element array */
3205 ELEM_REMOVE(&iobj->link);
3206 return FALSE;
3207 default:
3208 iobj->insn_id = BIN(adjuststack);
3209 return TRUE;
3210 }
3211}
3212
3213static int
3214is_frozen_putstring(INSN *insn, VALUE *op)
3215{
3216 if (IS_INSN_ID(insn, putstring) || IS_INSN_ID(insn, putchilledstring)) {
3217 *op = OPERAND_AT(insn, 0);
3218 return 1;
3219 }
3220 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3221 *op = OPERAND_AT(insn, 0);
3222 return RB_TYPE_P(*op, T_STRING);
3223 }
3224 return 0;
3225}
3226
3227static int
3228insn_has_label_before(LINK_ELEMENT *elem)
3229{
3230 LINK_ELEMENT *prev = elem->prev;
3231 while (prev) {
3232 if (prev->type == ISEQ_ELEMENT_LABEL) {
3233 LABEL *label = (LABEL *)prev;
3234 if (label->refcnt > 0) {
3235 return 1;
3236 }
3237 }
3238 else if (prev->type == ISEQ_ELEMENT_INSN) {
3239 break;
3240 }
3241 prev = prev->prev;
3242 }
3243 return 0;
3244}
3245
3246static int
3247optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3248{
3249 /*
3250 * putobject obj
3251 * dup
3252 * checktype T_XXX
3253 * branchif l1
3254 * l2:
3255 * ...
3256 * l1:
3257 *
3258 * => obj is a T_XXX
3259 *
3260 * putobject obj (T_XXX)
3261 * jump L1
3262 * L1:
3263 *
3264 * => obj is not a T_XXX
3265 *
3266 * putobject obj (T_XXX)
3267 * jump L2
3268 * L2:
3269 */
3270 int line, node_id;
3271 INSN *niobj, *ciobj, *dup = 0;
3272 LABEL *dest = 0;
3273 VALUE type;
3274
3275 switch (INSN_OF(iobj)) {
3276 case BIN(putstring):
3277 case BIN(putchilledstring):
3278 type = INT2FIX(T_STRING);
3279 break;
3280 case BIN(putnil):
3281 type = INT2FIX(T_NIL);
3282 break;
3283 case BIN(putobject):
3284 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3285 break;
3286 default: return FALSE;
3287 }
3288
3289 ciobj = (INSN *)get_next_insn(iobj);
3290 if (IS_INSN_ID(ciobj, jump)) {
3291 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3292 }
3293 if (IS_INSN_ID(ciobj, dup)) {
3294 ciobj = (INSN *)get_next_insn(dup = ciobj);
3295 }
3296 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3297 niobj = (INSN *)get_next_insn(ciobj);
3298 if (!niobj) {
3299 /* TODO: putobject true/false */
3300 return FALSE;
3301 }
3302 switch (INSN_OF(niobj)) {
3303 case BIN(branchif):
3304 if (OPERAND_AT(ciobj, 0) == type) {
3305 dest = (LABEL *)OPERAND_AT(niobj, 0);
3306 }
3307 break;
3308 case BIN(branchunless):
3309 if (OPERAND_AT(ciobj, 0) != type) {
3310 dest = (LABEL *)OPERAND_AT(niobj, 0);
3311 }
3312 break;
3313 default:
3314 return FALSE;
3315 }
3316 line = ciobj->insn_info.line_no;
3317 node_id = ciobj->insn_info.node_id;
3318 if (!dest) {
3319 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3320 dest = (LABEL *)niobj->link.next; /* reuse label */
3321 }
3322 else {
3323 dest = NEW_LABEL(line);
3324 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3325 }
3326 }
3327 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3328 LABEL_REF(dest);
3329 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3330 return TRUE;
3331}
3332
3333static const struct rb_callinfo *
3334ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3335{
3336 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3337 vm_ci_flag(ci) | add,
3338 vm_ci_argc(ci),
3339 vm_ci_kwarg(ci));
3340 RB_OBJ_WRITTEN(iseq, ci, nci);
3341 return nci;
3342}
3343
3344static const struct rb_callinfo *
3345ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3346{
3347 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3348 vm_ci_flag(ci),
3349 argc,
3350 vm_ci_kwarg(ci));
3351 RB_OBJ_WRITTEN(iseq, ci, nci);
3352 return nci;
3353}
3354
3355#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3356
3357static int
3358iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3359{
3360 INSN *const iobj = (INSN *)list;
3361
3362 again:
3363 optimize_checktype(iseq, iobj);
3364
3365 if (IS_INSN_ID(iobj, jump)) {
3366 INSN *niobj, *diobj, *piobj;
3367 diobj = (INSN *)get_destination_insn(iobj);
3368 niobj = (INSN *)get_next_insn(iobj);
3369
3370 if (diobj == niobj) {
3371 /*
3372 * jump LABEL
3373 * LABEL:
3374 * =>
3375 * LABEL:
3376 */
3377 unref_destination(iobj, 0);
3378 ELEM_REMOVE(&iobj->link);
3379 return COMPILE_OK;
3380 }
3381 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3382 IS_INSN_ID(diobj, jump) &&
3383 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3384 diobj->insn_info.events == 0) {
3385 /*
3386 * useless jump elimination:
3387 * jump LABEL1
3388 * ...
3389 * LABEL1:
3390 * jump LABEL2
3391 *
3392 * => in this case, first jump instruction should jump to
3393 * LABEL2 directly
3394 */
3395 if (replace_destination(iobj, diobj)) {
3396 remove_unreachable_chunk(iseq, iobj->link.next);
3397 goto again;
3398 }
3399 }
3400 else if (IS_INSN_ID(diobj, leave)) {
3401 /*
3402 * jump LABEL
3403 * ...
3404 * LABEL:
3405 * leave
3406 * =>
3407 * leave
3408 * ...
3409 * LABEL:
3410 * leave
3411 */
3412 /* replace */
3413 unref_destination(iobj, 0);
3414 iobj->insn_id = BIN(leave);
3415 iobj->operand_size = 0;
3416 iobj->insn_info = diobj->insn_info;
3417 goto again;
3418 }
3419 else if (IS_INSN(iobj->link.prev) &&
3420 (piobj = (INSN *)iobj->link.prev) &&
3421 (IS_INSN_ID(piobj, branchif) ||
3422 IS_INSN_ID(piobj, branchunless))) {
3423 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3424 if (niobj == pdiobj) {
3425 int refcnt = IS_LABEL(piobj->link.next) ?
3426 ((LABEL *)piobj->link.next)->refcnt : 0;
3427 /*
3428 * useless jump elimination (if/unless destination):
3429 * if L1
3430 * jump L2
3431 * L1:
3432 * ...
3433 * L2:
3434 *
3435 * ==>
3436 * unless L2
3437 * L1:
3438 * ...
3439 * L2:
3440 */
3441 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3442 ? BIN(branchunless) : BIN(branchif);
3443 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3444 ELEM_REMOVE(&iobj->link);
3445 }
3446 else {
3447 /* TODO: replace other branch destinations too */
3448 }
3449 return COMPILE_OK;
3450 }
3451 else if (diobj == pdiobj) {
3452 /*
3453 * useless jump elimination (if/unless before jump):
3454 * L1:
3455 * ...
3456 * if L1
3457 * jump L1
3458 *
3459 * ==>
3460 * L1:
3461 * ...
3462 * pop
3463 * jump L1
3464 */
3465 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3466 ELEM_REPLACE(&piobj->link, &popiobj->link);
3467 }
3468 }
3469 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3470 goto again;
3471 }
3472 }
3473
3474 /*
3475 * putstring "beg"
3476 * putstring "end"
3477 * newrange excl
3478 *
3479 * ==>
3480 *
3481 * putobject "beg".."end"
3482 */
3483 if (IS_INSN_ID(iobj, newrange)) {
3484 INSN *const range = iobj;
3485 INSN *beg, *end;
3486 VALUE str_beg, str_end;
3487
3488 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3489 is_frozen_putstring(end, &str_end) &&
3490 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3491 is_frozen_putstring(beg, &str_beg) &&
3492 !(insn_has_label_before(&beg->link) || insn_has_label_before(&end->link))) {
3493 int excl = FIX2INT(OPERAND_AT(range, 0));
3494 VALUE lit_range = RB_OBJ_SET_SHAREABLE(rb_range_new(str_beg, str_end, excl));
3495
3496 ELEM_REMOVE(&beg->link);
3497 ELEM_REMOVE(&end->link);
3498 range->insn_id = BIN(putobject);
3499 OPERAND_AT(range, 0) = lit_range;
3500 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3501 }
3502 }
3503
3504 if (IS_INSN_ID(iobj, leave)) {
3505 remove_unreachable_chunk(iseq, iobj->link.next);
3506 }
3507
3508 /*
3509 * ...
3510 * duparray [...]
3511 * concatarray | concattoarray
3512 * =>
3513 * ...
3514 * putobject [...]
3515 * concatarray | concattoarray
3516 */
3517 if (IS_INSN_ID(iobj, duparray)) {
3518 LINK_ELEMENT *next = iobj->link.next;
3519 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3520 iobj->insn_id = BIN(putobject);
3521 }
3522 }
3523
3524 /*
3525 * duparray [...]
3526 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3527 * =>
3528 * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3529 */
3530 if (IS_INSN_ID(iobj, duparray)) {
3531 LINK_ELEMENT *next = iobj->link.next;
3532 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3533 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3534 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3535
3536 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3537 VALUE ary = iobj->operands[0];
3538 rb_obj_reveal(ary, rb_cArray);
3539
3540 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, ary, (VALUE)ci);
3541 ELEM_REMOVE(next);
3542 }
3543 }
3544 }
3545
3546 /*
3547 * duphash {...}
3548 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3549 * =>
3550 * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3551 */
3552 if (IS_INSN_ID(iobj, duphash)) {
3553 LINK_ELEMENT *next = iobj->link.next;
3554 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3555 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3556 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3557
3558 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3559 VALUE hash = iobj->operands[0];
3560 rb_obj_reveal(hash, rb_cHash);
3561 RB_OBJ_SET_SHAREABLE(hash);
3562
3563 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, hash, (VALUE)ci);
3564 ELEM_REMOVE(next);
3565 }
3566 }
3567 }
3568
3569 /*
3570 * newarray 0
3571 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3572 * =>
3573 * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3574 */
3575 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3576 LINK_ELEMENT *next = iobj->link.next;
3577 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3578 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3579 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3580
3581 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3582 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, rb_cArray_empty_frozen, (VALUE)ci);
3583 ELEM_REMOVE(next);
3584 }
3585 }
3586 }
3587
3588 /*
3589 * newhash 0
3590 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3591 * =>
3592 * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3593 */
3594 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3595 LINK_ELEMENT *next = iobj->link.next;
3596 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3597 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3598 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3599
3600 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3601 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, rb_cHash_empty_frozen, (VALUE)ci);
3602 ELEM_REMOVE(next);
3603 }
3604 }
3605 }
3606
3607 if (IS_INSN_ID(iobj, branchif) ||
3608 IS_INSN_ID(iobj, branchnil) ||
3609 IS_INSN_ID(iobj, branchunless)) {
3610 /*
3611 * if L1
3612 * ...
3613 * L1:
3614 * jump L2
3615 * =>
3616 * if L2
3617 */
3618 INSN *nobj = (INSN *)get_destination_insn(iobj);
3619
3620 /* This is super nasty hack!!!
3621 *
3622 * This jump-jump optimization may ignore event flags of the jump
3623 * instruction being skipped. Actually, Line 2 TracePoint event
3624 * is never fired in the following code:
3625 *
3626 * 1: raise if 1 == 2
3627 * 2: while true
3628 * 3: break
3629 * 4: end
3630 *
3631 * This is critical for coverage measurement. [Bug #15980]
3632 *
3633 * This is a stopgap measure: stop the jump-jump optimization if
3634 * coverage measurement is enabled and if the skipped instruction
3635 * has any event flag.
3636 *
3637 * Note that, still, TracePoint Line event does not occur on Line 2.
3638 * This should be fixed in future.
3639 */
3640 int stop_optimization =
3641 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3642 nobj->link.type == ISEQ_ELEMENT_INSN &&
3643 nobj->insn_info.events;
3644 if (!stop_optimization) {
3645 INSN *pobj = (INSN *)iobj->link.prev;
3646 int prev_dup = 0;
3647 if (pobj) {
3648 if (!IS_INSN(&pobj->link))
3649 pobj = 0;
3650 else if (IS_INSN_ID(pobj, dup))
3651 prev_dup = 1;
3652 }
3653
3654 for (;;) {
3655 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3656 if (!replace_destination(iobj, nobj)) break;
3657 }
3658 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3659 !!(nobj = (INSN *)nobj->link.next) &&
3660 /* basic blocks, with no labels in the middle */
3661 nobj->insn_id == iobj->insn_id) {
3662 /*
3663 * dup
3664 * if L1
3665 * ...
3666 * L1:
3667 * dup
3668 * if L2
3669 * =>
3670 * dup
3671 * if L2
3672 * ...
3673 * L1:
3674 * dup
3675 * if L2
3676 */
3677 if (!replace_destination(iobj, nobj)) break;
3678 }
3679 else if (pobj) {
3680 /*
3681 * putnil
3682 * if L1
3683 * =>
3684 * # nothing
3685 *
3686 * putobject true
3687 * if L1
3688 * =>
3689 * jump L1
3690 *
3691 * putstring ".."
3692 * if L1
3693 * =>
3694 * jump L1
3695 *
3696 * putstring ".."
3697 * dup
3698 * if L1
3699 * =>
3700 * putstring ".."
3701 * jump L1
3702 *
3703 */
3704 int cond;
3705 if (prev_dup && IS_INSN(pobj->link.prev)) {
3706 pobj = (INSN *)pobj->link.prev;
3707 }
3708 if (IS_INSN_ID(pobj, putobject)) {
3709 cond = (IS_INSN_ID(iobj, branchif) ?
3710 OPERAND_AT(pobj, 0) != Qfalse :
3711 IS_INSN_ID(iobj, branchunless) ?
3712 OPERAND_AT(pobj, 0) == Qfalse :
3713 FALSE);
3714 }
3715 else if (IS_INSN_ID(pobj, putstring) ||
3716 IS_INSN_ID(pobj, duparray) ||
3717 IS_INSN_ID(pobj, newarray)) {
3718 cond = IS_INSN_ID(iobj, branchif);
3719 }
3720 else if (IS_INSN_ID(pobj, putnil)) {
3721 cond = !IS_INSN_ID(iobj, branchif);
3722 }
3723 else break;
3724 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3725 ELEM_REMOVE(iobj->link.prev);
3726 }
3727 else if (!iseq_pop_newarray(iseq, pobj)) {
3728 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3729 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3730 }
3731 if (cond) {
3732 if (prev_dup) {
3733 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3734 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3735 }
3736 iobj->insn_id = BIN(jump);
3737 goto again;
3738 }
3739 else {
3740 unref_destination(iobj, 0);
3741 ELEM_REMOVE(&iobj->link);
3742 }
3743 break;
3744 }
3745 else break;
3746 nobj = (INSN *)get_destination_insn(nobj);
3747 }
3748 }
3749 }
3750
3751 if (IS_INSN_ID(iobj, pop)) {
3752 /*
3753 * putself / putnil / putobject obj / putstring "..."
3754 * pop
3755 * =>
3756 * # do nothing
3757 */
3758 LINK_ELEMENT *prev = iobj->link.prev;
3759 if (IS_INSN(prev)) {
3760 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3761 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3762 previ == BIN(putself) || previ == BIN(putstring) ||
3763 previ == BIN(putchilledstring) ||
3764 previ == BIN(dup) ||
3765 previ == BIN(getlocal) ||
3766 previ == BIN(getblockparam) ||
3767 previ == BIN(getblockparamproxy) ||
3768 previ == BIN(getinstancevariable) ||
3769 previ == BIN(duparray)) {
3770 /* just push operand or static value and pop soon, no
3771 * side effects */
3772 ELEM_REMOVE(prev);
3773 ELEM_REMOVE(&iobj->link);
3774 }
3775 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3776 ELEM_REMOVE(&iobj->link);
3777 }
3778 else if (previ == BIN(concatarray)) {
3779 INSN *piobj = (INSN *)prev;
3780 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3781 INSN_OF(piobj) = BIN(pop);
3782 }
3783 else if (previ == BIN(concatstrings)) {
3784 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3785 ELEM_REMOVE(prev);
3786 }
3787 else {
3788 ELEM_REMOVE(&iobj->link);
3789 INSN_OF(prev) = BIN(adjuststack);
3790 }
3791 }
3792 }
3793 }
3794
3795 if (IS_INSN_ID(iobj, newarray) ||
3796 IS_INSN_ID(iobj, duparray) ||
3797 IS_INSN_ID(iobj, concatarray) ||
3798 IS_INSN_ID(iobj, splatarray) ||
3799 0) {
3800 /*
3801 * newarray N
3802 * splatarray
3803 * =>
3804 * newarray N
3805 * newarray always puts an array
3806 */
3807 LINK_ELEMENT *next = iobj->link.next;
3808 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3809 /* remove splatarray following always-array insn */
3810 ELEM_REMOVE(next);
3811 }
3812 }
3813
3814 if (IS_INSN_ID(iobj, newarray)) {
3815 LINK_ELEMENT *next = iobj->link.next;
3816 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3817 OPERAND_AT(next, 1) == INT2FIX(0)) {
3818 VALUE op1, op2;
3819 op1 = OPERAND_AT(iobj, 0);
3820 op2 = OPERAND_AT(next, 0);
3821 ELEM_REMOVE(next);
3822
3823 if (op1 == op2) {
3824 /*
3825 * newarray 2
3826 * expandarray 2, 0
3827 * =>
3828 * swap
3829 */
3830 if (op1 == INT2FIX(2)) {
3831 INSN_OF(iobj) = BIN(swap);
3832 iobj->operand_size = 0;
3833 }
3834 /*
3835 * newarray X
3836 * expandarray X, 0
3837 * =>
3838 * opt_reverse X
3839 */
3840 else {
3841 INSN_OF(iobj) = BIN(opt_reverse);
3842 }
3843 }
3844 else {
3845 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3846 INSN_OF(iobj) = BIN(opt_reverse);
3847 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3848
3849 if (op1 > op2) {
3850 /* X > Y
3851 * newarray X
3852 * expandarray Y, 0
3853 * =>
3854 * pop * (Y-X)
3855 * opt_reverse Y
3856 */
3857 for (; diff > 0; diff--) {
3858 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3859 }
3860 }
3861 else { /* (op1 < op2) */
3862 /* X < Y
3863 * newarray X
3864 * expandarray Y, 0
3865 * =>
3866 * putnil * (Y-X)
3867 * opt_reverse Y
3868 */
3869 for (; diff < 0; diff++) {
3870 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
3871 }
3872 }
3873 }
3874 }
3875 }
3876
3877 if (IS_INSN_ID(iobj, duparray)) {
3878 LINK_ELEMENT *next = iobj->link.next;
3879 /*
3880 * duparray obj
3881 * expandarray X, 0
3882 * =>
3883 * putobject obj
3884 * expandarray X, 0
3885 */
3886 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3887 INSN_OF(iobj) = BIN(putobject);
3888 }
3889 }
3890
3891 if (IS_INSN_ID(iobj, anytostring)) {
3892 LINK_ELEMENT *next = iobj->link.next;
3893 /*
3894 * anytostring
3895 * concatstrings 1
3896 * =>
3897 * anytostring
3898 */
3899 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3900 OPERAND_AT(next, 0) == INT2FIX(1)) {
3901 ELEM_REMOVE(next);
3902 }
3903 }
3904
3905 if (IS_INSN_ID(iobj, putstring) || IS_INSN_ID(iobj, putchilledstring) ||
3906 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3907 /*
3908 * putstring ""
3909 * concatstrings N
3910 * =>
3911 * concatstrings N-1
3912 */
3913 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3914 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3915 INSN *next = (INSN *)iobj->link.next;
3916 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3917 ELEM_REMOVE(&next->link);
3918 }
3919 ELEM_REMOVE(&iobj->link);
3920 }
3921 if (IS_NEXT_INSN_ID(&iobj->link, toregexp)) {
3922 INSN *next = (INSN *)iobj->link.next;
3923 if (OPERAND_AT(next, 1) == INT2FIX(1)) {
3924 VALUE src = OPERAND_AT(iobj, 0);
3925 int opt = (int)FIX2LONG(OPERAND_AT(next, 0));
3926 VALUE path = rb_iseq_path(iseq);
3927 int line = iobj->insn_info.line_no;
3928 VALUE errinfo = rb_errinfo();
3929 VALUE re = rb_reg_compile(src, opt, RSTRING_PTR(path), line);
3930 if (NIL_P(re)) {
3931 VALUE message = rb_attr_get(rb_errinfo(), idMesg);
3932 rb_set_errinfo(errinfo);
3933 COMPILE_ERROR(iseq, line, "%" PRIsVALUE, message);
3934 }
3935 else {
3936 RB_OBJ_SET_SHAREABLE(re);
3937 }
3938 RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
3939 ELEM_REMOVE(iobj->link.next);
3940 }
3941 }
3942 }
3943
3944 if (IS_INSN_ID(iobj, concatstrings)) {
3945 /*
3946 * concatstrings N
3947 * concatstrings M
3948 * =>
3949 * concatstrings N+M-1
3950 */
3951 LINK_ELEMENT *next = iobj->link.next;
3952 INSN *jump = 0;
3953 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3954 next = get_destination_insn(jump = (INSN *)next);
3955 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3956 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3957 OPERAND_AT(iobj, 0) = INT2FIX(n);
3958 if (jump) {
3959 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3960 if (!--label->refcnt) {
3961 ELEM_REMOVE(&label->link);
3962 }
3963 else {
3964 label = NEW_LABEL(0);
3965 OPERAND_AT(jump, 0) = (VALUE)label;
3966 }
3967 label->refcnt++;
3968 ELEM_INSERT_NEXT(next, &label->link);
3969 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3970 }
3971 else {
3972 ELEM_REMOVE(next);
3973 }
3974 }
3975 }
3976
3977 if (do_tailcallopt &&
3978 (IS_INSN_ID(iobj, send) ||
3979 IS_INSN_ID(iobj, invokesuper))) {
3980 /*
3981 * send ...
3982 * leave
3983 * =>
3984 * send ..., ... | VM_CALL_TAILCALL, ...
3985 * leave # unreachable
3986 */
3987 INSN *piobj = NULL;
3988 if (iobj->link.next) {
3989 LINK_ELEMENT *next = iobj->link.next;
3990 do {
3991 if (!IS_INSN(next)) {
3992 next = next->next;
3993 continue;
3994 }
3995 switch (INSN_OF(next)) {
3996 case BIN(nop):
3997 next = next->next;
3998 break;
3999 case BIN(jump):
4000 /* if cond
4001 * return tailcall
4002 * end
4003 */
4004 next = get_destination_insn((INSN *)next);
4005 break;
4006 case BIN(leave):
4007 piobj = iobj;
4008 /* fall through */
4009 default:
4010 next = NULL;
4011 break;
4012 }
4013 } while (next);
4014 }
4015
4016 if (piobj) {
4017 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
4018 if (IS_INSN_ID(piobj, send) ||
4019 IS_INSN_ID(piobj, invokesuper)) {
4020 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
4021 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4022 OPERAND_AT(piobj, 0) = (VALUE)ci;
4023 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4024 }
4025 }
4026 else {
4027 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4028 OPERAND_AT(piobj, 0) = (VALUE)ci;
4029 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4030 }
4031 }
4032 }
4033
4034 if (IS_INSN_ID(iobj, dup)) {
4035 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
4036 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
4037
4038 /*
4039 * dup
4040 * setlocal x, y
4041 * setlocal x, y
4042 * =>
4043 * dup
4044 * setlocal x, y
4045 */
4046 if (IS_NEXT_INSN_ID(set1, setlocal)) {
4047 set2 = set1->next;
4048 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4049 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4050 ELEM_REMOVE(set1);
4051 ELEM_REMOVE(&iobj->link);
4052 }
4053 }
4054
4055 /*
4056 * dup
4057 * setlocal x, y
4058 * dup
4059 * setlocal x, y
4060 * =>
4061 * dup
4062 * setlocal x, y
4063 */
4064 else if (IS_NEXT_INSN_ID(set1, dup) &&
4065 IS_NEXT_INSN_ID(set1->next, setlocal)) {
4066 set2 = set1->next->next;
4067 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4068 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4069 ELEM_REMOVE(set1->next);
4070 ELEM_REMOVE(set2);
4071 }
4072 }
4073 }
4074 }
4075
4076 /*
4077 * getlocal x, y
4078 * dup
4079 * setlocal x, y
4080 * =>
4081 * dup
4082 */
4083 if (IS_INSN_ID(iobj, getlocal)) {
4084 LINK_ELEMENT *niobj = &iobj->link;
4085 if (IS_NEXT_INSN_ID(niobj, dup)) {
4086 niobj = niobj->next;
4087 }
4088 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
4089 LINK_ELEMENT *set1 = niobj->next;
4090 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
4091 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
4092 ELEM_REMOVE(set1);
4093 ELEM_REMOVE(niobj);
4094 }
4095 }
4096 }
4097
4098 /*
4099 * opt_invokebuiltin_delegate
4100 * trace
4101 * leave
4102 * =>
4103 * opt_invokebuiltin_delegate_leave
4104 * trace
4105 * leave
4106 */
4107 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4108 if (IS_TRACE(iobj->link.next)) {
4109 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4110 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4111 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
4112 if (iobj == (INSN *)list && bf->argc == 0 && (ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4113 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4114 }
4115 }
4116 }
4117 }
4118
4119 /*
4120 * getblockparam
4121 * branchif / branchunless
4122 * =>
4123 * getblockparamproxy
4124 * branchif / branchunless
4125 */
4126 if (IS_INSN_ID(iobj, getblockparam)) {
4127 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4128 iobj->insn_id = BIN(getblockparamproxy);
4129 }
4130 }
4131
4132 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4133 LINK_ELEMENT *niobj = &iobj->link;
4134 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4135 niobj = niobj->next;
4136 LINK_ELEMENT *siobj;
4137 unsigned int set_flags = 0, unset_flags = 0;
4138
4139 /*
4140 * Eliminate hash allocation for f(*a, kw: 1)
4141 *
4142 * splatarray false
4143 * duphash
4144 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4145 * =>
4146 * splatarray false
4147 * putobject
4148 * send ARGS_SPLAT|KW_SPLAT
4149 */
4150 if (IS_NEXT_INSN_ID(niobj, send)) {
4151 siobj = niobj->next;
4152 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4153 unset_flags = VM_CALL_ARGS_BLOCKARG;
4154 }
4155 /*
4156 * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4157 *
4158 * splatarray false
4159 * duphash
4160 * getlocal / getinstancevariable / getblockparamproxy
4161 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4162 * =>
4163 * splatarray false
4164 * putobject
4165 * getlocal / getinstancevariable / getblockparamproxy
4166 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4167 */
4168 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4169 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4170 siobj = niobj->next->next;
4171 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4172 }
4173
4174 if (set_flags) {
4175 const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4176 unsigned int flags = vm_ci_flag(ci);
4177 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4178 ((INSN*)niobj)->insn_id = BIN(putobject);
4179 RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), RB_OBJ_SET_SHAREABLE(rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)))));
4180
4181 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4182 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4183 RB_OBJ_WRITTEN(iseq, ci, nci);
4184 OPERAND_AT(siobj, 0) = (VALUE)nci;
4185 }
4186 }
4187 }
4188 }
4189
4190 return COMPILE_OK;
4191}
4192
4193static int
4194insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4195{
4196 if (insn_id == BIN(opt_neq)) {
4197 VALUE original_ci = iobj->operands[0];
4198 VALUE new_ci = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4199 insn_replace_with_operands(iseq, iobj, insn_id, 2, new_ci, original_ci);
4200 }
4201 else {
4202 iobj->insn_id = insn_id;
4203 iobj->operand_size = insn_len(insn_id) - 1;
4204 }
4205 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4206
4207 return COMPILE_OK;
4208}
4209
4210static int
4211iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4212{
4213 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4214 IS_INSN(iobj->link.next)) {
4215 /*
4216 * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4217 */
4218 INSN *niobj = (INSN *)iobj->link.next;
4219 if (IS_INSN_ID(niobj, send)) {
4220 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4221 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4222 VALUE method = INT2FIX(0);
4223 switch (vm_ci_mid(ci)) {
4224 case idMax:
4225 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4226 break;
4227 case idMin:
4228 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4229 break;
4230 case idHash:
4231 method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4232 break;
4233 }
4234
4235 if (method != INT2FIX(0)) {
4236 VALUE num = iobj->operands[0];
4237 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, num, method);
4238 ELEM_REMOVE(&niobj->link);
4239 return COMPILE_OK;
4240 }
4241 }
4242 }
4243 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4244 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4245 IS_NEXT_INSN_ID(&niobj->link, send)) {
4246 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4247 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4248 VALUE num = iobj->operands[0];
4249 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK));
4250 ELEM_REMOVE(&iobj->link);
4251 ELEM_REMOVE(niobj->link.next);
4252 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4253 return COMPILE_OK;
4254 }
4255 }
4256 // newarray n, putchilledstring "E", getlocal b, send :pack with {buffer: b}
4257 // -> putchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
4258 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4259 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4260 IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4261 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4262 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4263 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4264 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4265 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4266 VALUE num = iobj->operands[0];
4267 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 2), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER));
4268 // Remove the "send" insn.
4269 ELEM_REMOVE((niobj->link.next)->next);
4270 // Remove the modified insn from its original "newarray" position...
4271 ELEM_REMOVE(&iobj->link);
4272 // and insert it after the buffer insn.
4273 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4274 return COMPILE_OK;
4275 }
4276 }
4277
4278 // Break the "else if" chain since some prior checks abort after sub-ifs.
4279 // We already found "newarray". To match `[...].include?(arg)` we look for
4280 // the instruction(s) representing the argument followed by a "send".
4281 if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4282 IS_INSN_ID(niobj, putobject) ||
4283 IS_INSN_ID(niobj, putself) ||
4284 IS_INSN_ID(niobj, getlocal) ||
4285 IS_INSN_ID(niobj, getinstancevariable)) &&
4286 IS_NEXT_INSN_ID(&niobj->link, send)) {
4287
4288 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4289 const struct rb_callinfo *ci;
4290 // Allow any number (0 or more) of simple method calls on the argument
4291 // (as in `[...].include?(arg.method1.method2)`.
4292 do {
4293 sendobj = sendobj->next;
4294 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4295 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4296
4297 // If this send is for .include? with one arg we can do our opt.
4298 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4299 VALUE num = iobj->operands[0];
4300 INSN *sendins = (INSN *)sendobj;
4301 insn_replace_with_operands(iseq, sendins, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P));
4302 // Remove the original "newarray" insn.
4303 ELEM_REMOVE(&iobj->link);
4304 return COMPILE_OK;
4305 }
4306 }
4307 }
4308
4309 /*
4310 * duparray [...]
4311 * some insn for the arg...
4312 * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4313 * =>
4314 * arg insn...
4315 * opt_duparray_send [...], :include?, 1
4316 */
4317 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4318 INSN *niobj = (INSN *)iobj->link.next;
4319 if ((IS_INSN_ID(niobj, getlocal) ||
4320 IS_INSN_ID(niobj, getinstancevariable) ||
4321 IS_INSN_ID(niobj, putself)) &&
4322 IS_NEXT_INSN_ID(&niobj->link, send)) {
4323
4324 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4325 const struct rb_callinfo *ci;
4326 // Allow any number (0 or more) of simple method calls on the argument
4327 // (as in `[...].include?(arg.method1.method2)`.
4328 do {
4329 sendobj = sendobj->next;
4330 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4331 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4332
4333 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4334 // Move the array arg from duparray to opt_duparray_send.
4335 VALUE ary = iobj->operands[0];
4336 rb_obj_reveal(ary, rb_cArray);
4337
4338 INSN *sendins = (INSN *)sendobj;
4339 insn_replace_with_operands(iseq, sendins, BIN(opt_duparray_send), 3, ary, rb_id2sym(idIncludeP), INT2FIX(1));
4340
4341 // Remove the duparray insn.
4342 ELEM_REMOVE(&iobj->link);
4343 return COMPILE_OK;
4344 }
4345 }
4346 }
4347
4348
4349 if (IS_INSN_ID(iobj, send)) {
4350 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4351 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4352
4353#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4354 if (vm_ci_simple(ci)) {
4355 switch (vm_ci_argc(ci)) {
4356 case 0:
4357 switch (vm_ci_mid(ci)) {
4358 case idLength: SP_INSN(length); return COMPILE_OK;
4359 case idSize: SP_INSN(size); return COMPILE_OK;
4360 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4361 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4362 case idSucc: SP_INSN(succ); return COMPILE_OK;
4363 case idNot: SP_INSN(not); return COMPILE_OK;
4364 }
4365 break;
4366 case 1:
4367 switch (vm_ci_mid(ci)) {
4368 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4369 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4370 case idMULT: SP_INSN(mult); return COMPILE_OK;
4371 case idDIV: SP_INSN(div); return COMPILE_OK;
4372 case idMOD: SP_INSN(mod); return COMPILE_OK;
4373 case idEq: SP_INSN(eq); return COMPILE_OK;
4374 case idNeq: SP_INSN(neq); return COMPILE_OK;
4375 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4376 case idLT: SP_INSN(lt); return COMPILE_OK;
4377 case idLE: SP_INSN(le); return COMPILE_OK;
4378 case idGT: SP_INSN(gt); return COMPILE_OK;
4379 case idGE: SP_INSN(ge); return COMPILE_OK;
4380 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4381 case idAREF: SP_INSN(aref); return COMPILE_OK;
4382 case idAnd: SP_INSN(and); return COMPILE_OK;
4383 case idOr: SP_INSN(or); return COMPILE_OK;
4384 }
4385 break;
4386 case 2:
4387 switch (vm_ci_mid(ci)) {
4388 case idASET: SP_INSN(aset); return COMPILE_OK;
4389 }
4390 break;
4391 }
4392 }
4393
4394 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4395 iobj->insn_id = BIN(opt_send_without_block);
4396 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4397 }
4398 }
4399#undef SP_INSN
4400
4401 return COMPILE_OK;
4402}
4403
4404static inline int
4405tailcallable_p(rb_iseq_t *iseq)
4406{
4407 switch (ISEQ_BODY(iseq)->type) {
4408 case ISEQ_TYPE_TOP:
4409 case ISEQ_TYPE_EVAL:
4410 case ISEQ_TYPE_MAIN:
4411 /* not tail callable because cfp will be over popped */
4412 case ISEQ_TYPE_RESCUE:
4413 case ISEQ_TYPE_ENSURE:
4414 /* rescue block can't tail call because of errinfo */
4415 return FALSE;
4416 default:
4417 return TRUE;
4418 }
4419}
4420
4421static int
4422iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4423{
4424 LINK_ELEMENT *list;
4425 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4426 const int do_tailcallopt = tailcallable_p(iseq) &&
4427 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4428 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4429 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4430 int rescue_level = 0;
4431 int tailcallopt = do_tailcallopt;
4432
4433 list = FIRST_ELEMENT(anchor);
4434
4435 int do_block_optimization = 0;
4436 LABEL * block_loop_label = NULL;
4437
4438 // If we're optimizing a block
4439 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
4440 do_block_optimization = 1;
4441
4442 // If the block starts with a nop and a label,
4443 // record the label so we can detect if it's a jump target
4444 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4445 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop) && IS_LABEL(le->next)) {
4446 block_loop_label = (LABEL *)le->next;
4447 }
4448 }
4449
4450 while (list) {
4451 if (IS_INSN(list)) {
4452 if (do_peepholeopt) {
4453 iseq_peephole_optimize(iseq, list, tailcallopt);
4454 }
4455 if (do_si) {
4456 iseq_specialized_instruction(iseq, (INSN *)list);
4457 }
4458 if (do_ou) {
4459 insn_operands_unification((INSN *)list);
4460 }
4461
4462 if (do_block_optimization) {
4463 INSN * item = (INSN *)list;
4464 // Give up if there is a throw
4465 if (IS_INSN_ID(item, throw)) {
4466 do_block_optimization = 0;
4467 }
4468 else {
4469 // If the instruction has a jump target, check if the
4470 // jump target is the block loop label
4471 const char *types = insn_op_types(item->insn_id);
4472 for (int j = 0; types[j]; j++) {
4473 if (types[j] == TS_OFFSET) {
4474 // If the jump target is equal to the block loop
4475 // label, then we can't do the optimization because
4476 // the leading `nop` instruction fires the block
4477 // entry tracepoint
4478 LABEL * target = (LABEL *)OPERAND_AT(item, j);
4479 if (target == block_loop_label) {
4480 do_block_optimization = 0;
4481 }
4482 }
4483 }
4484 }
4485 }
4486 }
4487 if (IS_LABEL(list)) {
4488 switch (((LABEL *)list)->rescued) {
4489 case LABEL_RESCUE_BEG:
4490 rescue_level++;
4491 tailcallopt = FALSE;
4492 break;
4493 case LABEL_RESCUE_END:
4494 if (!--rescue_level) tailcallopt = do_tailcallopt;
4495 break;
4496 }
4497 }
4498 list = list->next;
4499 }
4500
4501 if (do_block_optimization) {
4502 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4503 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4504 ELEM_REMOVE(le);
4505 }
4506 }
4507 return COMPILE_OK;
4508}
4509
4510#if OPT_INSTRUCTIONS_UNIFICATION
4511static INSN *
4512new_unified_insn(rb_iseq_t *iseq,
4513 int insn_id, int size, LINK_ELEMENT *seq_list)
4514{
4515 INSN *iobj = 0;
4516 LINK_ELEMENT *list = seq_list;
4517 int i, argc = 0;
4518 VALUE *operands = 0, *ptr = 0;
4519
4520
4521 /* count argc */
4522 for (i = 0; i < size; i++) {
4523 iobj = (INSN *)list;
4524 argc += iobj->operand_size;
4525 list = list->next;
4526 }
4527
4528 if (argc > 0) {
4529 ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
4530 }
4531
4532 /* copy operands */
4533 list = seq_list;
4534 for (i = 0; i < size; i++) {
4535 iobj = (INSN *)list;
4536 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4537 ptr += iobj->operand_size;
4538 list = list->next;
4539 }
4540
4541 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4542}
4543#endif
4544
4545/*
4546 * This scheme can get more performance if do this optimize with
4547 * label address resolving.
4548 * It's future work (if compile time was bottle neck).
4549 */
4550static int
4551iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4552{
4553#if OPT_INSTRUCTIONS_UNIFICATION
4554 LINK_ELEMENT *list;
4555 INSN *iobj, *niobj;
4556 int id, k;
4557 intptr_t j;
4558
4559 list = FIRST_ELEMENT(anchor);
4560 while (list) {
4561 if (IS_INSN(list)) {
4562 iobj = (INSN *)list;
4563 id = iobj->insn_id;
4564 if (unified_insns_data[id] != 0) {
4565 const int *const *entry = unified_insns_data[id];
4566 for (j = 1; j < (intptr_t)entry[0]; j++) {
4567 const int *unified = entry[j];
4568 LINK_ELEMENT *li = list->next;
4569 for (k = 2; k < unified[1]; k++) {
4570 if (!IS_INSN(li) ||
4571 ((INSN *)li)->insn_id != unified[k]) {
4572 goto miss;
4573 }
4574 li = li->next;
4575 }
4576 /* matched */
4577 niobj =
4578 new_unified_insn(iseq, unified[0], unified[1] - 1,
4579 list);
4580
4581 /* insert to list */
4582 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4583 niobj->link.next = li;
4584 if (li) {
4585 li->prev = (LINK_ELEMENT *)niobj;
4586 }
4587
4588 list->prev->next = (LINK_ELEMENT *)niobj;
4589 list = (LINK_ELEMENT *)niobj;
4590 break;
4591 miss:;
4592 }
4593 }
4594 }
4595 list = list->next;
4596 }
4597#endif
4598 return COMPILE_OK;
4599}
4600
4601static int
4602all_string_result_p(const NODE *node)
4603{
4604 if (!node) return FALSE;
4605 switch (nd_type(node)) {
4606 case NODE_STR: case NODE_DSTR: case NODE_FILE:
4607 return TRUE;
4608 case NODE_IF: case NODE_UNLESS:
4609 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4610 if (all_string_result_p(RNODE_IF(node)->nd_body))
4611 return all_string_result_p(RNODE_IF(node)->nd_else);
4612 return FALSE;
4613 case NODE_AND: case NODE_OR:
4614 if (!RNODE_AND(node)->nd_2nd)
4615 return all_string_result_p(RNODE_AND(node)->nd_1st);
4616 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4617 return FALSE;
4618 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4619 default:
4620 return FALSE;
4621 }
4622}
4623
4624 struct dstr_ctxt {
4625 rb_iseq_t *const iseq;
4626 LINK_ANCHOR *const ret;
4627 VALUE lit;
4628 const NODE *lit_node;
4629 int cnt;
4630 int dregx;
4631};
4632
4633static int
4634append_dstr_fragment(struct dstr_ctxt *args, const NODE *const node, rb_parser_string_t *str)
4635{
4636 VALUE s = rb_str_new_mutable_parser_string(str);
4637 if (args->dregx) {
4638 VALUE error = rb_reg_check_preprocess(s);
4639 if (!NIL_P(error)) {
4640 COMPILE_ERROR(args->iseq, nd_line(node), "%" PRIsVALUE, error);
4641 return COMPILE_NG;
4642 }
4643 }
4644 if (NIL_P(args->lit)) {
4645 args->lit = s;
4646 args->lit_node = node;
4647 }
4648 else {
4649 rb_str_buf_append(args->lit, s);
4650 }
4651 return COMPILE_OK;
4652}
4653
4654static void
4655flush_dstr_fragment(struct dstr_ctxt *args)
4656{
4657 if (!NIL_P(args->lit)) {
4658 rb_iseq_t *iseq = args->iseq;
4659 VALUE lit = args->lit;
4660 args->lit = Qnil;
4661 lit = rb_fstring(lit);
4662 ADD_INSN1(args->ret, args->lit_node, putobject, lit);
4663 RB_OBJ_WRITTEN(args->iseq, Qundef, lit);
4664 args->cnt++;
4665 }
4666}
4667
4668static int
4669compile_dstr_fragments_0(struct dstr_ctxt *args, const NODE *const node)
4670{
4671 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4672 rb_parser_string_t *str = RNODE_DSTR(node)->string;
4673
4674 if (str) {
4675 CHECK(append_dstr_fragment(args, node, str));
4676 }
4677
4678 while (list) {
4679 const NODE *const head = list->nd_head;
4680 if (nd_type_p(head, NODE_STR)) {
4681 CHECK(append_dstr_fragment(args, node, RNODE_STR(head)->string));
4682 }
4683 else if (nd_type_p(head, NODE_DSTR)) {
4684 CHECK(compile_dstr_fragments_0(args, head));
4685 }
4686 else {
4687 flush_dstr_fragment(args);
4688 rb_iseq_t *iseq = args->iseq;
4689 CHECK(COMPILE(args->ret, "each string", head));
4690 args->cnt++;
4691 }
4692 list = (struct RNode_LIST *)list->nd_next;
4693 }
4694 return COMPILE_OK;
4695}
4696
4697static int
4698compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp, int dregx)
4699{
4700 struct dstr_ctxt args = {
4701 .iseq = iseq, .ret = ret,
4702 .lit = Qnil, .lit_node = NULL,
4703 .cnt = 0, .dregx = dregx,
4704 };
4705 CHECK(compile_dstr_fragments_0(&args, node));
4706 flush_dstr_fragment(&args);
4707
4708 *cntp = args.cnt;
4709
4710 return COMPILE_OK;
4711}
4712
4713static int
4714compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4715{
4716 while (node && nd_type_p(node, NODE_BLOCK)) {
4717 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4718 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4719 node = RNODE_BLOCK(node)->nd_next;
4720 }
4721 if (node) {
4722 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4723 }
4724 return COMPILE_OK;
4725}
4726
4727static int
4728compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4729{
4730 int cnt;
4731 if (!RNODE_DSTR(node)->nd_next) {
4732 VALUE lit = rb_node_dstr_string_val(node);
4733 ADD_INSN1(ret, node, putstring, lit);
4734 RB_OBJ_SET_SHAREABLE(lit);
4735 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4736 }
4737 else {
4738 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, FALSE));
4739 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4740 }
4741 return COMPILE_OK;
4742}
4743
4744static int
4745compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4746{
4747 int cnt;
4748 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4749
4750 if (!RNODE_DREGX(node)->nd_next) {
4751 if (!popped) {
4752 VALUE src = rb_node_dregx_string_val(node);
4753 VALUE match = rb_reg_compile(src, cflag, NULL, 0);
4754 RB_OBJ_SET_SHAREABLE(match);
4755 ADD_INSN1(ret, node, putobject, match);
4756 RB_OBJ_WRITTEN(iseq, Qundef, match);
4757 }
4758 return COMPILE_OK;
4759 }
4760
4761 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, TRUE));
4762 ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
4763
4764 if (popped) {
4765 ADD_INSN(ret, node, pop);
4766 }
4767
4768 return COMPILE_OK;
4769}
4770
4771static int
4772compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4773 LABEL *then_label, LABEL *else_label)
4774{
4775 const int line = nd_line(node);
4776 LABEL *lend = NEW_LABEL(line);
4777 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4778 + VM_SVAR_FLIPFLOP_START;
4779 VALUE key = INT2FIX(cnt);
4780
4781 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4782 ADD_INSNL(ret, node, branchif, lend);
4783
4784 /* *flip == 0 */
4785 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4786 ADD_INSNL(ret, node, branchunless, else_label);
4787 ADD_INSN1(ret, node, putobject, Qtrue);
4788 ADD_INSN1(ret, node, setspecial, key);
4789 if (!again) {
4790 ADD_INSNL(ret, node, jump, then_label);
4791 }
4792
4793 /* *flip == 1 */
4794 ADD_LABEL(ret, lend);
4795 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4796 ADD_INSNL(ret, node, branchunless, then_label);
4797 ADD_INSN1(ret, node, putobject, Qfalse);
4798 ADD_INSN1(ret, node, setspecial, key);
4799 ADD_INSNL(ret, node, jump, then_label);
4800
4801 return COMPILE_OK;
4802}
4803
4804static int
4805compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4806 LABEL *then_label, LABEL *else_label);
4807
4808#define COMPILE_SINGLE 2
4809static int
4810compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4811 LABEL *then_label, LABEL *else_label)
4812{
4813 DECL_ANCHOR(seq);
4814 INIT_ANCHOR(seq);
4815 LABEL *label = NEW_LABEL(nd_line(cond));
4816 if (!then_label) then_label = label;
4817 else if (!else_label) else_label = label;
4818
4819 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4820
4821 if (LIST_INSN_SIZE_ONE(seq)) {
4822 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4823 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4824 return COMPILE_OK;
4825 }
4826 if (!label->refcnt) {
4827 return COMPILE_SINGLE;
4828 }
4829 ADD_LABEL(seq, label);
4830 ADD_SEQ(ret, seq);
4831 return COMPILE_OK;
4832}
4833
4834static int
4835compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4836 LABEL *then_label, LABEL *else_label)
4837{
4838 int ok;
4839 DECL_ANCHOR(ignore);
4840
4841 again:
4842 switch (nd_type(cond)) {
4843 case NODE_AND:
4844 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4845 cond = RNODE_AND(cond)->nd_2nd;
4846 if (ok == COMPILE_SINGLE) {
4847 ADD_INSNL(ret, cond, jump, else_label);
4848 INIT_ANCHOR(ignore);
4849 ret = ignore;
4850 then_label = NEW_LABEL(nd_line(cond));
4851 }
4852 goto again;
4853 case NODE_OR:
4854 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
4855 cond = RNODE_OR(cond)->nd_2nd;
4856 if (ok == COMPILE_SINGLE) {
4857 ADD_INSNL(ret, cond, jump, then_label);
4858 INIT_ANCHOR(ignore);
4859 ret = ignore;
4860 else_label = NEW_LABEL(nd_line(cond));
4861 }
4862 goto again;
4863 case NODE_SYM:
4864 case NODE_LINE:
4865 case NODE_FILE:
4866 case NODE_ENCODING:
4867 case NODE_INTEGER: /* NODE_INTEGER is always true */
4868 case NODE_FLOAT: /* NODE_FLOAT is always true */
4869 case NODE_RATIONAL: /* NODE_RATIONAL is always true */
4870 case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
4871 case NODE_TRUE:
4872 case NODE_STR:
4873 case NODE_REGX:
4874 case NODE_ZLIST:
4875 case NODE_LAMBDA:
4876 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4877 ADD_INSNL(ret, cond, jump, then_label);
4878 return COMPILE_OK;
4879 case NODE_FALSE:
4880 case NODE_NIL:
4881 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4882 ADD_INSNL(ret, cond, jump, else_label);
4883 return COMPILE_OK;
4884 case NODE_LIST:
4885 case NODE_ARGSCAT:
4886 case NODE_DREGX:
4887 case NODE_DSTR:
4888 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
4889 ADD_INSNL(ret, cond, jump, then_label);
4890 return COMPILE_OK;
4891 case NODE_FLIP2:
4892 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4893 return COMPILE_OK;
4894 case NODE_FLIP3:
4895 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4896 return COMPILE_OK;
4897 case NODE_DEFINED:
4898 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
4899 break;
4900 default:
4901 {
4902 DECL_ANCHOR(cond_seq);
4903 INIT_ANCHOR(cond_seq);
4904
4905 CHECK(COMPILE(cond_seq, "branch condition", cond));
4906
4907 if (LIST_INSN_SIZE_ONE(cond_seq)) {
4908 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
4909 if (insn->insn_id == BIN(putobject)) {
4910 if (RTEST(insn->operands[0])) {
4911 ADD_INSNL(ret, cond, jump, then_label);
4912 // maybe unreachable
4913 return COMPILE_OK;
4914 }
4915 else {
4916 ADD_INSNL(ret, cond, jump, else_label);
4917 return COMPILE_OK;
4918 }
4919 }
4920 }
4921 ADD_SEQ(ret, cond_seq);
4922 }
4923 break;
4924 }
4925
4926 ADD_INSNL(ret, cond, branchunless, else_label);
4927 ADD_INSNL(ret, cond, jump, then_label);
4928 return COMPILE_OK;
4929}
4930
4931#define HASH_BRACE 1
4932
4933static int
4934keyword_node_p(const NODE *const node)
4935{
4936 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
4937}
4938
4939static VALUE
4940get_symbol_value(rb_iseq_t *iseq, const NODE *node)
4941{
4942 switch (nd_type(node)) {
4943 case NODE_SYM:
4944 return rb_node_sym_string_val(node);
4945 default:
4946 UNKNOWN_NODE("get_symbol_value", node, Qnil);
4947 }
4948}
4949
4950static VALUE
4951node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
4952{
4953 NODE *node = node_hash->nd_head;
4954 VALUE hash = rb_hash_new();
4955 VALUE ary = rb_ary_new();
4956
4957 for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4958 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
4959 VALUE idx = rb_hash_aref(hash, key);
4960 if (!NIL_P(idx)) {
4961 rb_ary_store(ary, FIX2INT(idx), Qfalse);
4962 (*count_ptr)--;
4963 }
4964 rb_hash_aset(hash, key, INT2FIX(i));
4965 rb_ary_store(ary, i, Qtrue);
4966 (*count_ptr)++;
4967 }
4968
4969 return ary;
4970}
4971
4972static int
4973compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4974 const NODE *const root_node,
4975 struct rb_callinfo_kwarg **const kw_arg_ptr,
4976 unsigned int *flag)
4977{
4978 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
4979 RUBY_ASSERT(kw_arg_ptr != NULL);
4980 RUBY_ASSERT(flag != NULL);
4981
4982 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
4983 const NODE *node = RNODE_HASH(root_node)->nd_head;
4984 int seen_nodes = 0;
4985
4986 while (node) {
4987 const NODE *key_node = RNODE_LIST(node)->nd_head;
4988 seen_nodes++;
4989
4990 RUBY_ASSERT(nd_type_p(node, NODE_LIST));
4991 if (key_node && nd_type_p(key_node, NODE_SYM)) {
4992 /* can be keywords */
4993 }
4994 else {
4995 if (flag) {
4996 *flag |= VM_CALL_KW_SPLAT;
4997 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4998 /* A new hash will be created for the keyword arguments
4999 * in this case, so mark the method as passing mutable
5000 * keyword splat.
5001 */
5002 *flag |= VM_CALL_KW_SPLAT_MUT;
5003 }
5004 }
5005 return FALSE;
5006 }
5007 node = RNODE_LIST(node)->nd_next; /* skip value node */
5008 node = RNODE_LIST(node)->nd_next;
5009 }
5010
5011 /* may be keywords */
5012 node = RNODE_HASH(root_node)->nd_head;
5013 {
5014 int len = 0;
5015 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
5016 struct rb_callinfo_kwarg *kw_arg =
5017 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
5018 VALUE *keywords = kw_arg->keywords;
5019 int i = 0;
5020 int j = 0;
5021 kw_arg->references = 0;
5022 kw_arg->keyword_len = len;
5023
5024 *kw_arg_ptr = kw_arg;
5025
5026 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5027 const NODE *key_node = RNODE_LIST(node)->nd_head;
5028 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5029 int popped = TRUE;
5030 if (rb_ary_entry(key_index, i)) {
5031 keywords[j] = get_symbol_value(iseq, key_node);
5032 j++;
5033 popped = FALSE;
5034 }
5035 NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
5036 }
5037 RUBY_ASSERT(j == len);
5038 return TRUE;
5039 }
5040 }
5041 return FALSE;
5042}
5043
5044static int
5045compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
5046{
5047 int len = 0;
5048
5049 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
5050 if (CPDEBUG > 0) {
5051 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
5052 }
5053
5054 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
5055 *kwnode_ptr = RNODE_LIST(node)->nd_head;
5056 }
5057 else {
5058 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
5059 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
5060 }
5061 }
5062
5063 return len;
5064}
5065
5066static inline bool
5067frozen_string_literal_p(const rb_iseq_t *iseq)
5068{
5069 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
5070}
5071
5072static inline bool
5073static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
5074{
5075 switch (nd_type(node)) {
5076 case NODE_SYM:
5077 case NODE_REGX:
5078 case NODE_LINE:
5079 case NODE_ENCODING:
5080 case NODE_INTEGER:
5081 case NODE_FLOAT:
5082 case NODE_RATIONAL:
5083 case NODE_IMAGINARY:
5084 case NODE_NIL:
5085 case NODE_TRUE:
5086 case NODE_FALSE:
5087 return TRUE;
5088 case NODE_STR:
5089 case NODE_FILE:
5090 return hash_key || frozen_string_literal_p(iseq);
5091 default:
5092 return FALSE;
5093 }
5094}
5095
5096static inline VALUE
5097static_literal_value(const NODE *node, rb_iseq_t *iseq)
5098{
5099 switch (nd_type(node)) {
5100 case NODE_INTEGER:
5101 {
5102 VALUE lit = rb_node_integer_literal_val(node);
5103 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5104 return lit;
5105 }
5106 case NODE_FLOAT:
5107 {
5108 VALUE lit = rb_node_float_literal_val(node);
5109 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5110 return lit;
5111 }
5112 case NODE_RATIONAL:
5113 return rb_ractor_make_shareable(rb_node_rational_literal_val(node));
5114 case NODE_IMAGINARY:
5115 return rb_ractor_make_shareable(rb_node_imaginary_literal_val(node));
5116 case NODE_NIL:
5117 return Qnil;
5118 case NODE_TRUE:
5119 return Qtrue;
5120 case NODE_FALSE:
5121 return Qfalse;
5122 case NODE_SYM:
5123 return rb_node_sym_string_val(node);
5124 case NODE_REGX:
5125 return RB_OBJ_SET_SHAREABLE(rb_node_regx_string_val(node));
5126 case NODE_LINE:
5127 return rb_node_line_lineno_val(node);
5128 case NODE_ENCODING:
5129 return rb_node_encoding_val(node);
5130 case NODE_FILE:
5131 case NODE_STR:
5132 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
5133 VALUE lit = get_string_value(node);
5134 VALUE str = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
5135 RB_OBJ_SET_SHAREABLE(str);
5136 return str;
5137 }
5138 else {
5139 return get_string_value(node);
5140 }
5141 default:
5142 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
5143 }
5144}
5145
5146static int
5147compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
5148{
5149 const NODE *line_node = node;
5150
5151 if (nd_type_p(node, NODE_ZLIST)) {
5152 if (!popped) {
5153 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5154 }
5155 return 0;
5156 }
5157
5158 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5159
5160 if (popped) {
5161 for (; node; node = RNODE_LIST(node)->nd_next) {
5162 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
5163 }
5164 return 1;
5165 }
5166
5167 /* Compilation of an array literal.
5168 * The following code is essentially the same as:
5169 *
5170 * for (int count = 0; node; count++; node->nd_next) {
5171 * compile(node->nd_head);
5172 * }
5173 * ADD_INSN(newarray, count);
5174 *
5175 * However, there are three points.
5176 *
5177 * - The code above causes stack overflow for a big string literal.
5178 * The following limits the stack length up to max_stack_len.
5179 *
5180 * [x1,x2,...,x10000] =>
5181 * push x1 ; push x2 ; ...; push x256; newarray 256;
5182 * push x257; push x258; ...; push x512; pushtoarray 256;
5183 * push x513; push x514; ...; push x768; pushtoarray 256;
5184 * ...
5185 *
5186 * - Long subarray can be optimized by pre-allocating a hidden array.
5187 *
5188 * [1,2,3,...,100] =>
5189 * duparray [1,2,3,...,100]
5190 *
5191 * [x, 1,2,3,...,100, z] =>
5192 * push x; newarray 1;
5193 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5194 * push z; pushtoarray 1;
5195 *
5196 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5197 * to only push it onto the array if it is not empty
5198 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5199 *
5200 * [1,2,3,**kw] =>
5201 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5202 */
5203
5204 const int max_stack_len = 0x100;
5205 const int min_tmp_ary_len = 0x40;
5206 int stack_len = 0;
5207
5208 /* Either create a new array, or push to the existing array */
5209#define FLUSH_CHUNK \
5210 if (stack_len) { \
5211 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5212 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5213 first_chunk = FALSE; \
5214 stack_len = 0; \
5215 }
5216
5217 while (node) {
5218 int count = 1;
5219
5220 /* pre-allocation check (this branch can be omittable) */
5221 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5222 /* count the elements that are optimizable */
5223 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5224 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5225 count++;
5226
5227 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5228 /* The literal contains only optimizable elements, or the subarray is long enough */
5229 VALUE ary = rb_ary_hidden_new(count);
5230
5231 /* Create a hidden array */
5232 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5233 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5234 RB_OBJ_SET_FROZEN_SHAREABLE(ary);
5235
5236 /* Emit optimized code */
5237 FLUSH_CHUNK;
5238 if (first_chunk) {
5239 ADD_INSN1(ret, line_node, duparray, ary);
5240 first_chunk = FALSE;
5241 }
5242 else {
5243 ADD_INSN1(ret, line_node, putobject, ary);
5244 ADD_INSN(ret, line_node, concattoarray);
5245 }
5246 RB_OBJ_SET_SHAREABLE(ary);
5247 RB_OBJ_WRITTEN(iseq, Qundef, ary);
5248 }
5249 }
5250
5251 /* Base case: Compile "count" elements */
5252 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5253 if (CPDEBUG > 0) {
5254 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5255 }
5256
5257 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5258 /* Create array or push existing non-keyword elements onto array */
5259 if (stack_len == 0 && first_chunk) {
5260 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5261 }
5262 else {
5263 FLUSH_CHUNK;
5264 }
5265 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5266 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5267 return 1;
5268 }
5269 else {
5270 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5271 stack_len++;
5272 }
5273
5274 /* If there are many pushed elements, flush them to avoid stack overflow */
5275 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5276 }
5277 }
5278
5279 FLUSH_CHUNK;
5280#undef FLUSH_CHUNK
5281 return 1;
5282}
5283
5284static inline int
5285static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5286{
5287 return RNODE_LIST(node)->nd_head && static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, true) && static_literal_node_p(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq, false);
5288}
5289
5290static int
5291compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5292{
5293 const NODE *line_node = node;
5294
5295 node = RNODE_HASH(node)->nd_head;
5296
5297 if (!node || nd_type_p(node, NODE_ZLIST)) {
5298 if (!popped) {
5299 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5300 }
5301 return 0;
5302 }
5303
5304 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5305
5306 if (popped) {
5307 for (; node; node = RNODE_LIST(node)->nd_next) {
5308 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5309 }
5310 return 1;
5311 }
5312
5313 /* Compilation of a hash literal (or keyword arguments).
5314 * This is very similar to compile_array, but there are some differences:
5315 *
5316 * - It contains key-value pairs. So we need to take every two elements.
5317 * We can assume that the length is always even.
5318 *
5319 * - Merging is done by a method call (id_core_hash_merge_ptr).
5320 * Sometimes we need to insert the receiver, so "anchor" is needed.
5321 * In addition, a method call is much slower than concatarray.
5322 * So it pays only when the subsequence is really long.
5323 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5324 *
5325 * - We need to handle keyword splat: **kw.
5326 * For **kw, the key part (node->nd_head) is NULL, and the value part
5327 * (node->nd_next->nd_head) is "kw".
5328 * The code is a bit difficult to avoid hash allocation for **{}.
5329 */
5330
5331 const int max_stack_len = 0x100;
5332 const int min_tmp_hash_len = 0x800;
5333 int stack_len = 0;
5334 int first_chunk = 1;
5335 DECL_ANCHOR(anchor);
5336 INIT_ANCHOR(anchor);
5337
5338 /* Convert pushed elements to a hash, and merge if needed */
5339#define FLUSH_CHUNK() \
5340 if (stack_len) { \
5341 if (first_chunk) { \
5342 APPEND_LIST(ret, anchor); \
5343 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5344 } \
5345 else { \
5346 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5347 ADD_INSN(ret, line_node, swap); \
5348 APPEND_LIST(ret, anchor); \
5349 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
5350 } \
5351 INIT_ANCHOR(anchor); \
5352 first_chunk = stack_len = 0; \
5353 }
5354
5355 while (node) {
5356 int count = 1;
5357
5358 /* pre-allocation check (this branch can be omittable) */
5359 if (static_literal_node_pair_p(node, iseq)) {
5360 /* count the elements that are optimizable */
5361 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5362 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5363 count++;
5364
5365 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5366 /* The literal contains only optimizable elements, or the subsequence is long enough */
5367 VALUE ary = rb_ary_hidden_new(count);
5368
5369 /* Create a hidden hash */
5370 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5371 VALUE elem[2];
5372 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5373 if (!RB_SPECIAL_CONST_P(elem[0])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[0]);
5374 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5375 if (!RB_SPECIAL_CONST_P(elem[1])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[1]);
5376 rb_ary_cat(ary, elem, 2);
5377 }
5378 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
5379 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
5380 hash = RB_OBJ_SET_FROZEN_SHAREABLE(rb_obj_hide(hash));
5381
5382 /* Emit optimized code */
5383 FLUSH_CHUNK();
5384 if (first_chunk) {
5385 ADD_INSN1(ret, line_node, duphash, hash);
5386 first_chunk = 0;
5387 }
5388 else {
5389 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5390 ADD_INSN(ret, line_node, swap);
5391
5392 ADD_INSN1(ret, line_node, putobject, hash);
5393
5394 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5395 }
5396 RB_OBJ_WRITTEN(iseq, Qundef, hash);
5397 }
5398 }
5399
5400 /* Base case: Compile "count" elements */
5401 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5402
5403 if (CPDEBUG > 0) {
5404 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5405 }
5406
5407 if (RNODE_LIST(node)->nd_head) {
5408 /* Normal key-value pair */
5409 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5410 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5411 stack_len += 2;
5412
5413 /* If there are many pushed elements, flush them to avoid stack overflow */
5414 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5415 }
5416 else {
5417 /* kwsplat case: foo(..., **kw, ...) */
5418 FLUSH_CHUNK();
5419
5420 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5421 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5422 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5423 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5424 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5425
5426 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5427 if (empty_kw) {
5428 if (only_kw && method_call_keywords) {
5429 /* **{} appears at the only keyword argument in method call,
5430 * so it won't be modified.
5431 * kw is a special NODE_LIT that contains a special empty hash,
5432 * so this emits: putobject {}.
5433 * This is only done for method calls and not for literal hashes,
5434 * because literal hashes should always result in a new hash.
5435 */
5436 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5437 }
5438 else if (first_kw) {
5439 /* **{} appears as the first keyword argument, so it may be modified.
5440 * We need to create a fresh hash object.
5441 */
5442 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5443 }
5444 /* Any empty keyword splats that are not the first can be ignored.
5445 * since merging an empty hash into the existing hash is the same
5446 * as not merging it. */
5447 }
5448 else {
5449 if (only_kw && method_call_keywords) {
5450 /* **kw is only keyword argument in method call.
5451 * Use directly. This will be not be flagged as mutable.
5452 * This is only done for method calls and not for literal hashes,
5453 * because literal hashes should always result in a new hash.
5454 */
5455 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5456 }
5457 else {
5458 /* There is more than one keyword argument, or this is not a method
5459 * call. In that case, we need to add an empty hash (if first keyword),
5460 * or merge the hash to the accumulated hash (if not the first keyword).
5461 */
5462 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5463 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5464 else ADD_INSN(ret, line_node, swap);
5465
5466 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5467
5468 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5469 }
5470 }
5471
5472 first_chunk = 0;
5473 }
5474 }
5475 }
5476
5477 FLUSH_CHUNK();
5478#undef FLUSH_CHUNK
5479 return 1;
5480}
5481
5482 VALUE
5483rb_node_case_when_optimizable_literal(const NODE *const node)
5484{
5485 switch (nd_type(node)) {
5486 case NODE_INTEGER:
5487 return rb_node_integer_literal_val(node);
5488 case NODE_FLOAT: {
5489 VALUE v = rb_node_float_literal_val(node);
5490 double ival;
5491
5492 if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5493 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5494 }
5495 return v;
5496 }
5497 case NODE_RATIONAL:
5498 case NODE_IMAGINARY:
5499 return Qundef;
5500 case NODE_NIL:
5501 return Qnil;
5502 case NODE_TRUE:
5503 return Qtrue;
5504 case NODE_FALSE:
5505 return Qfalse;
5506 case NODE_SYM:
5507 return rb_node_sym_string_val(node);
5508 case NODE_LINE:
5509 return rb_node_line_lineno_val(node);
5510 case NODE_STR:
5511 return rb_node_str_string_val(node);
5512 case NODE_FILE:
5513 return rb_node_file_path_val(node);
5514 }
5515 return Qundef;
5516}
5517
5518static int
5519when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5520 LABEL *l1, int only_special_literals, VALUE literals)
5521{
5522 while (vals) {
5523 const NODE *val = RNODE_LIST(vals)->nd_head;
5524 VALUE lit = rb_node_case_when_optimizable_literal(val);
5525
5526 if (UNDEF_P(lit)) {
5527 only_special_literals = 0;
5528 }
5529 else if (NIL_P(rb_hash_lookup(literals, lit))) {
5530 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
5531 }
5532
5533 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5534 debugp_param("nd_lit", get_string_value(val));
5535 lit = get_string_value(val);
5536 ADD_INSN1(cond_seq, val, putobject, lit);
5537 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5538 }
5539 else {
5540 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5541 }
5542
5543 // Emit pattern === target
5544 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5545 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5546 ADD_INSNL(cond_seq, val, branchif, l1);
5547 vals = RNODE_LIST(vals)->nd_next;
5548 }
5549 return only_special_literals;
5550}
5551
5552static int
5553when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5554 LABEL *l1, int only_special_literals, VALUE literals)
5555{
5556 const NODE *line_node = vals;
5557
5558 switch (nd_type(vals)) {
5559 case NODE_LIST:
5560 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5561 return COMPILE_NG;
5562 break;
5563 case NODE_SPLAT:
5564 ADD_INSN (cond_seq, line_node, dup);
5565 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5566 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5567 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5568 ADD_INSNL(cond_seq, line_node, branchif, l1);
5569 break;
5570 case NODE_ARGSCAT:
5571 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5572 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5573 break;
5574 case NODE_ARGSPUSH:
5575 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5576 ADD_INSN (cond_seq, line_node, dup);
5577 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5578 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5579 ADD_INSNL(cond_seq, line_node, branchif, l1);
5580 break;
5581 default:
5582 ADD_INSN (cond_seq, line_node, dup);
5583 CHECK(COMPILE(cond_seq, "when val", vals));
5584 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5585 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5586 ADD_INSNL(cond_seq, line_node, branchif, l1);
5587 break;
5588 }
5589 return COMPILE_OK;
5590}
5591
5592/* Multiple Assignment Handling
5593 *
5594 * In order to handle evaluation of multiple assignment such that the left hand side
5595 * is evaluated before the right hand side, we need to process the left hand side
5596 * and see if there are any attributes that need to be assigned, or constants set
5597 * on explicit objects. If so, we add instructions to evaluate the receiver of
5598 * any assigned attributes or constants before we process the right hand side.
5599 *
5600 * For a multiple assignment such as:
5601 *
5602 * l1.m1, l2[0] = r3, r4
5603 *
5604 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5605 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5606 * On the VM stack, this looks like:
5607 *
5608 * self # putself
5609 * l1 # send
5610 * l1, self # putself
5611 * l1, l2 # send
5612 * l1, l2, 0 # putobject 0
5613 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5614 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5615 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5616 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5617 * l1, l2, 0, [r3, r4], r4, m1= # send
5618 * l1, l2, 0, [r3, r4], r4 # pop
5619 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5620 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5621 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5622 * l1, l2, 0, [r3, r4], r4, []= # send
5623 * l1, l2, 0, [r3, r4], r4 # pop
5624 * l1, l2, 0, [r3, r4] # pop
5625 * [r3, r4], l2, 0, [r3, r4] # setn 3
5626 * [r3, r4], l2, 0 # pop
5627 * [r3, r4], l2 # pop
5628 * [r3, r4] # pop
5629 *
5630 * This is made more complex when you have to handle splats, post args,
5631 * and arbitrary levels of nesting. You need to keep track of the total
5632 * number of attributes to set, and for each attribute, how many entries
5633 * are on the stack before the final attribute, in order to correctly
5634 * calculate the topn value to use to get the receiver of the attribute
5635 * setter method.
5636 *
5637 * A brief description of the VM stack for simple multiple assignment
5638 * with no splat (rhs_array will not be present if the return value of
5639 * the multiple assignment is not needed):
5640 *
5641 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5642 *
5643 * For multiple assignment with splats, while processing the part before
5644 * the splat (splat+post here is an array of the splat and the post arguments):
5645 *
5646 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5647 *
5648 * When processing the splat and post arguments:
5649 *
5650 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5651 *
5652 * When processing nested multiple assignment, existing values on the stack
5653 * are kept. So for:
5654 *
5655 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5656 *
5657 * The stack layout would be the following before processing the nested
5658 * multiple assignment:
5659 *
5660 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5661 *
5662 * In order to handle this correctly, we need to keep track of the nesting
5663 * level for each attribute assignment, as well as the attribute number
5664 * (left hand side attributes are processed left to right) and number of
5665 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5666 * this information.
5667 *
5668 * We also need to track information for the entire multiple assignment, such
5669 * as the total number of arguments, and the current nesting level, to
5670 * handle both nested multiple assignment as well as cases where the
5671 * rhs is not needed. We also need to keep track of all attribute
5672 * assignments in this, which we do using a linked listed. struct masgn_state
5673 * tracks this information.
5674 */
5675
5676 struct masgn_lhs_node {
5677 INSN *before_insn;
5678 struct masgn_lhs_node *next;
5679 const NODE *line_node;
5680 int argn;
5681 int num_args;
5682 int lhs_pos;
5683};
5684
5685 struct masgn_state {
5686 struct masgn_lhs_node *first_memo;
5687 struct masgn_lhs_node *last_memo;
5688 int lhs_level;
5689 int num_args;
5690 bool nested;
5691};
5692
5693static int
5694add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5695{
5696 if (!state) {
5697 rb_bug("no masgn_state");
5698 }
5699
5700 struct masgn_lhs_node *memo;
5701 memo = malloc(sizeof(struct masgn_lhs_node));
5702 if (!memo) {
5703 return COMPILE_NG;
5704 }
5705
5706 memo->before_insn = before_insn;
5707 memo->line_node = line_node;
5708 memo->argn = state->num_args + 1;
5709 memo->num_args = argc;
5710 state->num_args += argc;
5711 memo->lhs_pos = lhs_pos;
5712 memo->next = NULL;
5713 if (!state->first_memo) {
5714 state->first_memo = memo;
5715 }
5716 else {
5717 state->last_memo->next = memo;
5718 }
5719 state->last_memo = memo;
5720
5721 return COMPILE_OK;
5722}
5723
5724static int compile_massign0(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs, LINK_ANCHOR *const lhs, LINK_ANCHOR *const post, const NODE *const node, struct masgn_state *state, int popped);
5725
5726static int
5727compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs, LINK_ANCHOR *const lhs, LINK_ANCHOR *const post, const NODE *const node, struct masgn_state *state, int lhs_pos)
5728{
5729 switch (nd_type(node)) {
5730 case NODE_ATTRASGN: {
5731 INSN *iobj;
5732 const NODE *line_node = node;
5733
5734 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5735
5736 bool safenav_call = false;
5737 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5738 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5739 ASSUME(iobj);
5740 ELEM_REMOVE(insn_element);
5741 if (!IS_INSN_ID(iobj, send)) {
5742 safenav_call = true;
5743 iobj = (INSN *)get_prev_insn(iobj);
5744 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5745 }
5746 (pre->last = iobj->link.prev)->next = 0;
5747
5748 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5749 int argc = vm_ci_argc(ci) + 1;
5750 ci = ci_argc_set(iseq, ci, argc);
5751 OPERAND_AT(iobj, 0) = (VALUE)ci;
5752 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5753
5754 if (argc == 1) {
5755 ADD_INSN(lhs, line_node, swap);
5756 }
5757 else {
5758 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5759 }
5760
5761 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5762 return COMPILE_NG;
5763 }
5764
5765 iobj->link.prev = lhs->last;
5766 lhs->last->next = &iobj->link;
5767 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5768 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5769 int argc = vm_ci_argc(ci);
5770 bool dupsplat = false;
5771 ci = ci_argc_set(iseq, ci, argc - 1);
5772 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5773 /* Given h[*a], _ = ary
5774 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5775 * `a` must be dupped, because it will be appended with ary[0]
5776 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5777 */
5778 dupsplat = true;
5779 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5780 }
5781 OPERAND_AT(iobj, 0) = (VALUE)ci;
5782 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5783
5784 /* Given: h[*a], h[*b, 1] = ary
5785 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
5786 * so this uses splatarray true on a to dup it before using pushtoarray
5787 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
5788 * so you can use pushtoarray directly
5789 */
5790 int line_no = nd_line(line_node);
5791 int node_id = nd_node_id(line_node);
5792
5793 if (dupsplat) {
5794 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5795 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
5796 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5797 }
5798 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
5799 }
5800 if (!safenav_call) {
5801 ADD_INSN(lhs, line_node, pop);
5802 if (argc != 1) {
5803 ADD_INSN(lhs, line_node, pop);
5804 }
5805 }
5806 for (int i=0; i < argc; i++) {
5807 ADD_INSN(post, line_node, pop);
5808 }
5809 break;
5810 }
5811 case NODE_MASGN: {
5812 DECL_ANCHOR(nest_rhs);
5813 INIT_ANCHOR(nest_rhs);
5814 DECL_ANCHOR(nest_lhs);
5815 INIT_ANCHOR(nest_lhs);
5816
5817 int prev_level = state->lhs_level;
5818 bool prev_nested = state->nested;
5819 state->nested = 1;
5820 state->lhs_level = lhs_pos - 1;
5821 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5822 state->lhs_level = prev_level;
5823 state->nested = prev_nested;
5824
5825 ADD_SEQ(lhs, nest_rhs);
5826 ADD_SEQ(lhs, nest_lhs);
5827 break;
5828 }
5829 case NODE_CDECL:
5830 if (!RNODE_CDECL(node)->nd_vid) {
5831 /* Special handling only needed for expr::C, not for C */
5832 INSN *iobj;
5833
5834 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5835
5836 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5837 iobj = (INSN *)insn_element; /* setconstant insn */
5838 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5839 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5840 ELEM_REMOVE(insn_element);
5841 pre->last = iobj->link.prev;
5842 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5843
5844 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5845 return COMPILE_NG;
5846 }
5847
5848 ADD_INSN(post, node, pop);
5849 break;
5850 }
5851 /* Fallthrough */
5852 default: {
5853 DECL_ANCHOR(anchor);
5854 INIT_ANCHOR(anchor);
5855 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5856 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5857 ADD_SEQ(lhs, anchor);
5858 }
5859 }
5860
5861 return COMPILE_OK;
5862}
5863
5864static int
5865compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5866{
5867 if (lhsn) {
5868 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
5869 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
5870 }
5871 return COMPILE_OK;
5872}
5873
5874static int
5875compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5876 const NODE *rhsn, const NODE *orig_lhsn)
5877{
5878 VALUE mem[64];
5879 const int memsize = numberof(mem);
5880 int memindex = 0;
5881 int llen = 0, rlen = 0;
5882 int i;
5883 const NODE *lhsn = orig_lhsn;
5884
5885#define MEMORY(v) { \
5886 int i; \
5887 if (memindex == memsize) return 0; \
5888 for (i=0; i<memindex; i++) { \
5889 if (mem[i] == (v)) return 0; \
5890 } \
5891 mem[memindex++] = (v); \
5892}
5893
5894 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5895 return 0;
5896 }
5897
5898 while (lhsn) {
5899 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
5900 switch (nd_type(ln)) {
5901 case NODE_LASGN:
5902 case NODE_DASGN:
5903 case NODE_IASGN:
5904 case NODE_CVASGN:
5905 MEMORY(get_nd_vid(ln));
5906 break;
5907 default:
5908 return 0;
5909 }
5910 lhsn = RNODE_LIST(lhsn)->nd_next;
5911 llen++;
5912 }
5913
5914 while (rhsn) {
5915 if (llen <= rlen) {
5916 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
5917 }
5918 else {
5919 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
5920 }
5921 rhsn = RNODE_LIST(rhsn)->nd_next;
5922 rlen++;
5923 }
5924
5925 if (llen > rlen) {
5926 for (i=0; i<llen-rlen; i++) {
5927 ADD_INSN(ret, orig_lhsn, putnil);
5928 }
5929 }
5930
5931 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5932 return 1;
5933}
5934
5935static int
5936compile_massign0(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs, LINK_ANCHOR *const lhs, LINK_ANCHOR *const post, const NODE *const node, struct masgn_state *state, int popped)
5937{
5938 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
5939 const NODE *splatn = RNODE_MASGN(node)->nd_args;
5940 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
5941 const NODE *lhsn_count = lhsn;
5942 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5943
5944 int llen = 0;
5945 int lpos = 0;
5946
5947 while (lhsn_count) {
5948 llen++;
5949 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
5950 }
5951 while (lhsn) {
5952 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5953 lpos++;
5954 lhsn = RNODE_LIST(lhsn)->nd_next;
5955 }
5956
5957 if (lhs_splat) {
5958 if (nd_type_p(splatn, NODE_POSTARG)) {
5959 /*a, b, *r, p1, p2 */
5960 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
5961 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
5962 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
5963 int ppos = 0;
5964 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5965
5966 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
5967
5968 if (NODE_NAMED_REST_P(restn)) {
5969 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5970 }
5971 while (postn) {
5972 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
5973 ppos++;
5974 postn = RNODE_LIST(postn)->nd_next;
5975 }
5976 }
5977 else {
5978 /* a, b, *r */
5979 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5980 }
5981 }
5982
5983 if (!state->nested) {
5984 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
5985 }
5986
5987 if (!popped) {
5988 ADD_INSN(rhs, node, dup);
5989 }
5990 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
5991 return COMPILE_OK;
5992}
5993
5994static int
5995compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
5996{
5997 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
5998 struct masgn_state state;
5999 state.lhs_level = popped ? 0 : 1;
6000 state.nested = 0;
6001 state.num_args = 0;
6002 state.first_memo = NULL;
6003 state.last_memo = NULL;
6004
6005 DECL_ANCHOR(pre);
6006 INIT_ANCHOR(pre);
6007 DECL_ANCHOR(rhs);
6008 INIT_ANCHOR(rhs);
6009 DECL_ANCHOR(lhs);
6010 INIT_ANCHOR(lhs);
6011 DECL_ANCHOR(post);
6012 INIT_ANCHOR(post);
6013 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
6014
6015 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
6016 while (memo) {
6017 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
6018 for (int i = 0; i < memo->num_args; i++) {
6019 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
6020 }
6021 tmp_memo = memo->next;
6022 free(memo);
6023 memo = tmp_memo;
6024 }
6025 CHECK(ok);
6026
6027 ADD_SEQ(ret, pre);
6028 ADD_SEQ(ret, rhs);
6029 ADD_SEQ(ret, lhs);
6030 if (!popped && state.num_args >= 1) {
6031 /* make sure rhs array is returned before popping */
6032 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
6033 }
6034 ADD_SEQ(ret, post);
6035 }
6036 return COMPILE_OK;
6037}
6038
6039static VALUE
6040collect_const_segments(rb_iseq_t *iseq, const NODE *node)
6041{
6042 VALUE arr = rb_ary_new();
6043 for (;;) {
6044 switch (nd_type(node)) {
6045 case NODE_CONST:
6046 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
6047 RB_OBJ_SET_SHAREABLE(arr);
6048 return arr;
6049 case NODE_COLON3:
6050 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
6051 rb_ary_unshift(arr, ID2SYM(idNULL));
6052 RB_OBJ_SET_SHAREABLE(arr);
6053 return arr;
6054 case NODE_COLON2:
6055 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
6056 node = RNODE_COLON2(node)->nd_head;
6057 break;
6058 default:
6059 return Qfalse;
6060 }
6061 }
6062}
6063
6064static int
6065compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
6066 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
6067{
6068 switch (nd_type(node)) {
6069 case NODE_CONST:
6070 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
6071 ADD_INSN1(body, node, putobject, Qtrue);
6072 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
6073 break;
6074 case NODE_COLON3:
6075 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
6076 ADD_INSN(body, node, pop);
6077 ADD_INSN1(body, node, putobject, rb_cObject);
6078 ADD_INSN1(body, node, putobject, Qtrue);
6079 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
6080 break;
6081 case NODE_COLON2:
6082 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
6083 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
6084 ADD_INSN1(body, node, putobject, Qfalse);
6085 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
6086 break;
6087 default:
6088 CHECK(COMPILE(pref, "const colon2 prefix", node));
6089 break;
6090 }
6091 return COMPILE_OK;
6092}
6093
6094static int
6095compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
6096{
6097 if (nd_type_p(cpath, NODE_COLON3)) {
6098 /* toplevel class ::Foo */
6099 ADD_INSN1(ret, cpath, putobject, rb_cObject);
6100 return VM_DEFINECLASS_FLAG_SCOPED;
6101 }
6102 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
6103 /* Bar::Foo */
6104 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
6105 return VM_DEFINECLASS_FLAG_SCOPED;
6106 }
6107 else {
6108 /* class at cbase Foo */
6109 ADD_INSN1(ret, cpath, putspecialobject,
6110 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
6111 return 0;
6112 }
6113}
6114
6115static inline int
6116private_recv_p(const NODE *node)
6117{
6118 NODE *recv = get_nd_recv(node);
6119 if (recv && nd_type_p(recv, NODE_SELF)) {
6120 return RNODE_SELF(recv)->nd_state != 0;
6121 }
6122 return 0;
6123}
6124
6125static void
6126defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6127 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
6128
6129static int
6130compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const enum node_type type, const NODE *const line_node, int popped, bool assume_receiver);
6131
6132static void
6133defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6134 const NODE *const node, LABEL **lfinish, VALUE needstr,
6135 bool keep_result)
6136{
6137 enum defined_type expr_type = DEFINED_NOT_DEFINED;
6138 enum node_type type;
6139 const int line = nd_line(node);
6140 const NODE *line_node = node;
6141
6142 switch (type = nd_type(node)) {
6143
6144 /* easy literals */
6145 case NODE_NIL:
6146 expr_type = DEFINED_NIL;
6147 break;
6148 case NODE_SELF:
6149 expr_type = DEFINED_SELF;
6150 break;
6151 case NODE_TRUE:
6152 expr_type = DEFINED_TRUE;
6153 break;
6154 case NODE_FALSE:
6155 expr_type = DEFINED_FALSE;
6156 break;
6157
6158 case NODE_HASH:
6159 case NODE_LIST:{
6160 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6161
6162 if (vals) {
6163 do {
6164 if (RNODE_LIST(vals)->nd_head) {
6165 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
6166
6167 if (!lfinish[1]) {
6168 lfinish[1] = NEW_LABEL(line);
6169 }
6170 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6171 }
6172 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6173 }
6174 }
6175 /* fall through */
6176 case NODE_STR:
6177 case NODE_SYM:
6178 case NODE_REGX:
6179 case NODE_LINE:
6180 case NODE_FILE:
6181 case NODE_ENCODING:
6182 case NODE_INTEGER:
6183 case NODE_FLOAT:
6184 case NODE_RATIONAL:
6185 case NODE_IMAGINARY:
6186 case NODE_ZLIST:
6187 case NODE_AND:
6188 case NODE_OR:
6189 default:
6190 expr_type = DEFINED_EXPR;
6191 break;
6192
6193 case NODE_SPLAT:
6194 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6195 if (!lfinish[1]) {
6196 lfinish[1] = NEW_LABEL(line);
6197 }
6198 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6199 expr_type = DEFINED_EXPR;
6200 break;
6201
6202 /* variables */
6203 case NODE_LVAR:
6204 case NODE_DVAR:
6205 expr_type = DEFINED_LVAR;
6206 break;
6207
6208#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6209 case NODE_IVAR:
6210 ADD_INSN3(ret, line_node, definedivar,
6211 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6212 return;
6213
6214 case NODE_GVAR:
6215 ADD_INSN(ret, line_node, putnil);
6216 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6217 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6218 return;
6219
6220 case NODE_CVAR:
6221 ADD_INSN(ret, line_node, putnil);
6222 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6223 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6224 return;
6225
6226 case NODE_CONST:
6227 ADD_INSN(ret, line_node, putnil);
6228 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6229 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6230 return;
6231 case NODE_COLON2:
6232 if (!lfinish[1]) {
6233 lfinish[1] = NEW_LABEL(line);
6234 }
6235 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6236 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6237 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6238
6239 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6240 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6241 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6242 }
6243 else {
6244 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6245 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6246 }
6247 return;
6248 case NODE_COLON3:
6249 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6250 ADD_INSN3(ret, line_node, defined,
6251 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6252 return;
6253
6254 /* method dispatch */
6255 case NODE_CALL:
6256 case NODE_OPCALL:
6257 case NODE_VCALL:
6258 case NODE_FCALL:
6259 case NODE_ATTRASGN:{
6260 const int explicit_receiver =
6261 (type == NODE_CALL || type == NODE_OPCALL ||
6262 (type == NODE_ATTRASGN && !private_recv_p(node)));
6263
6264 if (get_nd_args(node) || explicit_receiver) {
6265 if (!lfinish[1]) {
6266 lfinish[1] = NEW_LABEL(line);
6267 }
6268 if (!lfinish[2]) {
6269 lfinish[2] = NEW_LABEL(line);
6270 }
6271 }
6272 if (get_nd_args(node)) {
6273 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6274 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6275 }
6276 if (explicit_receiver) {
6277 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6278 switch (nd_type(get_nd_recv(node))) {
6279 case NODE_CALL:
6280 case NODE_OPCALL:
6281 case NODE_VCALL:
6282 case NODE_FCALL:
6283 case NODE_ATTRASGN:
6284 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6285 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6286 break;
6287 default:
6288 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6289 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6290 break;
6291 }
6292 if (keep_result) {
6293 ADD_INSN(ret, line_node, dup);
6294 }
6295 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6296 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6297 }
6298 else {
6299 ADD_INSN(ret, line_node, putself);
6300 if (keep_result) {
6301 ADD_INSN(ret, line_node, dup);
6302 }
6303 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6304 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6305 }
6306 return;
6307 }
6308
6309 case NODE_YIELD:
6310 ADD_INSN(ret, line_node, putnil);
6311 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6312 PUSH_VAL(DEFINED_YIELD));
6313 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6314 return;
6315
6316 case NODE_BACK_REF:
6317 case NODE_NTH_REF:
6318 ADD_INSN(ret, line_node, putnil);
6319 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6320 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6321 PUSH_VAL(DEFINED_GVAR));
6322 return;
6323
6324 case NODE_SUPER:
6325 case NODE_ZSUPER:
6326 ADD_INSN(ret, line_node, putnil);
6327 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6328 PUSH_VAL(DEFINED_ZSUPER));
6329 return;
6330
6331#undef PUSH_VAL
6332 case NODE_OP_ASGN1:
6333 case NODE_OP_ASGN2:
6334 case NODE_OP_ASGN_OR:
6335 case NODE_OP_ASGN_AND:
6336 case NODE_MASGN:
6337 case NODE_LASGN:
6338 case NODE_DASGN:
6339 case NODE_GASGN:
6340 case NODE_IASGN:
6341 case NODE_CDECL:
6342 case NODE_CVASGN:
6343 case NODE_OP_CDECL:
6344 expr_type = DEFINED_ASGN;
6345 break;
6346 }
6347
6348 RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6349
6350 if (needstr != Qfalse) {
6351 VALUE str = rb_iseq_defined_string(expr_type);
6352 ADD_INSN1(ret, line_node, putobject, str);
6353 }
6354 else {
6355 ADD_INSN1(ret, line_node, putobject, Qtrue);
6356 }
6357}
6358
6359static void
6360build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6361{
6362 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6363 iseq_set_exception_local_table(iseq);
6364}
6365
6366static void
6367defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6368 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6369{
6370 LINK_ELEMENT *lcur = ret->last;
6371 defined_expr0(iseq, ret, node, lfinish, needstr, false);
6372 if (lfinish[1]) {
6373 int line = nd_line(node);
6374 LABEL *lstart = NEW_LABEL(line);
6375 LABEL *lend = NEW_LABEL(line);
6376 const rb_iseq_t *rescue;
6377 struct rb_iseq_new_with_callback_callback_func *ifunc =
6378 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6379 rescue = NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc,
6380 rb_str_concat(rb_str_new2("defined guard in "),
6381 ISEQ_BODY(iseq)->location.label),
6382 ISEQ_TYPE_RESCUE, 0);
6383 lstart->rescued = LABEL_RESCUE_BEG;
6384 lend->rescued = LABEL_RESCUE_END;
6385 APPEND_LABEL(ret, lcur, lstart);
6386 ADD_LABEL(ret, lend);
6387 if (!ignore) {
6388 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6389 }
6390 }
6391}
6392
6393static int
6394compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6395{
6396 const int line = nd_line(node);
6397 const NODE *line_node = node;
6398 if (!RNODE_DEFINED(node)->nd_head) {
6399 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6400 ADD_INSN1(ret, line_node, putobject, str);
6401 }
6402 else {
6403 LABEL *lfinish[3];
6404 LINK_ELEMENT *last = ret->last;
6405 lfinish[0] = NEW_LABEL(line);
6406 lfinish[1] = 0;
6407 lfinish[2] = 0;
6408 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6409 if (lfinish[1]) {
6410 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6411 ADD_INSN(ret, line_node, swap);
6412 if (lfinish[2]) {
6413 ADD_LABEL(ret, lfinish[2]);
6414 }
6415 ADD_INSN(ret, line_node, pop);
6416 ADD_LABEL(ret, lfinish[1]);
6417 }
6418 ADD_LABEL(ret, lfinish[0]);
6419 }
6420 return COMPILE_OK;
6421}
6422
6423static VALUE
6424make_name_for_block(const rb_iseq_t *orig_iseq)
6425{
6426 int level = 1;
6427 const rb_iseq_t *iseq = orig_iseq;
6428
6429 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6430 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6431 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6432 level++;
6433 }
6434 iseq = ISEQ_BODY(iseq)->parent_iseq;
6435 }
6436 }
6437
6438 if (level == 1) {
6439 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6440 }
6441 else {
6442 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6443 }
6444}
6445
6446static void
6447push_ensure_entry(rb_iseq_t *iseq,
6448 struct iseq_compile_data_ensure_node_stack *enl,
6449 struct ensure_range *er, const void *const node)
6450{
6451 enl->ensure_node = node;
6452 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6453 enl->erange = er;
6454 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6455}
6456
6457static void
6458add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6459 LABEL *lstart, LABEL *lend)
6460{
6461 struct ensure_range *ne =
6462 compile_data_alloc(iseq, sizeof(struct ensure_range));
6463
6464 while (erange->next != 0) {
6465 erange = erange->next;
6466 }
6467 ne->next = 0;
6468 ne->begin = lend;
6469 ne->end = erange->end;
6470 erange->end = lstart;
6471
6472 erange->next = ne;
6473}
6474
6475static bool
6476can_add_ensure_iseq(const rb_iseq_t *iseq)
6477{
6478 struct iseq_compile_data_ensure_node_stack *e;
6479 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6480 while (e) {
6481 if (e->ensure_node) return false;
6482 e = e->prev;
6483 }
6484 }
6485 return true;
6486}
6487
6488static void
6489add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6490{
6491 RUBY_ASSERT(can_add_ensure_iseq(iseq));
6492
6493 struct iseq_compile_data_ensure_node_stack *enlp =
6494 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6495 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6496 DECL_ANCHOR(ensure);
6497
6498 INIT_ANCHOR(ensure);
6499 while (enlp) {
6500 if (enlp->erange != NULL) {
6501 DECL_ANCHOR(ensure_part);
6502 LABEL *lstart = NEW_LABEL(0);
6503 LABEL *lend = NEW_LABEL(0);
6504 INIT_ANCHOR(ensure_part);
6505
6506 add_ensure_range(iseq, enlp->erange, lstart, lend);
6507
6508 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6509 ADD_LABEL(ensure_part, lstart);
6510 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6511 ADD_LABEL(ensure_part, lend);
6512 ADD_SEQ(ensure, ensure_part);
6513 }
6514 else {
6515 if (!is_return) {
6516 break;
6517 }
6518 }
6519 enlp = enlp->prev;
6520 }
6521 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6522 ADD_SEQ(ret, ensure);
6523}
6524
6525#if RUBY_DEBUG
6526static int
6527check_keyword(const NODE *node)
6528{
6529 /* This check is essentially a code clone of compile_keyword_arg. */
6530
6531 if (nd_type_p(node, NODE_LIST)) {
6532 while (RNODE_LIST(node)->nd_next) {
6533 node = RNODE_LIST(node)->nd_next;
6534 }
6535 node = RNODE_LIST(node)->nd_head;
6536 }
6537
6538 return keyword_node_p(node);
6539}
6540#endif
6541
6542static bool
6543keyword_node_single_splat_p(NODE *kwnode)
6544{
6545 RUBY_ASSERT(keyword_node_p(kwnode));
6546
6547 NODE *node = RNODE_HASH(kwnode)->nd_head;
6548 return RNODE_LIST(node)->nd_head == NULL &&
6549 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6550}
6551
6552static void
6553compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6554 NODE *kwnode, unsigned int *flag_ptr)
6555{
6556 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6557 ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6558 ADD_INSN1(args, argn, newhash, INT2FIX(0));
6559 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6560 ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6561}
6562
6563#define SPLATARRAY_FALSE 0
6564#define SPLATARRAY_TRUE 1
6565#define DUP_SINGLE_KW_SPLAT 2
6566
6567static int
6568setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6569 unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6570{
6571 if (!argn) return 0;
6572
6573 NODE *kwnode = NULL;
6574
6575 switch (nd_type(argn)) {
6576 case NODE_LIST: {
6577 // f(x, y, z)
6578 int len = compile_args(iseq, args, argn, &kwnode);
6579 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6580
6581 if (kwnode) {
6582 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6583 len -= 1;
6584 }
6585 else {
6586 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6587 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6588 }
6589 else {
6590 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6591 }
6592 }
6593 }
6594
6595 return len;
6596 }
6597 case NODE_SPLAT: {
6598 // f(*a)
6599 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6600 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6601 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6602 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6603 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6604 return 1;
6605 }
6606 case NODE_ARGSCAT: {
6607 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6608 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6609 bool args_pushed = false;
6610
6611 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6612 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6613 if (kwnode) rest_len--;
6614 ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6615 args_pushed = true;
6616 }
6617 else {
6618 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6619 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6620 }
6621
6622 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6623 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6624 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6625 argc += 1;
6626 }
6627 else if (!args_pushed) {
6628 ADD_INSN(args, argn, concattoarray);
6629 }
6630
6631 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6632 if (kwnode) {
6633 // kwsplat
6634 *flag_ptr |= VM_CALL_KW_SPLAT;
6635 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6636 argc += 1;
6637 }
6638
6639 return argc;
6640 }
6641 case NODE_ARGSPUSH: {
6642 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6643 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6644
6645 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6646 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6647 if (kwnode) rest_len--;
6648 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6649 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6650 }
6651 else {
6652 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6653 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6654 }
6655 else {
6656 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6657 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6658 }
6659 }
6660
6661 if (kwnode) {
6662 // f(*a, k:1)
6663 *flag_ptr |= VM_CALL_KW_SPLAT;
6664 if (!keyword_node_single_splat_p(kwnode)) {
6665 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6666 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6667 }
6668 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6669 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6670 }
6671 else {
6672 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6673 }
6674 argc += 1;
6675 }
6676
6677 return argc;
6678 }
6679 default: {
6680 UNKNOWN_NODE("setup_arg", argn, Qnil);
6681 }
6682 }
6683}
6684
6685static void
6686setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6687{
6688 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6689 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6690 }
6691}
6692
6693static bool
6694setup_args_dup_rest_p(const NODE *argn)
6695{
6696 switch(nd_type(argn)) {
6697 case NODE_LVAR:
6698 case NODE_DVAR:
6699 case NODE_GVAR:
6700 case NODE_IVAR:
6701 case NODE_CVAR:
6702 case NODE_CONST:
6703 case NODE_COLON3:
6704 case NODE_INTEGER:
6705 case NODE_FLOAT:
6706 case NODE_RATIONAL:
6707 case NODE_IMAGINARY:
6708 case NODE_STR:
6709 case NODE_SYM:
6710 case NODE_REGX:
6711 case NODE_SELF:
6712 case NODE_NIL:
6713 case NODE_TRUE:
6714 case NODE_FALSE:
6715 case NODE_LAMBDA:
6716 case NODE_NTH_REF:
6717 case NODE_BACK_REF:
6718 return false;
6719 case NODE_COLON2:
6720 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6721 case NODE_LIST:
6722 while (argn) {
6723 if (setup_args_dup_rest_p(RNODE_LIST(argn)->nd_head)) {
6724 return true;
6725 }
6726 argn = RNODE_LIST(argn)->nd_next;
6727 }
6728 return false;
6729 default:
6730 return true;
6731 }
6732}
6733
6734static VALUE
6735setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6736 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6737{
6738 VALUE ret;
6739 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6740
6741 if (argn) {
6742 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6743 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6744
6745 if (check_arg) {
6746 switch(nd_type(check_arg)) {
6747 case(NODE_SPLAT):
6748 // avoid caller side array allocation for f(*arg)
6749 dup_rest = SPLATARRAY_FALSE;
6750 break;
6751 case(NODE_ARGSCAT):
6752 // avoid caller side array allocation for f(1, *arg)
6753 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6754 break;
6755 case(NODE_ARGSPUSH):
6756 // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
6757 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6758 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6759 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6760 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6761 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6762
6763 if (dup_rest == SPLATARRAY_FALSE) {
6764 // require allocation for keyword key/value/splat that may modify splatted argument
6765 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6766 while (node) {
6767 NODE *key_node = RNODE_LIST(node)->nd_head;
6768 if (key_node && setup_args_dup_rest_p(key_node)) {
6769 dup_rest = SPLATARRAY_TRUE;
6770 break;
6771 }
6772
6773 node = RNODE_LIST(node)->nd_next;
6774 NODE *value_node = RNODE_LIST(node)->nd_head;
6775 if (setup_args_dup_rest_p(value_node)) {
6776 dup_rest = SPLATARRAY_TRUE;
6777 break;
6778 }
6779
6780 node = RNODE_LIST(node)->nd_next;
6781 }
6782 }
6783 break;
6784 default:
6785 break;
6786 }
6787 }
6788
6789 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6790 // for block pass that may modify splatted argument, dup rest and kwrest if given
6791 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6792 }
6793 }
6794 initial_dup_rest = dup_rest;
6795
6796 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6797 DECL_ANCHOR(arg_block);
6798 INIT_ANCHOR(arg_block);
6799
6800 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6801 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
6802
6803 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
6804 const NODE * arg_node =
6805 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
6806
6807 int argc = 0;
6808
6809 // Only compile leading args:
6810 // foo(x, y, ...)
6811 // ^^^^
6812 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
6813 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
6814 }
6815
6816 *flag |= VM_CALL_FORWARDING;
6817
6818 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
6819 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6820 return INT2FIX(argc);
6821 }
6822 else {
6823 *flag |= VM_CALL_ARGS_BLOCKARG;
6824
6825 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
6826 }
6827
6828 if (LIST_INSN_SIZE_ONE(arg_block)) {
6829 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
6830 if (IS_INSN(elem)) {
6831 INSN *iobj = (INSN *)elem;
6832 if (iobj->insn_id == BIN(getblockparam)) {
6833 iobj->insn_id = BIN(getblockparamproxy);
6834 }
6835 }
6836 }
6837 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
6838 ADD_SEQ(args, arg_block);
6839 }
6840 else {
6841 ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
6842 }
6843 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6844 return ret;
6845}
6846
6847static void
6848build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
6849{
6850 const NODE *body = ptr;
6851 int line = nd_line(body);
6852 VALUE argc = INT2FIX(0);
6853 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
6854
6855 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6856 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
6857 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
6858 iseq_set_local_table(iseq, 0, 0);
6859}
6860
6861static void
6862compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
6863{
6864 const NODE *vars;
6865 LINK_ELEMENT *last;
6866 int line = nd_line(node);
6867 const NODE *line_node = node;
6868 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
6869
6870#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6871 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
6872#else
6873 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
6874#endif
6875 ADD_INSN(ret, line_node, dup);
6876 ADD_INSNL(ret, line_node, branchunless, fail_label);
6877
6878 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6879 INSN *cap;
6880 if (RNODE_BLOCK(vars)->nd_next) {
6881 ADD_INSN(ret, line_node, dup);
6882 }
6883 last = ret->last;
6884 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6885 last = last->next; /* putobject :var */
6886 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
6887 NULL, INT2FIX(0), NULL);
6888 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
6889#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6890 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
6891 /* only one name */
6892 DECL_ANCHOR(nom);
6893
6894 INIT_ANCHOR(nom);
6895 ADD_INSNL(nom, line_node, jump, end_label);
6896 ADD_LABEL(nom, fail_label);
6897# if 0 /* $~ must be MatchData or nil */
6898 ADD_INSN(nom, line_node, pop);
6899 ADD_INSN(nom, line_node, putnil);
6900# endif
6901 ADD_LABEL(nom, end_label);
6902 (nom->last->next = cap->link.next)->prev = nom->last;
6903 (cap->link.next = nom->anchor.next)->prev = &cap->link;
6904 return;
6905 }
6906#endif
6907 }
6908 ADD_INSNL(ret, line_node, jump, end_label);
6909 ADD_LABEL(ret, fail_label);
6910 ADD_INSN(ret, line_node, pop);
6911 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6912 last = ret->last;
6913 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6914 last = last->next; /* putobject :var */
6915 ((INSN*)last)->insn_id = BIN(putnil);
6916 ((INSN*)last)->operand_size = 0;
6917 }
6918 ADD_LABEL(ret, end_label);
6919}
6920
6921static int
6922optimizable_range_item_p(const NODE *n)
6923{
6924 if (!n) return FALSE;
6925 switch (nd_type(n)) {
6926 case NODE_LINE:
6927 return TRUE;
6928 case NODE_INTEGER:
6929 return TRUE;
6930 case NODE_NIL:
6931 return TRUE;
6932 default:
6933 return FALSE;
6934 }
6935}
6936
6937static VALUE
6938optimized_range_item(const NODE *n)
6939{
6940 switch (nd_type(n)) {
6941 case NODE_LINE:
6942 return rb_node_line_lineno_val(n);
6943 case NODE_INTEGER:
6944 return rb_node_integer_literal_val(n);
6945 case NODE_FLOAT:
6946 return rb_node_float_literal_val(n);
6947 case NODE_RATIONAL:
6948 return rb_node_rational_literal_val(n);
6949 case NODE_IMAGINARY:
6950 return rb_node_imaginary_literal_val(n);
6951 case NODE_NIL:
6952 return Qnil;
6953 default:
6954 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
6955 }
6956}
6957
6958static int
6959compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6960{
6961 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
6962 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
6963
6964 const int line = nd_line(node);
6965 const NODE *line_node = node;
6966 DECL_ANCHOR(cond_seq);
6967 LABEL *then_label, *else_label, *end_label;
6968 VALUE branches = Qfalse;
6969
6970 INIT_ANCHOR(cond_seq);
6971 then_label = NEW_LABEL(line);
6972 else_label = NEW_LABEL(line);
6973 end_label = 0;
6974
6975 NODE *cond = RNODE_IF(node)->nd_cond;
6976 if (nd_type(cond) == NODE_BLOCK) {
6977 cond = RNODE_BLOCK(cond)->nd_head;
6978 }
6979
6980 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
6981 ADD_SEQ(ret, cond_seq);
6982
6983 if (then_label->refcnt && else_label->refcnt) {
6984 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
6985 }
6986
6987 if (then_label->refcnt) {
6988 ADD_LABEL(ret, then_label);
6989
6990 DECL_ANCHOR(then_seq);
6991 INIT_ANCHOR(then_seq);
6992 CHECK(COMPILE_(then_seq, "then", node_body, popped));
6993
6994 if (else_label->refcnt) {
6995 const NODE *const coverage_node = node_body ? node_body : node;
6996 add_trace_branch_coverage(
6997 iseq,
6998 ret,
6999 nd_code_loc(coverage_node),
7000 nd_node_id(coverage_node),
7001 0,
7002 type == NODE_IF ? "then" : "else",
7003 branches);
7004 end_label = NEW_LABEL(line);
7005 ADD_INSNL(then_seq, line_node, jump, end_label);
7006 if (!popped) {
7007 ADD_INSN(then_seq, line_node, pop);
7008 }
7009 }
7010 ADD_SEQ(ret, then_seq);
7011 }
7012
7013 if (else_label->refcnt) {
7014 ADD_LABEL(ret, else_label);
7015
7016 DECL_ANCHOR(else_seq);
7017 INIT_ANCHOR(else_seq);
7018 CHECK(COMPILE_(else_seq, "else", node_else, popped));
7019
7020 if (then_label->refcnt) {
7021 const NODE *const coverage_node = node_else ? node_else : node;
7022 add_trace_branch_coverage(
7023 iseq,
7024 ret,
7025 nd_code_loc(coverage_node),
7026 nd_node_id(coverage_node),
7027 1,
7028 type == NODE_IF ? "else" : "then",
7029 branches);
7030 }
7031 ADD_SEQ(ret, else_seq);
7032 }
7033
7034 if (end_label) {
7035 ADD_LABEL(ret, end_label);
7036 }
7037
7038 return COMPILE_OK;
7039}
7040
7041static int
7042compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7043{
7044 const NODE *vals;
7045 const NODE *node = orig_node;
7046 LABEL *endlabel, *elselabel;
7047 DECL_ANCHOR(head);
7048 DECL_ANCHOR(body_seq);
7049 DECL_ANCHOR(cond_seq);
7050 int only_special_literals = 1;
7051 VALUE literals = rb_hash_new();
7052 int line;
7053 enum node_type type;
7054 const NODE *line_node;
7055 VALUE branches = Qfalse;
7056 int branch_id = 0;
7057
7058 INIT_ANCHOR(head);
7059 INIT_ANCHOR(body_seq);
7060 INIT_ANCHOR(cond_seq);
7061
7062 RHASH_TBL_RAW(literals)->type = &cdhash_type;
7063
7064 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
7065
7066 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
7067
7068 node = RNODE_CASE(node)->nd_body;
7069 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
7070 type = nd_type(node);
7071 line = nd_line(node);
7072 line_node = node;
7073
7074 endlabel = NEW_LABEL(line);
7075 elselabel = NEW_LABEL(line);
7076
7077 ADD_SEQ(ret, head); /* case VAL */
7078
7079 while (type == NODE_WHEN) {
7080 LABEL *l1;
7081
7082 l1 = NEW_LABEL(line);
7083 ADD_LABEL(body_seq, l1);
7084 ADD_INSN(body_seq, line_node, pop);
7085
7086 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7087 add_trace_branch_coverage(
7088 iseq,
7089 body_seq,
7090 nd_code_loc(coverage_node),
7091 nd_node_id(coverage_node),
7092 branch_id++,
7093 "when",
7094 branches);
7095
7096 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
7097 ADD_INSNL(body_seq, line_node, jump, endlabel);
7098
7099 vals = RNODE_WHEN(node)->nd_head;
7100 if (vals) {
7101 switch (nd_type(vals)) {
7102 case NODE_LIST:
7103 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
7104 if (only_special_literals < 0) return COMPILE_NG;
7105 break;
7106 case NODE_SPLAT:
7107 case NODE_ARGSCAT:
7108 case NODE_ARGSPUSH:
7109 only_special_literals = 0;
7110 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
7111 break;
7112 default:
7113 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
7114 }
7115 }
7116 else {
7117 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
7118 }
7119
7120 node = RNODE_WHEN(node)->nd_next;
7121 if (!node) {
7122 break;
7123 }
7124 type = nd_type(node);
7125 line = nd_line(node);
7126 line_node = node;
7127 }
7128 /* else */
7129 if (node) {
7130 ADD_LABEL(cond_seq, elselabel);
7131 ADD_INSN(cond_seq, line_node, pop);
7132 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
7133 CHECK(COMPILE_(cond_seq, "else", node, popped));
7134 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7135 }
7136 else {
7137 debugs("== else (implicit)\n");
7138 ADD_LABEL(cond_seq, elselabel);
7139 ADD_INSN(cond_seq, orig_node, pop);
7140 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
7141 if (!popped) {
7142 ADD_INSN(cond_seq, orig_node, putnil);
7143 }
7144 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7145 }
7146
7147 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7148 ADD_INSN(ret, orig_node, dup);
7149 rb_obj_hide(literals);
7150 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
7151 RB_OBJ_WRITTEN(iseq, Qundef, literals);
7152 LABEL_REF(elselabel);
7153 }
7154
7155 ADD_SEQ(ret, cond_seq);
7156 ADD_SEQ(ret, body_seq);
7157 ADD_LABEL(ret, endlabel);
7158 return COMPILE_OK;
7159}
7160
7161static int
7162compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7163{
7164 const NODE *vals;
7165 const NODE *val;
7166 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
7167 LABEL *endlabel;
7168 DECL_ANCHOR(body_seq);
7169 VALUE branches = Qfalse;
7170 int branch_id = 0;
7171
7172 branches = decl_branch_base(iseq, PTR2NUM(orig_node), nd_code_loc(orig_node), "case");
7173
7174 INIT_ANCHOR(body_seq);
7175 endlabel = NEW_LABEL(nd_line(node));
7176
7177 while (node && nd_type_p(node, NODE_WHEN)) {
7178 const int line = nd_line(node);
7179 LABEL *l1 = NEW_LABEL(line);
7180 ADD_LABEL(body_seq, l1);
7181
7182 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7183 add_trace_branch_coverage(
7184 iseq,
7185 body_seq,
7186 nd_code_loc(coverage_node),
7187 nd_node_id(coverage_node),
7188 branch_id++,
7189 "when",
7190 branches);
7191
7192 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7193 ADD_INSNL(body_seq, node, jump, endlabel);
7194
7195 vals = RNODE_WHEN(node)->nd_head;
7196 if (!vals) {
7197 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7198 }
7199 switch (nd_type(vals)) {
7200 case NODE_LIST:
7201 while (vals) {
7202 LABEL *lnext;
7203 val = RNODE_LIST(vals)->nd_head;
7204 lnext = NEW_LABEL(nd_line(val));
7205 debug_compile("== when2\n", (void)0);
7206 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7207 ADD_LABEL(ret, lnext);
7208 vals = RNODE_LIST(vals)->nd_next;
7209 }
7210 break;
7211 case NODE_SPLAT:
7212 case NODE_ARGSCAT:
7213 case NODE_ARGSPUSH:
7214 ADD_INSN(ret, vals, putnil);
7215 CHECK(COMPILE(ret, "when2/cond splat", vals));
7216 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7217 ADD_INSNL(ret, vals, branchif, l1);
7218 break;
7219 default:
7220 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7221 }
7222 node = RNODE_WHEN(node)->nd_next;
7223 }
7224 /* else */
7225 const NODE *const coverage_node = node ? node : orig_node;
7226 add_trace_branch_coverage(
7227 iseq,
7228 ret,
7229 nd_code_loc(coverage_node),
7230 nd_node_id(coverage_node),
7231 branch_id,
7232 "else",
7233 branches);
7234 CHECK(COMPILE_(ret, "else", node, popped));
7235 ADD_INSNL(ret, orig_node, jump, endlabel);
7236
7237 ADD_SEQ(ret, body_seq);
7238 ADD_LABEL(ret, endlabel);
7239 return COMPILE_OK;
7240}
7241
7242static int iseq_compile_pattern_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *unmatched, bool in_single_pattern, bool in_alt_pattern, int base_index, bool use_deconstructed_cache);
7243
7244static int iseq_compile_pattern_constant(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *match_failed, bool in_single_pattern, int base_index);
7245static int iseq_compile_array_deconstruct(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *deconstruct, LABEL *deconstructed, LABEL *match_failed, LABEL *type_error, bool in_single_pattern, int base_index, bool use_deconstructed_cache);
7246static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7247static int iseq_compile_pattern_set_length_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, VALUE pattern_length, int base_index);
7248static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7249
7250#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7251#define CASE3_BI_OFFSET_ERROR_STRING 1
7252#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7253#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7254#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7255
7256static int
7257iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *matched, LABEL *unmatched, bool in_single_pattern, bool in_alt_pattern, int base_index, bool use_deconstructed_cache)
7258{
7259 const int line = nd_line(node);
7260 const NODE *line_node = node;
7261
7262 switch (nd_type(node)) {
7263 case NODE_ARYPTN: {
7264 /*
7265 * if pattern.use_rest_num?
7266 * rest_num = 0
7267 * end
7268 * if pattern.has_constant_node?
7269 * unless pattern.constant === obj
7270 * goto match_failed
7271 * end
7272 * end
7273 * unless obj.respond_to?(:deconstruct)
7274 * goto match_failed
7275 * end
7276 * d = obj.deconstruct
7277 * unless Array === d
7278 * goto type_error
7279 * end
7280 * min_argc = pattern.pre_args_num + pattern.post_args_num
7281 * if pattern.has_rest_arg?
7282 * unless d.length >= min_argc
7283 * goto match_failed
7284 * end
7285 * else
7286 * unless d.length == min_argc
7287 * goto match_failed
7288 * end
7289 * end
7290 * pattern.pre_args_num.each do |i|
7291 * unless pattern.pre_args[i].match?(d[i])
7292 * goto match_failed
7293 * end
7294 * end
7295 * if pattern.use_rest_num?
7296 * rest_num = d.length - min_argc
7297 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7298 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7299 * goto match_failed
7300 * end
7301 * end
7302 * end
7303 * pattern.post_args_num.each do |i|
7304 * j = pattern.pre_args_num + i
7305 * j += rest_num
7306 * unless pattern.post_args[i].match?(d[j])
7307 * goto match_failed
7308 * end
7309 * end
7310 * goto matched
7311 * type_error:
7312 * FrozenCore.raise TypeError
7313 * match_failed:
7314 * goto unmatched
7315 */
7316 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7317 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7318 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7319
7320 const int min_argc = pre_args_num + post_args_num;
7321 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7322 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7323
7324 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7325 int i;
7326 match_failed = NEW_LABEL(line);
7327 type_error = NEW_LABEL(line);
7328 deconstruct = NEW_LABEL(line);
7329 deconstructed = NEW_LABEL(line);
7330
7331 if (use_rest_num) {
7332 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7333 ADD_INSN(ret, line_node, swap);
7334 if (base_index) {
7335 base_index++;
7336 }
7337 }
7338
7339 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7340
7341 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7342
7343 ADD_INSN(ret, line_node, dup);
7344 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7345 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7346 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7347 if (in_single_pattern) {
7348 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7349 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7350 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7351 INT2FIX(min_argc), base_index + 1 /* (1) */));
7352 }
7353 ADD_INSNL(ret, line_node, branchunless, match_failed);
7354
7355 for (i = 0; i < pre_args_num; i++) {
7356 ADD_INSN(ret, line_node, dup);
7357 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7358 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7359 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(args)->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (2) */, false));
7360 args = RNODE_LIST(args)->nd_next;
7361 }
7362
7363 if (RNODE_ARYPTN(node)->rest_arg) {
7364 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7365 ADD_INSN(ret, line_node, dup);
7366 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7367 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7368 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7369 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7370 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7371 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
7372 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7373
7374 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_ARYPTN(node)->rest_arg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (3) */, false));
7375 }
7376 else {
7377 if (post_args_num > 0) {
7378 ADD_INSN(ret, line_node, dup);
7379 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7380 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7381 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7382 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7383 ADD_INSN(ret, line_node, pop);
7384 }
7385 }
7386 }
7387
7388 args = RNODE_ARYPTN(node)->post_args;
7389 for (i = 0; i < post_args_num; i++) {
7390 ADD_INSN(ret, line_node, dup);
7391
7392 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7393 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7394 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7395
7396 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7397 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(args)->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (4) */, false));
7398 args = RNODE_LIST(args)->nd_next;
7399 }
7400
7401 ADD_INSN(ret, line_node, pop);
7402 if (use_rest_num) {
7403 ADD_INSN(ret, line_node, pop);
7404 }
7405 ADD_INSNL(ret, line_node, jump, matched);
7406 ADD_INSN(ret, line_node, putnil);
7407 if (use_rest_num) {
7408 ADD_INSN(ret, line_node, putnil);
7409 }
7410
7411 ADD_LABEL(ret, type_error);
7412 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7413 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7414 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7415 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7416 ADD_INSN(ret, line_node, pop);
7417
7418 ADD_LABEL(ret, match_failed);
7419 ADD_INSN(ret, line_node, pop);
7420 if (use_rest_num) {
7421 ADD_INSN(ret, line_node, pop);
7422 }
7423 ADD_INSNL(ret, line_node, jump, unmatched);
7424
7425 break;
7426 }
7427 case NODE_FNDPTN: {
7428 /*
7429 * if pattern.has_constant_node?
7430 * unless pattern.constant === obj
7431 * goto match_failed
7432 * end
7433 * end
7434 * unless obj.respond_to?(:deconstruct)
7435 * goto match_failed
7436 * end
7437 * d = obj.deconstruct
7438 * unless Array === d
7439 * goto type_error
7440 * end
7441 * unless d.length >= pattern.args_num
7442 * goto match_failed
7443 * end
7444 *
7445 * begin
7446 * len = d.length
7447 * limit = d.length - pattern.args_num
7448 * i = 0
7449 * while i <= limit
7450 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7451 * if pattern.has_pre_rest_arg_id
7452 * unless pattern.pre_rest_arg.match?(d[0, i])
7453 * goto find_failed
7454 * end
7455 * end
7456 * if pattern.has_post_rest_arg_id
7457 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7458 * goto find_failed
7459 * end
7460 * end
7461 * goto find_succeeded
7462 * end
7463 * i+=1
7464 * end
7465 * find_failed:
7466 * goto match_failed
7467 * find_succeeded:
7468 * end
7469 *
7470 * goto matched
7471 * type_error:
7472 * FrozenCore.raise TypeError
7473 * match_failed:
7474 * goto unmatched
7475 */
7476 const NODE *args = RNODE_FNDPTN(node)->args;
7477 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7478
7479 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7480 match_failed = NEW_LABEL(line);
7481 type_error = NEW_LABEL(line);
7482 deconstruct = NEW_LABEL(line);
7483 deconstructed = NEW_LABEL(line);
7484
7485 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7486
7487 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7488
7489 ADD_INSN(ret, line_node, dup);
7490 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7491 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7492 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7493 if (in_single_pattern) {
7494 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node, rb_fstring_lit("%p length mismatch (given %p, expected %p+)"), INT2FIX(args_num), base_index + 1 /* (1) */));
7495 }
7496 ADD_INSNL(ret, line_node, branchunless, match_failed);
7497
7498 {
7499 LABEL *while_begin = NEW_LABEL(nd_line(node));
7500 LABEL *next_loop = NEW_LABEL(nd_line(node));
7501 LABEL *find_succeeded = NEW_LABEL(line);
7502 LABEL *find_failed = NEW_LABEL(nd_line(node));
7503 int j;
7504
7505 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7506 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7507
7508 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7509 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7510 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7511
7512 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7513
7514 ADD_LABEL(ret, while_begin);
7515
7516 ADD_INSN(ret, line_node, dup);
7517 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7518 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7519 ADD_INSNL(ret, line_node, branchunless, find_failed);
7520
7521 for (j = 0; j < args_num; j++) {
7522 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7523 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7524 if (j != 0) {
7525 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7526 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7527 }
7528 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7529
7530 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(args)->nd_head, next_loop, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3), (4), (5) */, false));
7531 args = RNODE_LIST(args)->nd_next;
7532 }
7533
7534 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7535 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7536 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7537 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7538 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7539 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_FNDPTN(node)->pre_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3), (4), (6) */, false));
7540 }
7541 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7542 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7543 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7544 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7545 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7546 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7547 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7548 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_FNDPTN(node)->post_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3),(4), (7) */, false));
7549 }
7550 ADD_INSNL(ret, line_node, jump, find_succeeded);
7551
7552 ADD_LABEL(ret, next_loop);
7553 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7554 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7555 ADD_INSNL(ret, line_node, jump, while_begin);
7556
7557 ADD_LABEL(ret, find_failed);
7558 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7559 if (in_single_pattern) {
7560 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7561 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7562 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7563 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7564 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7565
7566 ADD_INSN1(ret, line_node, putobject, Qfalse);
7567 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7568
7569 ADD_INSN(ret, line_node, pop);
7570 ADD_INSN(ret, line_node, pop);
7571 }
7572 ADD_INSNL(ret, line_node, jump, match_failed);
7573 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7574
7575 ADD_LABEL(ret, find_succeeded);
7576 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7577 }
7578
7579 ADD_INSN(ret, line_node, pop);
7580 ADD_INSNL(ret, line_node, jump, matched);
7581 ADD_INSN(ret, line_node, putnil);
7582
7583 ADD_LABEL(ret, type_error);
7584 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7585 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7586 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7587 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7588 ADD_INSN(ret, line_node, pop);
7589
7590 ADD_LABEL(ret, match_failed);
7591 ADD_INSN(ret, line_node, pop);
7592 ADD_INSNL(ret, line_node, jump, unmatched);
7593
7594 break;
7595 }
7596 case NODE_HSHPTN: {
7597 /*
7598 * keys = nil
7599 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7600 * keys = pattern.kw_args_node.keys
7601 * end
7602 * if pattern.has_constant_node?
7603 * unless pattern.constant === obj
7604 * goto match_failed
7605 * end
7606 * end
7607 * unless obj.respond_to?(:deconstruct_keys)
7608 * goto match_failed
7609 * end
7610 * d = obj.deconstruct_keys(keys)
7611 * unless Hash === d
7612 * goto type_error
7613 * end
7614 * if pattern.has_kw_rest_arg_node?
7615 * d = d.dup
7616 * end
7617 * if pattern.has_kw_args_node?
7618 * pattern.kw_args_node.each |k,|
7619 * unless d.key?(k)
7620 * goto match_failed
7621 * end
7622 * end
7623 * pattern.kw_args_node.each |k, pat|
7624 * if pattern.has_kw_rest_arg_node?
7625 * unless pat.match?(d.delete(k))
7626 * goto match_failed
7627 * end
7628 * else
7629 * unless pat.match?(d[k])
7630 * goto match_failed
7631 * end
7632 * end
7633 * end
7634 * else
7635 * unless d.empty?
7636 * goto match_failed
7637 * end
7638 * end
7639 * if pattern.has_kw_rest_arg_node?
7640 * if pattern.no_rest_keyword?
7641 * unless d.empty?
7642 * goto match_failed
7643 * end
7644 * else
7645 * unless pattern.kw_rest_arg_node.match?(d)
7646 * goto match_failed
7647 * end
7648 * end
7649 * end
7650 * goto matched
7651 * type_error:
7652 * FrozenCore.raise TypeError
7653 * match_failed:
7654 * goto unmatched
7655 */
7656 LABEL *match_failed, *type_error;
7657 VALUE keys = Qnil;
7658
7659 match_failed = NEW_LABEL(line);
7660 type_error = NEW_LABEL(line);
7661
7662 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7663 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7664 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7665 while (kw_args) {
7666 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7667 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7668 }
7669 }
7670
7671 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7672
7673 ADD_INSN(ret, line_node, dup);
7674 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7675 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7676 if (in_single_pattern) {
7677 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7678 }
7679 ADD_INSNL(ret, line_node, branchunless, match_failed);
7680
7681 if (NIL_P(keys)) {
7682 ADD_INSN(ret, line_node, putnil);
7683 }
7684 else {
7685 RB_OBJ_SET_FROZEN_SHAREABLE(keys);
7686 ADD_INSN1(ret, line_node, duparray, keys);
7687 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7688 }
7689 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7690
7691 ADD_INSN(ret, line_node, dup);
7692 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7693 ADD_INSNL(ret, line_node, branchunless, type_error);
7694
7695 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7696 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7697 }
7698
7699 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7700 int i;
7701 int keys_num;
7702 const NODE *args;
7703 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7704 if (args) {
7705 DECL_ANCHOR(match_values);
7706 INIT_ANCHOR(match_values);
7707 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7708 for (i = 0; i < keys_num; i++) {
7709 NODE *key_node = RNODE_LIST(args)->nd_head;
7710 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7711 VALUE key = get_symbol_value(iseq, key_node);
7712
7713 ADD_INSN(ret, line_node, dup);
7714 ADD_INSN1(ret, line_node, putobject, key);
7715 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7716 if (in_single_pattern) {
7717 LABEL *match_succeeded;
7718 match_succeeded = NEW_LABEL(line);
7719
7720 ADD_INSN(ret, line_node, dup);
7721 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7722
7723 VALUE str = rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key));
7724 ADD_INSN1(ret, line_node, putobject, RB_OBJ_SET_SHAREABLE(str)); // (4)
7725 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7726 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7727 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7728 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7729 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7730 ADD_INSN1(ret, line_node, putobject, key); // (7)
7731 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7732
7733 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7734
7735 ADD_LABEL(ret, match_succeeded);
7736 }
7737 ADD_INSNL(ret, line_node, branchunless, match_failed);
7738
7739 ADD_INSN(match_values, line_node, dup);
7740 ADD_INSN1(match_values, line_node, putobject, key);
7741 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7742 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7743 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7744 }
7745 ADD_SEQ(ret, match_values);
7746 }
7747 }
7748 else {
7749 ADD_INSN(ret, line_node, dup);
7750 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7751 if (in_single_pattern) {
7752 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7753 }
7754 ADD_INSNL(ret, line_node, branchunless, match_failed);
7755 }
7756
7757 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7758 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7759 ADD_INSN(ret, line_node, dup);
7760 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7761 if (in_single_pattern) {
7762 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7763 }
7764 ADD_INSNL(ret, line_node, branchunless, match_failed);
7765 }
7766 else {
7767 ADD_INSN(ret, line_node, dup); // (11)
7768 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_HSHPTN(node)->nd_pkwrestarg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (11) */, false));
7769 }
7770 }
7771
7772 ADD_INSN(ret, line_node, pop);
7773 ADD_INSNL(ret, line_node, jump, matched);
7774 ADD_INSN(ret, line_node, putnil);
7775
7776 ADD_LABEL(ret, type_error);
7777 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7778 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7779 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7780 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7781 ADD_INSN(ret, line_node, pop);
7782
7783 ADD_LABEL(ret, match_failed);
7784 ADD_INSN(ret, line_node, pop);
7785 ADD_INSNL(ret, line_node, jump, unmatched);
7786 break;
7787 }
7788 case NODE_SYM:
7789 case NODE_REGX:
7790 case NODE_LINE:
7791 case NODE_INTEGER:
7792 case NODE_FLOAT:
7793 case NODE_RATIONAL:
7794 case NODE_IMAGINARY:
7795 case NODE_FILE:
7796 case NODE_ENCODING:
7797 case NODE_STR:
7798 case NODE_XSTR:
7799 case NODE_DSTR:
7800 case NODE_DSYM:
7801 case NODE_DREGX:
7802 case NODE_LIST:
7803 case NODE_ZLIST:
7804 case NODE_LAMBDA:
7805 case NODE_DOT2:
7806 case NODE_DOT3:
7807 case NODE_CONST:
7808 case NODE_LVAR:
7809 case NODE_DVAR:
7810 case NODE_IVAR:
7811 case NODE_CVAR:
7812 case NODE_GVAR:
7813 case NODE_TRUE:
7814 case NODE_FALSE:
7815 case NODE_SELF:
7816 case NODE_NIL:
7817 case NODE_COLON2:
7818 case NODE_COLON3:
7819 case NODE_BEGIN:
7820 case NODE_BLOCK:
7821 case NODE_ONCE:
7822 CHECK(COMPILE(ret, "case in literal", node)); // (1)
7823 if (in_single_pattern) {
7824 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7825 }
7826 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
7827 if (in_single_pattern) {
7828 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
7829 }
7830 ADD_INSNL(ret, line_node, branchif, matched);
7831 ADD_INSNL(ret, line_node, jump, unmatched);
7832 break;
7833 case NODE_LASGN: {
7834 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
7835 ID id = RNODE_LASGN(node)->nd_vid;
7836 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
7837
7838 if (in_alt_pattern) {
7839 const char *name = rb_id2name(id);
7840 if (name && strlen(name) > 0 && name[0] != '_') {
7841 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7842 rb_id2str(id));
7843 return COMPILE_NG;
7844 }
7845 }
7846
7847 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7848 ADD_INSNL(ret, line_node, jump, matched);
7849 break;
7850 }
7851 case NODE_DASGN: {
7852 int idx, lv, ls;
7853 ID id = RNODE_DASGN(node)->nd_vid;
7854
7855 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7856
7857 if (in_alt_pattern) {
7858 const char *name = rb_id2name(id);
7859 if (name && strlen(name) > 0 && name[0] != '_') {
7860 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7861 rb_id2str(id));
7862 return COMPILE_NG;
7863 }
7864 }
7865
7866 if (idx < 0) {
7867 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
7868 rb_id2str(id));
7869 return COMPILE_NG;
7870 }
7871 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
7872 ADD_INSNL(ret, line_node, jump, matched);
7873 break;
7874 }
7875 case NODE_IF:
7876 case NODE_UNLESS: {
7877 LABEL *match_failed;
7878 match_failed = unmatched;
7879 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7880 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
7881 if (in_single_pattern) {
7882 LABEL *match_succeeded;
7883 match_succeeded = NEW_LABEL(line);
7884
7885 ADD_INSN(ret, line_node, dup);
7886 if (nd_type_p(node, NODE_IF)) {
7887 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7888 }
7889 else {
7890 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
7891 }
7892
7893 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
7894 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7895 ADD_INSN1(ret, line_node, putobject, Qfalse);
7896 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7897
7898 ADD_INSN(ret, line_node, pop);
7899 ADD_INSN(ret, line_node, pop);
7900
7901 ADD_LABEL(ret, match_succeeded);
7902 }
7903 if (nd_type_p(node, NODE_IF)) {
7904 ADD_INSNL(ret, line_node, branchunless, match_failed);
7905 }
7906 else {
7907 ADD_INSNL(ret, line_node, branchif, match_failed);
7908 }
7909 ADD_INSNL(ret, line_node, jump, matched);
7910 break;
7911 }
7912 case NODE_HASH: {
7913 NODE *n;
7914 LABEL *match_failed;
7915 match_failed = NEW_LABEL(line);
7916
7917 n = RNODE_HASH(node)->nd_head;
7918 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
7919 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7920 return COMPILE_NG;
7921 }
7922
7923 ADD_INSN(ret, line_node, dup); // (1)
7924 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(n)->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (1) */, use_deconstructed_cache));
7925 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head, matched, match_failed, in_single_pattern, in_alt_pattern, base_index, false));
7926 ADD_INSN(ret, line_node, putnil);
7927
7928 ADD_LABEL(ret, match_failed);
7929 ADD_INSN(ret, line_node, pop);
7930 ADD_INSNL(ret, line_node, jump, unmatched);
7931 break;
7932 }
7933 case NODE_OR: {
7934 LABEL *match_succeeded, *fin;
7935 match_succeeded = NEW_LABEL(line);
7936 fin = NEW_LABEL(line);
7937
7938 ADD_INSN(ret, line_node, dup); // (1)
7939 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_1st, match_succeeded, fin, in_single_pattern, true, base_index + 1 /* (1) */, use_deconstructed_cache));
7940 ADD_LABEL(ret, match_succeeded);
7941 ADD_INSN(ret, line_node, pop);
7942 ADD_INSNL(ret, line_node, jump, matched);
7943 ADD_INSN(ret, line_node, putnil);
7944 ADD_LABEL(ret, fin);
7945 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
7946 break;
7947 }
7948 default:
7949 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
7950 }
7951 return COMPILE_OK;
7952}
7953
7954static int
7955iseq_compile_pattern_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *unmatched, bool in_single_pattern, bool in_alt_pattern, int base_index, bool use_deconstructed_cache)
7956{
7957 LABEL *fin = NEW_LABEL(nd_line(node));
7958 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7959 ADD_LABEL(ret, fin);
7960 return COMPILE_OK;
7961}
7962
7963static int
7964iseq_compile_pattern_constant(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *match_failed, bool in_single_pattern, int base_index)
7965{
7966 const NODE *line_node = node;
7967
7968 if (RNODE_ARYPTN(node)->nd_pconst) {
7969 ADD_INSN(ret, line_node, dup); // (1)
7970 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
7971 if (in_single_pattern) {
7972 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7973 }
7974 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
7975 if (in_single_pattern) {
7976 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
7977 }
7978 ADD_INSNL(ret, line_node, branchunless, match_failed);
7979 }
7980 return COMPILE_OK;
7981}
7982
7983
7984static int
7985iseq_compile_array_deconstruct(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *deconstruct, LABEL *deconstructed, LABEL *match_failed, LABEL *type_error, bool in_single_pattern, int base_index, bool use_deconstructed_cache)
7986{
7987 const NODE *line_node = node;
7988
7989 // NOTE: this optimization allows us to re-use the #deconstruct value
7990 // (or its absence).
7991 if (use_deconstructed_cache) {
7992 // If value is nil then we haven't tried to deconstruct
7993 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7994 ADD_INSNL(ret, line_node, branchnil, deconstruct);
7995
7996 // If false then the value is not deconstructable
7997 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7998 ADD_INSNL(ret, line_node, branchunless, match_failed);
7999
8000 // Drop value, add deconstructed to the stack and jump
8001 ADD_INSN(ret, line_node, pop); // (1)
8002 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
8003 ADD_INSNL(ret, line_node, jump, deconstructed);
8004 }
8005 else {
8006 ADD_INSNL(ret, line_node, jump, deconstruct);
8007 }
8008
8009 ADD_LABEL(ret, deconstruct);
8010 ADD_INSN(ret, line_node, dup);
8011 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
8012 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
8013
8014 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
8015 if (use_deconstructed_cache) {
8016 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
8017 }
8018
8019 if (in_single_pattern) {
8020 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
8021 }
8022
8023 ADD_INSNL(ret, line_node, branchunless, match_failed);
8024
8025 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
8026
8027 // Cache the result (if it's cacheable - currently, only top-level array patterns)
8028 if (use_deconstructed_cache) {
8029 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8030 }
8031
8032 ADD_INSN(ret, line_node, dup);
8033 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
8034 ADD_INSNL(ret, line_node, branchunless, type_error);
8035
8036 ADD_LABEL(ret, deconstructed);
8037
8038 return COMPILE_OK;
8039}
8040
8041static int
8042iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
8043{
8044 /*
8045 * if match_succeeded?
8046 * goto match_succeeded
8047 * end
8048 * error_string = FrozenCore.sprintf(errmsg, matchee)
8049 * key_error_p = false
8050 * match_succeeded:
8051 */
8052 const int line = nd_line(node);
8053 const NODE *line_node = node;
8054 LABEL *match_succeeded = NEW_LABEL(line);
8055
8056 ADD_INSN(ret, line_node, dup);
8057 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8058
8059 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8060 ADD_INSN1(ret, line_node, putobject, errmsg);
8061 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8062 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
8063 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8064
8065 ADD_INSN1(ret, line_node, putobject, Qfalse);
8066 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8067
8068 ADD_INSN(ret, line_node, pop);
8069 ADD_INSN(ret, line_node, pop);
8070 ADD_LABEL(ret, match_succeeded);
8071
8072 return COMPILE_OK;
8073}
8074
8075static int
8076iseq_compile_pattern_set_length_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, VALUE pattern_length, int base_index)
8077{
8078 /*
8079 * if match_succeeded?
8080 * goto match_succeeded
8081 * end
8082 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
8083 * key_error_p = false
8084 * match_succeeded:
8085 */
8086 const int line = nd_line(node);
8087 const NODE *line_node = node;
8088 LABEL *match_succeeded = NEW_LABEL(line);
8089
8090 ADD_INSN(ret, line_node, dup);
8091 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8092
8093 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8094 ADD_INSN1(ret, line_node, putobject, errmsg);
8095 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8096 ADD_INSN(ret, line_node, dup);
8097 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
8098 ADD_INSN1(ret, line_node, putobject, pattern_length);
8099 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
8100 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8101
8102 ADD_INSN1(ret, line_node, putobject, Qfalse);
8103 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
8104
8105 ADD_INSN(ret, line_node, pop);
8106 ADD_INSN(ret, line_node, pop);
8107 ADD_LABEL(ret, match_succeeded);
8108
8109 return COMPILE_OK;
8110}
8111
8112static int
8113iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
8114{
8115 /*
8116 * if match_succeeded?
8117 * goto match_succeeded
8118 * end
8119 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
8120 * key_error_p = false
8121 * match_succeeded:
8122 */
8123 const int line = nd_line(node);
8124 const NODE *line_node = node;
8125 LABEL *match_succeeded = NEW_LABEL(line);
8126
8127 ADD_INSN(ret, line_node, dup);
8128 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8129
8130 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8131 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
8132 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8133 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
8134 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
8135 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8136
8137 ADD_INSN1(ret, line_node, putobject, Qfalse);
8138 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8139
8140 ADD_INSN(ret, line_node, pop);
8141 ADD_INSN(ret, line_node, pop);
8142
8143 ADD_LABEL(ret, match_succeeded);
8144 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
8145 ADD_INSN(ret, line_node, pop);
8146 ADD_INSN(ret, line_node, pop);
8147
8148 return COMPILE_OK;
8149}
8150
8151static int
8152compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
8153{
8154 const NODE *pattern;
8155 const NODE *node = orig_node;
8156 LABEL *endlabel, *elselabel;
8157 DECL_ANCHOR(head);
8158 DECL_ANCHOR(body_seq);
8159 DECL_ANCHOR(cond_seq);
8160 int line;
8161 enum node_type type;
8162 const NODE *line_node;
8163 VALUE branches = 0;
8164 int branch_id = 0;
8165 bool single_pattern;
8166
8167 INIT_ANCHOR(head);
8168 INIT_ANCHOR(body_seq);
8169 INIT_ANCHOR(cond_seq);
8170
8171 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
8172
8173 node = RNODE_CASE3(node)->nd_body;
8174 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
8175 type = nd_type(node);
8176 line = nd_line(node);
8177 line_node = node;
8178 single_pattern = !RNODE_IN(node)->nd_next;
8179
8180 endlabel = NEW_LABEL(line);
8181 elselabel = NEW_LABEL(line);
8182
8183 if (single_pattern) {
8184 /* allocate stack for ... */
8185 ADD_INSN(head, line_node, putnil); /* key_error_key */
8186 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
8187 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
8188 ADD_INSN(head, line_node, putnil); /* error_string */
8189 }
8190 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
8191
8192 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8193
8194 ADD_SEQ(ret, head); /* case VAL */
8195
8196 while (type == NODE_IN) {
8197 LABEL *l1;
8198
8199 if (branch_id) {
8200 ADD_INSN(body_seq, line_node, putnil);
8201 }
8202 l1 = NEW_LABEL(line);
8203 ADD_LABEL(body_seq, l1);
8204 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8205
8206 const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8207 add_trace_branch_coverage(
8208 iseq,
8209 body_seq,
8210 nd_code_loc(coverage_node),
8211 nd_node_id(coverage_node),
8212 branch_id++,
8213 "in",
8214 branches);
8215
8216 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8217 ADD_INSNL(body_seq, line_node, jump, endlabel);
8218
8219 pattern = RNODE_IN(node)->nd_head;
8220 if (pattern) {
8221 int pat_line = nd_line(pattern);
8222 LABEL *next_pat = NEW_LABEL(pat_line);
8223 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8224 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8225 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8226 ADD_LABEL(cond_seq, next_pat);
8227 LABEL_UNREMOVABLE(next_pat);
8228 }
8229 else {
8230 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8231 return COMPILE_NG;
8232 }
8233
8234 node = RNODE_IN(node)->nd_next;
8235 if (!node) {
8236 break;
8237 }
8238 type = nd_type(node);
8239 line = nd_line(node);
8240 line_node = node;
8241 }
8242 /* else */
8243 if (node) {
8244 ADD_LABEL(cond_seq, elselabel);
8245 ADD_INSN(cond_seq, line_node, pop);
8246 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8247 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8248 CHECK(COMPILE_(cond_seq, "else", node, popped));
8249 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8250 ADD_INSN(cond_seq, line_node, putnil);
8251 if (popped) {
8252 ADD_INSN(cond_seq, line_node, putnil);
8253 }
8254 }
8255 else {
8256 debugs("== else (implicit)\n");
8257 ADD_LABEL(cond_seq, elselabel);
8258 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8259 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8260
8261 if (single_pattern) {
8262 /*
8263 * if key_error_p
8264 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8265 * else
8266 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8267 * end
8268 */
8269 LABEL *key_error, *fin;
8270 struct rb_callinfo_kwarg *kw_arg;
8271
8272 key_error = NEW_LABEL(line);
8273 fin = NEW_LABEL(line);
8274
8275 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8276 kw_arg->references = 0;
8277 kw_arg->keyword_len = 2;
8278 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8279 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8280
8281 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8282 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8283 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8284 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8285 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8286 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8287 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8288 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8289 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8290 ADD_INSNL(cond_seq, orig_node, jump, fin);
8291
8292 ADD_LABEL(cond_seq, key_error);
8293 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8294 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8295 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8296 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8297 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8298 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8299 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8300 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8301 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8302 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8303
8304 ADD_LABEL(cond_seq, fin);
8305 }
8306 else {
8307 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8308 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8309 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8310 }
8311 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8312 if (!popped) {
8313 ADD_INSN(cond_seq, orig_node, putnil);
8314 }
8315 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8316 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8317 if (popped) {
8318 ADD_INSN(cond_seq, line_node, putnil);
8319 }
8320 }
8321
8322 ADD_SEQ(ret, cond_seq);
8323 ADD_SEQ(ret, body_seq);
8324 ADD_LABEL(ret, endlabel);
8325 return COMPILE_OK;
8326}
8327
8328#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8329#undef CASE3_BI_OFFSET_ERROR_STRING
8330#undef CASE3_BI_OFFSET_KEY_ERROR_P
8331#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8332#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8333
8334static int
8335compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8336{
8337 const int line = (int)nd_line(node);
8338 const NODE *line_node = node;
8339
8340 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8341 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8342 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8343 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8344 VALUE branches = Qfalse;
8345
8346 struct iseq_compile_data_ensure_node_stack enl;
8347
8348 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8349 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8350 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8351 LABEL *end_label = NEW_LABEL(line);
8352 LABEL *adjust_label = NEW_LABEL(line);
8353
8354 LABEL *next_catch_label = NEW_LABEL(line);
8355 LABEL *tmp_label = NULL;
8356
8357 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8358 push_ensure_entry(iseq, &enl, NULL, NULL);
8359
8360 if (RNODE_WHILE(node)->nd_state == 1) {
8361 ADD_INSNL(ret, line_node, jump, next_label);
8362 }
8363 else {
8364 tmp_label = NEW_LABEL(line);
8365 ADD_INSNL(ret, line_node, jump, tmp_label);
8366 }
8367 ADD_LABEL(ret, adjust_label);
8368 ADD_INSN(ret, line_node, putnil);
8369 ADD_LABEL(ret, next_catch_label);
8370 ADD_INSN(ret, line_node, pop);
8371 ADD_INSNL(ret, line_node, jump, next_label);
8372 if (tmp_label) ADD_LABEL(ret, tmp_label);
8373
8374 ADD_LABEL(ret, redo_label);
8375 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8376
8377 const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8378 add_trace_branch_coverage(
8379 iseq,
8380 ret,
8381 nd_code_loc(coverage_node),
8382 nd_node_id(coverage_node),
8383 0,
8384 "body",
8385 branches);
8386
8387 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8388 ADD_LABEL(ret, next_label); /* next */
8389
8390 if (type == NODE_WHILE) {
8391 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8392 redo_label, end_label));
8393 }
8394 else {
8395 /* until */
8396 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8397 end_label, redo_label));
8398 }
8399
8400 ADD_LABEL(ret, end_label);
8401 ADD_ADJUST_RESTORE(ret, adjust_label);
8402
8403 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8404 /* ADD_INSN(ret, line_node, putundef); */
8405 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8406 return COMPILE_NG;
8407 }
8408 else {
8409 ADD_INSN(ret, line_node, putnil);
8410 }
8411
8412 ADD_LABEL(ret, break_label); /* break */
8413
8414 if (popped) {
8415 ADD_INSN(ret, line_node, pop);
8416 }
8417
8418 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8419 break_label);
8420 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8421 next_catch_label);
8422 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8423 ISEQ_COMPILE_DATA(iseq)->redo_label);
8424
8425 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8426 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8427 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8428 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8429 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8430 return COMPILE_OK;
8431}
8432
8433static int
8434compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8435{
8436 const int line = nd_line(node);
8437 const NODE *line_node = node;
8438 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8439 LABEL *retry_label = NEW_LABEL(line);
8440 LABEL *retry_end_l = NEW_LABEL(line);
8441 const rb_iseq_t *child_iseq;
8442
8443 ADD_LABEL(ret, retry_label);
8444 if (nd_type_p(node, NODE_FOR)) {
8445 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8446
8447 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8448 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8449 ISEQ_TYPE_BLOCK, line);
8450 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8451 }
8452 else {
8453 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8454 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8455 ISEQ_TYPE_BLOCK, line);
8456 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8457 }
8458
8459 {
8460 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8461 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8462 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8463 //
8464 // Normally, "send" instruction is at the last.
8465 // However, qcall under branch coverage measurement adds some instructions after the "send".
8466 //
8467 // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8468 INSN *iobj;
8469 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8470 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8471 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8472 iobj = (INSN*) get_prev_insn(iobj);
8473 }
8474 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8475
8476 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8477 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8478 if (&iobj->link == LAST_ELEMENT(ret)) {
8479 ret->last = (LINK_ELEMENT*) retry_end_l;
8480 }
8481 }
8482
8483 if (popped) {
8484 ADD_INSN(ret, line_node, pop);
8485 }
8486
8487 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8488
8489 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8490 return COMPILE_OK;
8491}
8492
8493static int
8494compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8495{
8496 /* massign to var in "for"
8497 * (args.length == 1 && Array.try_convert(args[0])) || args
8498 */
8499 const NODE *line_node = node;
8500 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8501 LABEL *not_single = NEW_LABEL(nd_line(var));
8502 LABEL *not_ary = NEW_LABEL(nd_line(var));
8503 CHECK(COMPILE(ret, "for var", var));
8504 ADD_INSN(ret, line_node, dup);
8505 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8506 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8507 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8508 ADD_INSNL(ret, line_node, branchunless, not_single);
8509 ADD_INSN(ret, line_node, dup);
8510 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8511 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8512 ADD_INSN1(ret, line_node, putobject, rb_cArray);
8513 ADD_INSN(ret, line_node, swap);
8514 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8515 ADD_INSN(ret, line_node, dup);
8516 ADD_INSNL(ret, line_node, branchunless, not_ary);
8517 ADD_INSN(ret, line_node, swap);
8518 ADD_LABEL(ret, not_ary);
8519 ADD_INSN(ret, line_node, pop);
8520 ADD_LABEL(ret, not_single);
8521 return COMPILE_OK;
8522}
8523
8524static int
8525compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8526{
8527 const NODE *line_node = node;
8528 unsigned long throw_flag = 0;
8529
8530 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8531 /* while/until */
8532 LABEL *splabel = NEW_LABEL(0);
8533 ADD_LABEL(ret, splabel);
8534 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8535 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8536 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8537 add_ensure_iseq(ret, iseq, 0);
8538 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8539 ADD_ADJUST_RESTORE(ret, splabel);
8540
8541 if (!popped) {
8542 ADD_INSN(ret, line_node, putnil);
8543 }
8544 }
8545 else {
8546 const rb_iseq_t *ip = iseq;
8547
8548 while (ip) {
8549 if (!ISEQ_COMPILE_DATA(ip)) {
8550 ip = 0;
8551 break;
8552 }
8553
8554 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8555 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8556 }
8557 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8558 throw_flag = 0;
8559 }
8560 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8561 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8562 return COMPILE_NG;
8563 }
8564 else {
8565 ip = ISEQ_BODY(ip)->parent_iseq;
8566 continue;
8567 }
8568
8569 /* escape from block */
8570 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8571 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8572 if (popped) {
8573 ADD_INSN(ret, line_node, pop);
8574 }
8575 return COMPILE_OK;
8576 }
8577 COMPILE_ERROR(ERROR_ARGS "Invalid break");
8578 return COMPILE_NG;
8579 }
8580 return COMPILE_OK;
8581}
8582
8583static int
8584compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8585{
8586 const NODE *line_node = node;
8587 unsigned long throw_flag = 0;
8588
8589 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8590 LABEL *splabel = NEW_LABEL(0);
8591 debugs("next in while loop\n");
8592 ADD_LABEL(ret, splabel);
8593 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8594 add_ensure_iseq(ret, iseq, 0);
8595 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8596 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8597 ADD_ADJUST_RESTORE(ret, splabel);
8598 if (!popped) {
8599 ADD_INSN(ret, line_node, putnil);
8600 }
8601 }
8602 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8603 LABEL *splabel = NEW_LABEL(0);
8604 debugs("next in block\n");
8605 ADD_LABEL(ret, splabel);
8606 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8607 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8608 add_ensure_iseq(ret, iseq, 0);
8609 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8610 ADD_ADJUST_RESTORE(ret, splabel);
8611
8612 if (!popped) {
8613 ADD_INSN(ret, line_node, putnil);
8614 }
8615 }
8616 else {
8617 const rb_iseq_t *ip = iseq;
8618
8619 while (ip) {
8620 if (!ISEQ_COMPILE_DATA(ip)) {
8621 ip = 0;
8622 break;
8623 }
8624
8625 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8626 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8627 /* while loop */
8628 break;
8629 }
8630 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8631 break;
8632 }
8633 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8634 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8635 return COMPILE_NG;
8636 }
8637
8638 ip = ISEQ_BODY(ip)->parent_iseq;
8639 }
8640 if (ip != 0) {
8641 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8642 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8643
8644 if (popped) {
8645 ADD_INSN(ret, line_node, pop);
8646 }
8647 }
8648 else {
8649 COMPILE_ERROR(ERROR_ARGS "Invalid next");
8650 return COMPILE_NG;
8651 }
8652 }
8653 return COMPILE_OK;
8654}
8655
8656static int
8657compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8658{
8659 const NODE *line_node = node;
8660
8661 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8662 LABEL *splabel = NEW_LABEL(0);
8663 debugs("redo in while");
8664 ADD_LABEL(ret, splabel);
8665 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8666 add_ensure_iseq(ret, iseq, 0);
8667 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8668 ADD_ADJUST_RESTORE(ret, splabel);
8669 if (!popped) {
8670 ADD_INSN(ret, line_node, putnil);
8671 }
8672 }
8673 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8674 LABEL *splabel = NEW_LABEL(0);
8675
8676 debugs("redo in block");
8677 ADD_LABEL(ret, splabel);
8678 add_ensure_iseq(ret, iseq, 0);
8679 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8680 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8681 ADD_ADJUST_RESTORE(ret, splabel);
8682
8683 if (!popped) {
8684 ADD_INSN(ret, line_node, putnil);
8685 }
8686 }
8687 else {
8688 const rb_iseq_t *ip = iseq;
8689
8690 while (ip) {
8691 if (!ISEQ_COMPILE_DATA(ip)) {
8692 ip = 0;
8693 break;
8694 }
8695
8696 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8697 break;
8698 }
8699 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8700 break;
8701 }
8702 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8703 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8704 return COMPILE_NG;
8705 }
8706
8707 ip = ISEQ_BODY(ip)->parent_iseq;
8708 }
8709 if (ip != 0) {
8710 ADD_INSN(ret, line_node, putnil);
8711 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8712
8713 if (popped) {
8714 ADD_INSN(ret, line_node, pop);
8715 }
8716 }
8717 else {
8718 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8719 return COMPILE_NG;
8720 }
8721 }
8722 return COMPILE_OK;
8723}
8724
8725static int
8726compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8727{
8728 const NODE *line_node = node;
8729
8730 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8731 ADD_INSN(ret, line_node, putnil);
8732 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8733
8734 if (popped) {
8735 ADD_INSN(ret, line_node, pop);
8736 }
8737 }
8738 else {
8739 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8740 return COMPILE_NG;
8741 }
8742 return COMPILE_OK;
8743}
8744
8745static int
8746compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8747{
8748 const int line = nd_line(node);
8749 const NODE *line_node = node;
8750 LABEL *lstart = NEW_LABEL(line);
8751 LABEL *lend = NEW_LABEL(line);
8752 LABEL *lcont = NEW_LABEL(line);
8753 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8754 rb_str_concat(rb_str_new2("rescue in "),
8755 ISEQ_BODY(iseq)->location.label),
8756 ISEQ_TYPE_RESCUE, line);
8757
8758 lstart->rescued = LABEL_RESCUE_BEG;
8759 lend->rescued = LABEL_RESCUE_END;
8760 ADD_LABEL(ret, lstart);
8761
8762 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8763 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8764 {
8765 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8766 }
8767 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8768
8769 ADD_LABEL(ret, lend);
8770 if (RNODE_RESCUE(node)->nd_else) {
8771 ADD_INSN(ret, line_node, pop);
8772 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8773 }
8774 ADD_INSN(ret, line_node, nop);
8775 ADD_LABEL(ret, lcont);
8776
8777 if (popped) {
8778 ADD_INSN(ret, line_node, pop);
8779 }
8780
8781 /* register catch entry */
8782 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8783 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8784 return COMPILE_OK;
8785}
8786
8787static int
8788compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8789{
8790 const int line = nd_line(node);
8791 const NODE *line_node = node;
8792 const NODE *resq = node;
8793 const NODE *narg;
8794 LABEL *label_miss, *label_hit;
8795
8796 while (resq) {
8797 label_miss = NEW_LABEL(line);
8798 label_hit = NEW_LABEL(line);
8799
8800 narg = RNODE_RESBODY(resq)->nd_args;
8801 if (narg) {
8802 switch (nd_type(narg)) {
8803 case NODE_LIST:
8804 while (narg) {
8805 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8806 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8807 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8808 ADD_INSNL(ret, line_node, branchif, label_hit);
8809 narg = RNODE_LIST(narg)->nd_next;
8810 }
8811 break;
8812 case NODE_SPLAT:
8813 case NODE_ARGSCAT:
8814 case NODE_ARGSPUSH:
8815 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8816 CHECK(COMPILE(ret, "rescue/cond splat", narg));
8817 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8818 ADD_INSNL(ret, line_node, branchif, label_hit);
8819 break;
8820 default:
8821 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
8822 }
8823 }
8824 else {
8825 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8826 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
8827 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8828 ADD_INSNL(ret, line_node, branchif, label_hit);
8829 }
8830 ADD_INSNL(ret, line_node, jump, label_miss);
8831 ADD_LABEL(ret, label_hit);
8832 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
8833
8834 if (RNODE_RESBODY(resq)->nd_exc_var) {
8835 CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
8836 }
8837
8838 if (nd_type(RNODE_RESBODY(resq)->nd_body) == NODE_BEGIN && RNODE_BEGIN(RNODE_RESBODY(resq)->nd_body)->nd_body == NULL && !RNODE_RESBODY(resq)->nd_exc_var) {
8839 // empty body
8840 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
8841 }
8842 else {
8843 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
8844 }
8845
8846 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
8847 ADD_INSN(ret, line_node, nop);
8848 }
8849 ADD_INSN(ret, line_node, leave);
8850 ADD_LABEL(ret, label_miss);
8851 resq = RNODE_RESBODY(resq)->nd_next;
8852 }
8853 return COMPILE_OK;
8854}
8855
8856static int
8857compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8858{
8859 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
8860 const NODE *line_node = node;
8861 DECL_ANCHOR(ensr);
8862 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
8863 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
8864 ISEQ_TYPE_ENSURE, line);
8865 LABEL *lstart = NEW_LABEL(line);
8866 LABEL *lend = NEW_LABEL(line);
8867 LABEL *lcont = NEW_LABEL(line);
8868 LINK_ELEMENT *last;
8869 int last_leave = 0;
8870 struct ensure_range er;
8871 struct iseq_compile_data_ensure_node_stack enl;
8872 struct ensure_range *erange;
8873
8874 INIT_ANCHOR(ensr);
8875 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
8876 last = ensr->last;
8877 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
8878
8879 er.begin = lstart;
8880 er.end = lend;
8881 er.next = 0;
8882 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
8883
8884 ADD_LABEL(ret, lstart);
8885 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
8886 ADD_LABEL(ret, lend);
8887 ADD_SEQ(ret, ensr);
8888 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
8889 ADD_LABEL(ret, lcont);
8890 if (last_leave) ADD_INSN(ret, line_node, pop);
8891
8892 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
8893 if (lstart->link.next != &lend->link) {
8894 while (erange) {
8895 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
8896 ensure, lcont);
8897 erange = erange->next;
8898 }
8899 }
8900
8901 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
8902 return COMPILE_OK;
8903}
8904
8905static int
8906compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8907{
8908 const NODE *line_node = node;
8909
8910 if (iseq) {
8911 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
8912 const rb_iseq_t *is = iseq;
8913 enum rb_iseq_type t = type;
8914 const NODE *retval = RNODE_RETURN(node)->nd_stts;
8915 LABEL *splabel = 0;
8916
8917 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
8918 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
8919 t = ISEQ_BODY(is)->type;
8920 }
8921 switch (t) {
8922 case ISEQ_TYPE_TOP:
8923 case ISEQ_TYPE_MAIN:
8924 if (retval) {
8925 rb_warn("argument of top-level return is ignored");
8926 }
8927 if (is == iseq) {
8928 /* plain top-level, leave directly */
8929 type = ISEQ_TYPE_METHOD;
8930 }
8931 break;
8932 default:
8933 break;
8934 }
8935
8936 if (type == ISEQ_TYPE_METHOD) {
8937 splabel = NEW_LABEL(0);
8938 ADD_LABEL(ret, splabel);
8939 ADD_ADJUST(ret, line_node, 0);
8940 }
8941
8942 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
8943
8944 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
8945 add_ensure_iseq(ret, iseq, 1);
8946 ADD_TRACE(ret, RUBY_EVENT_RETURN);
8947 ADD_INSN(ret, line_node, leave);
8948 ADD_ADJUST_RESTORE(ret, splabel);
8949
8950 if (!popped) {
8951 ADD_INSN(ret, line_node, putnil);
8952 }
8953 }
8954 else {
8955 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
8956 if (popped) {
8957 ADD_INSN(ret, line_node, pop);
8958 }
8959 }
8960 }
8961 return COMPILE_OK;
8962}
8963
8964static bool
8965drop_unreachable_return(LINK_ANCHOR *ret)
8966{
8967 LINK_ELEMENT *i = ret->last, *last;
8968 if (!i) return false;
8969 if (IS_TRACE(i)) i = i->prev;
8970 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
8971 last = i = i->prev;
8972 if (IS_ADJUST(i)) i = i->prev;
8973 if (!IS_INSN(i)) return false;
8974 switch (INSN_OF(i)) {
8975 case BIN(leave):
8976 case BIN(jump):
8977 break;
8978 default:
8979 return false;
8980 }
8981 (ret->last = last->prev)->next = NULL;
8982 return true;
8983}
8984
8985static int
8986compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8987{
8988 CHECK(COMPILE_(ret, "nd_body", node, popped));
8989
8990 if (!popped && !all_string_result_p(node)) {
8991 const NODE *line_node = node;
8992 const unsigned int flag = VM_CALL_FCALL;
8993
8994 // Note, this dup could be removed if we are willing to change anytostring. It pops
8995 // two VALUEs off the stack when it could work by replacing the top most VALUE.
8996 ADD_INSN(ret, line_node, dup);
8997 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
8998 ADD_INSN(ret, line_node, anytostring);
8999 }
9000 return COMPILE_OK;
9001}
9002
9003static void
9004compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
9005{
9006 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
9007
9008 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
9009 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
9010}
9011
9012static LABEL *
9013qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
9014{
9015 LABEL *else_label = NEW_LABEL(nd_line(line_node));
9016 VALUE br = 0;
9017
9018 br = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "&.");
9019 *branches = br;
9020 ADD_INSN(recv, line_node, dup);
9021 ADD_INSNL(recv, line_node, branchnil, else_label);
9022 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
9023 return else_label;
9024}
9025
9026static void
9027qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
9028{
9029 LABEL *end_label;
9030 if (!else_label) return;
9031 end_label = NEW_LABEL(nd_line(line_node));
9032 ADD_INSNL(ret, line_node, jump, end_label);
9033 ADD_LABEL(ret, else_label);
9034 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
9035 ADD_LABEL(ret, end_label);
9036}
9037
9038static int
9039compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
9040{
9041 /* optimization shortcut
9042 * "literal".freeze -> opt_str_freeze("literal")
9043 */
9044 if (get_nd_recv(node) &&
9045 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
9046 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
9047 get_nd_args(node) == NULL &&
9048 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
9049 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
9050 VALUE str = get_string_value(get_nd_recv(node));
9051 if (get_node_call_nd_mid(node) == idUMinus) {
9052 ADD_INSN2(ret, line_node, opt_str_uminus, str,
9053 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
9054 }
9055 else {
9056 ADD_INSN2(ret, line_node, opt_str_freeze, str,
9057 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
9058 }
9059 RB_OBJ_WRITTEN(iseq, Qundef, str);
9060 if (popped) {
9061 ADD_INSN(ret, line_node, pop);
9062 }
9063 return TRUE;
9064 }
9065 return FALSE;
9066}
9067
9068static int
9069iseq_has_builtin_function_table(const rb_iseq_t *iseq)
9070{
9071 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
9072}
9073
9074static const struct rb_builtin_function *
9075iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
9076{
9077 int i;
9078 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
9079 for (i=0; table[i].index != -1; i++) {
9080 if (strcmp(table[i].name, name) == 0) {
9081 return &table[i];
9082 }
9083 }
9084 return NULL;
9085}
9086
9087static const char *
9088iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
9089{
9090 const char *name = rb_id2name(mid);
9091 static const char prefix[] = "__builtin_";
9092 const size_t prefix_len = sizeof(prefix) - 1;
9093
9094 switch (type) {
9095 case NODE_CALL:
9096 if (recv) {
9097 switch (nd_type(recv)) {
9098 case NODE_VCALL:
9099 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
9100 return name;
9101 }
9102 break;
9103 case NODE_CONST:
9104 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
9105 return name;
9106 }
9107 break;
9108 default: break;
9109 }
9110 }
9111 break;
9112 case NODE_VCALL:
9113 case NODE_FCALL:
9114 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
9115 return &name[prefix_len];
9116 }
9117 break;
9118 default: break;
9119 }
9120 return NULL;
9121}
9122
9123static int
9124delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
9125{
9126
9127 if (argc == 0) {
9128 *pstart_index = 0;
9129 return TRUE;
9130 }
9131 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
9132 unsigned int start=0;
9133
9134 // local_table: [p1, p2, p3, l1, l2, l3]
9135 // arguments: [p3, l1, l2] -> 2
9136 for (start = 0;
9137 argc + start <= ISEQ_BODY(iseq)->local_table_size;
9138 start++) {
9139 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
9140
9141 for (unsigned int i=start; i-start<argc; i++) {
9142 if (IS_INSN(elem) &&
9143 INSN_OF(elem) == BIN(getlocal)) {
9144 int local_index = FIX2INT(OPERAND_AT(elem, 0));
9145 int local_level = FIX2INT(OPERAND_AT(elem, 1));
9146
9147 if (local_level == 0) {
9148 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
9149 if (0) { // for debug
9150 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
9151 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
9152 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9153 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
9154 }
9155 if (i == index) {
9156 elem = elem->next;
9157 continue; /* for */
9158 }
9159 else {
9160 goto next;
9161 }
9162 }
9163 else {
9164 goto fail; // level != 0 is unsupported
9165 }
9166 }
9167 else {
9168 goto fail; // insn is not a getlocal
9169 }
9170 }
9171 goto success;
9172 next:;
9173 }
9174 fail:
9175 return FALSE;
9176 success:
9177 *pstart_index = start;
9178 return TRUE;
9179 }
9180 else {
9181 return FALSE;
9182 }
9183}
9184
9185// Compile Primitive.attr! :leaf, ...
9186static int
9187compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9188{
9189 VALUE symbol;
9190 VALUE string;
9191 if (!node) goto no_arg;
9192 while (node) {
9193 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9194 const NODE *next = RNODE_LIST(node)->nd_next;
9195
9196 node = RNODE_LIST(node)->nd_head;
9197 if (!node) goto no_arg;
9198 switch (nd_type(node)) {
9199 case NODE_SYM:
9200 symbol = rb_node_sym_string_val(node);
9201 break;
9202 default:
9203 goto bad_arg;
9204 }
9205
9206 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9207
9208 string = rb_sym2str(symbol);
9209 if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
9210 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9211 }
9212 else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) {
9213 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9214 }
9215 else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
9216 iseq_set_use_block(iseq);
9217 }
9218 else if (strcmp(RSTRING_PTR(string), "c_trace") == 0) {
9219 // Let the iseq act like a C method in backtraces
9220 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9221 }
9222 else {
9223 goto unknown_arg;
9224 }
9225 node = next;
9226 }
9227 return COMPILE_OK;
9228 no_arg:
9229 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9230 return COMPILE_NG;
9231 non_symbol_arg:
9232 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9233 return COMPILE_NG;
9234 unknown_arg:
9235 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
9236 return COMPILE_NG;
9237 bad_arg:
9238 UNKNOWN_NODE("attr!", node, COMPILE_NG);
9239}
9240
9241static int
9242compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9243{
9244 VALUE name;
9245
9246 if (!node) goto no_arg;
9247 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9248 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9249 node = RNODE_LIST(node)->nd_head;
9250 if (!node) goto no_arg;
9251 switch (nd_type(node)) {
9252 case NODE_SYM:
9253 name = rb_node_sym_string_val(node);
9254 break;
9255 default:
9256 goto bad_arg;
9257 }
9258 if (!SYMBOL_P(name)) goto non_symbol_arg;
9259 if (!popped) {
9260 compile_lvar(iseq, ret, line_node, SYM2ID(name));
9261 }
9262 return COMPILE_OK;
9263 no_arg:
9264 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9265 return COMPILE_NG;
9266 too_many_arg:
9267 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9268 return COMPILE_NG;
9269 non_symbol_arg:
9270 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9271 rb_builtin_class_name(name));
9272 return COMPILE_NG;
9273 bad_arg:
9274 UNKNOWN_NODE("arg!", node, COMPILE_NG);
9275}
9276
9277static NODE *
9278mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9279{
9280 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9281 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9282 return RNODE_IF(node)->nd_body;
9283 }
9284 else {
9285 rb_bug("mandatory_node: can't find mandatory node");
9286 }
9287}
9288
9289static int
9290compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9291{
9292 // arguments
9293 struct rb_args_info args = {
9294 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9295 };
9296 rb_node_args_t args_node;
9297 rb_node_init(RNODE(&args_node), NODE_ARGS);
9298 args_node.nd_ainfo = args;
9299
9300 // local table without non-mandatory parameters
9301 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9302 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9303
9304 VALUE idtmp = 0;
9305 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9306 tbl->size = table_size;
9307
9308 int i;
9309
9310 // lead parameters
9311 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9312 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9313 }
9314 // local variables
9315 for (; i<table_size; i++) {
9316 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9317 }
9318
9319 rb_node_scope_t scope_node;
9320 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9321 scope_node.nd_tbl = tbl;
9322 scope_node.nd_body = mandatory_node(iseq, node);
9323 scope_node.nd_parent = NULL;
9324 scope_node.nd_args = &args_node;
9325
9326 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9327
9328 const rb_iseq_t *mandatory_only_iseq =
9329 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9330 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9331 nd_line(line_node), NULL, 0,
9332 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9333 ISEQ_BODY(iseq)->variable.script_lines);
9334 RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
9335
9336 ALLOCV_END(idtmp);
9337 return COMPILE_OK;
9338}
9339
9340static int
9341compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9342 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9343{
9344 NODE *args_node = get_nd_args(node);
9345
9346 if (parent_block != NULL) {
9347 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9348 return COMPILE_NG;
9349 }
9350 else {
9351# define BUILTIN_INLINE_PREFIX "_bi"
9352 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9353 bool cconst = false;
9354 retry:;
9355 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9356
9357 if (bf == NULL) {
9358 if (strcmp("cstmt!", builtin_func) == 0 ||
9359 strcmp("cexpr!", builtin_func) == 0) {
9360 // ok
9361 }
9362 else if (strcmp("cconst!", builtin_func) == 0) {
9363 cconst = true;
9364 }
9365 else if (strcmp("cinit!", builtin_func) == 0) {
9366 // ignore
9367 return COMPILE_OK;
9368 }
9369 else if (strcmp("attr!", builtin_func) == 0) {
9370 return compile_builtin_attr(iseq, args_node);
9371 }
9372 else if (strcmp("arg!", builtin_func) == 0) {
9373 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9374 }
9375 else if (strcmp("mandatory_only?", builtin_func) == 0) {
9376 if (popped) {
9377 rb_bug("mandatory_only? should be in if condition");
9378 }
9379 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9380 rb_bug("mandatory_only? should be put on top");
9381 }
9382
9383 ADD_INSN1(ret, line_node, putobject, Qfalse);
9384 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9385 }
9386 else if (1) {
9387 rb_bug("can't find builtin function:%s", builtin_func);
9388 }
9389 else {
9390 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9391 return COMPILE_NG;
9392 }
9393
9394 int inline_index = nd_line(node);
9395 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9396 builtin_func = inline_func;
9397 args_node = NULL;
9398 goto retry;
9399 }
9400
9401 if (cconst) {
9402 typedef VALUE(*builtin_func0)(void *, VALUE);
9403 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9404 ADD_INSN1(ret, line_node, putobject, const_val);
9405 return COMPILE_OK;
9406 }
9407
9408 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9409
9410 unsigned int flag = 0;
9411 struct rb_callinfo_kwarg *keywords = NULL;
9412 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9413
9414 if (FIX2INT(argc) != bf->argc) {
9415 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9416 builtin_func, bf->argc, FIX2INT(argc));
9417 return COMPILE_NG;
9418 }
9419
9420 unsigned int start_index;
9421 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9422 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9423 }
9424 else {
9425 ADD_SEQ(ret, args);
9426 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9427 }
9428
9429 if (popped) ADD_INSN(ret, line_node, pop);
9430 return COMPILE_OK;
9431 }
9432}
9433
9434static int
9435compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const enum node_type type, const NODE *const line_node, int popped, bool assume_receiver)
9436{
9437 /* call: obj.method(...)
9438 * fcall: func(...)
9439 * vcall: func
9440 */
9441 DECL_ANCHOR(recv);
9442 DECL_ANCHOR(args);
9443 ID mid = get_node_call_nd_mid(node);
9444 VALUE argc;
9445 unsigned int flag = 0;
9446 struct rb_callinfo_kwarg *keywords = NULL;
9447 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9448 LABEL *else_label = NULL;
9449 VALUE branches = Qfalse;
9450
9451 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9452
9453 INIT_ANCHOR(recv);
9454 INIT_ANCHOR(args);
9455
9456#if OPT_SUPPORT_JOKE
9457 if (nd_type_p(node, NODE_VCALL)) {
9458 ID id_bitblt;
9459 ID id_answer;
9460
9461 CONST_ID(id_bitblt, "bitblt");
9462 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9463
9464 if (mid == id_bitblt) {
9465 ADD_INSN(ret, line_node, bitblt);
9466 return COMPILE_OK;
9467 }
9468 else if (mid == id_answer) {
9469 ADD_INSN(ret, line_node, answer);
9470 return COMPILE_OK;
9471 }
9472 }
9473 /* only joke */
9474 {
9475 ID goto_id;
9476 ID label_id;
9477
9478 CONST_ID(goto_id, "__goto__");
9479 CONST_ID(label_id, "__label__");
9480
9481 if (nd_type_p(node, NODE_FCALL) &&
9482 (mid == goto_id || mid == label_id)) {
9483 LABEL *label;
9484 st_data_t data;
9485 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9486 VALUE label_name;
9487
9488 if (!labels_table) {
9489 labels_table = st_init_numtable();
9490 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9491 }
9492 {
9493 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9494 return COMPILE_NG;
9495 }
9496
9497 if (mid == goto_id) {
9498 ADD_INSNL(ret, line_node, jump, label);
9499 }
9500 else {
9501 ADD_LABEL(ret, label);
9502 }
9503 return COMPILE_OK;
9504 }
9505 }
9506#endif
9507
9508 const char *builtin_func;
9509 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9510 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9511 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9512 }
9513
9514 /* receiver */
9515 if (!assume_receiver) {
9516 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9517 int idx, level;
9518
9519 if (mid == idCall &&
9520 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9521 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9522 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9523 }
9524 else if (private_recv_p(node)) {
9525 ADD_INSN(recv, node, putself);
9526 flag |= VM_CALL_FCALL;
9527 }
9528 else {
9529 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9530 }
9531
9532 if (type == NODE_QCALL) {
9533 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9534 }
9535 }
9536 else if (type == NODE_FCALL || type == NODE_VCALL) {
9537 ADD_CALL_RECEIVER(recv, line_node);
9538 }
9539 }
9540
9541 /* args */
9542 if (type != NODE_VCALL) {
9543 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9544 CHECK(!NIL_P(argc));
9545 }
9546 else {
9547 argc = INT2FIX(0);
9548 }
9549
9550 ADD_SEQ(ret, recv);
9551
9552 bool inline_new = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction &&
9553 mid == rb_intern("new") &&
9554 parent_block == NULL &&
9555 !(flag & VM_CALL_ARGS_BLOCKARG);
9556
9557 if (inline_new) {
9558 ADD_INSN(ret, node, putnil);
9559 ADD_INSN(ret, node, swap);
9560 }
9561
9562 ADD_SEQ(ret, args);
9563
9564 debugp_param("call args argc", argc);
9565 debugp_param("call method", ID2SYM(mid));
9566
9567 switch ((int)type) {
9568 case NODE_VCALL:
9569 flag |= VM_CALL_VCALL;
9570 /* VCALL is funcall, so fall through */
9571 case NODE_FCALL:
9572 flag |= VM_CALL_FCALL;
9573 }
9574
9575 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9576 ADD_INSN(ret, line_node, splatkw);
9577 }
9578
9579 LABEL *not_basic_new = NEW_LABEL(nd_line(node));
9580 LABEL *not_basic_new_finish = NEW_LABEL(nd_line(node));
9581
9582 if (inline_new) {
9583 // Jump unless the receiver uses the "basic" implementation of "new"
9584 VALUE ci;
9585 if (flag & VM_CALL_FORWARDING) {
9586 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc) + 1, flag, keywords, 0);
9587 }
9588 else {
9589 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc), flag, keywords, 0);
9590 }
9591 ADD_INSN2(ret, node, opt_new, ci, not_basic_new);
9592 LABEL_REF(not_basic_new);
9593
9594 // optimized path
9595 ADD_SEND_R(ret, line_node, rb_intern("initialize"), argc, parent_block, INT2FIX(flag | VM_CALL_FCALL), keywords);
9596 ADD_INSNL(ret, line_node, jump, not_basic_new_finish);
9597
9598 ADD_LABEL(ret, not_basic_new);
9599 // Fall back to normal send
9600 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9601 ADD_INSN(ret, line_node, swap);
9602
9603 ADD_LABEL(ret, not_basic_new_finish);
9604 ADD_INSN(ret, line_node, pop);
9605 }
9606 else {
9607 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9608 }
9609
9610 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9611 if (popped) {
9612 ADD_INSN(ret, line_node, pop);
9613 }
9614 return COMPILE_OK;
9615}
9616
9617static int
9618compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9619{
9620 const int line = nd_line(node);
9621 VALUE argc;
9622 unsigned int flag = 0;
9623 int asgnflag = 0;
9624 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9625
9626 /*
9627 * a[x] (op)= y
9628 *
9629 * nil # nil
9630 * eval a # nil a
9631 * eval x # nil a x
9632 * dupn 2 # nil a x a x
9633 * send :[] # nil a x a[x]
9634 * eval y # nil a x a[x] y
9635 * send op # nil a x ret
9636 * setn 3 # ret a x ret
9637 * send []= # ret ?
9638 * pop # ret
9639 */
9640
9641 /*
9642 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9643 * NODE_OP_ASGN nd_recv
9644 * nd_args->nd_head
9645 * nd_args->nd_body
9646 * nd_mid
9647 */
9648
9649 if (!popped) {
9650 ADD_INSN(ret, node, putnil);
9651 }
9652 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9653 CHECK(asgnflag != -1);
9654 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9655 case NODE_ZLIST:
9656 argc = INT2FIX(0);
9657 break;
9658 default:
9659 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9660 CHECK(!NIL_P(argc));
9661 }
9662 int dup_argn = FIX2INT(argc) + 1;
9663 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9664 flag |= asgnflag;
9665 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9666
9667 if (id == idOROP || id == idANDOP) {
9668 /* a[x] ||= y or a[x] &&= y
9669
9670 unless/if a[x]
9671 a[x]= y
9672 else
9673 nil
9674 end
9675 */
9676 LABEL *label = NEW_LABEL(line);
9677 LABEL *lfin = NEW_LABEL(line);
9678
9679 ADD_INSN(ret, node, dup);
9680 if (id == idOROP) {
9681 ADD_INSNL(ret, node, branchif, label);
9682 }
9683 else { /* idANDOP */
9684 ADD_INSNL(ret, node, branchunless, label);
9685 }
9686 ADD_INSN(ret, node, pop);
9687
9688 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9689 if (!popped) {
9690 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9691 }
9692 if (flag & VM_CALL_ARGS_SPLAT) {
9693 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9694 ADD_INSN(ret, node, swap);
9695 ADD_INSN1(ret, node, splatarray, Qtrue);
9696 ADD_INSN(ret, node, swap);
9697 flag |= VM_CALL_ARGS_SPLAT_MUT;
9698 }
9699 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9700 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9701 }
9702 else {
9703 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9704 }
9705 ADD_INSN(ret, node, pop);
9706 ADD_INSNL(ret, node, jump, lfin);
9707 ADD_LABEL(ret, label);
9708 if (!popped) {
9709 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9710 }
9711 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9712 ADD_LABEL(ret, lfin);
9713 }
9714 else {
9715 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9716 ADD_SEND(ret, node, id, INT2FIX(1));
9717 if (!popped) {
9718 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9719 }
9720 if (flag & VM_CALL_ARGS_SPLAT) {
9721 if (flag & VM_CALL_KW_SPLAT) {
9722 ADD_INSN1(ret, node, topn, INT2FIX(2));
9723 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9724 ADD_INSN1(ret, node, splatarray, Qtrue);
9725 flag |= VM_CALL_ARGS_SPLAT_MUT;
9726 }
9727 ADD_INSN(ret, node, swap);
9728 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9729 ADD_INSN1(ret, node, setn, INT2FIX(2));
9730 ADD_INSN(ret, node, pop);
9731 }
9732 else {
9733 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9734 ADD_INSN(ret, node, swap);
9735 ADD_INSN1(ret, node, splatarray, Qtrue);
9736 ADD_INSN(ret, node, swap);
9737 flag |= VM_CALL_ARGS_SPLAT_MUT;
9738 }
9739 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9740 }
9741 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9742 }
9743 else {
9744 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9745 }
9746 ADD_INSN(ret, node, pop);
9747 }
9748 return COMPILE_OK;
9749}
9750
9751static int
9752compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9753{
9754 const int line = nd_line(node);
9755 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9756 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9757 int asgnflag;
9758 LABEL *lfin = NEW_LABEL(line);
9759 LABEL *lcfin = NEW_LABEL(line);
9760 LABEL *lskip = 0;
9761 /*
9762 class C; attr_accessor :c; end
9763 r = C.new
9764 r.a &&= v # asgn2
9765
9766 eval r # r
9767 dup # r r
9768 eval r.a # r o
9769
9770 # or
9771 dup # r o o
9772 if lcfin # r o
9773 pop # r
9774 eval v # r v
9775 swap # v r
9776 topn 1 # v r v
9777 send a= # v ?
9778 jump lfin # v ?
9779
9780 lcfin: # r o
9781 swap # o r
9782
9783 lfin: # o ?
9784 pop # o
9785
9786 # or (popped)
9787 if lcfin # r
9788 eval v # r v
9789 send a= # ?
9790 jump lfin # ?
9791
9792 lcfin: # r
9793
9794 lfin: # ?
9795 pop #
9796
9797 # and
9798 dup # r o o
9799 unless lcfin
9800 pop # r
9801 eval v # r v
9802 swap # v r
9803 topn 1 # v r v
9804 send a= # v ?
9805 jump lfin # v ?
9806
9807 # others
9808 eval v # r o v
9809 send ?? # r w
9810 send a= # w
9811
9812 */
9813
9814 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9815 CHECK(asgnflag != -1);
9816 if (RNODE_OP_ASGN2(node)->nd_aid) {
9817 lskip = NEW_LABEL(line);
9818 ADD_INSN(ret, node, dup);
9819 ADD_INSNL(ret, node, branchnil, lskip);
9820 }
9821 ADD_INSN(ret, node, dup);
9822 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
9823
9824 if (atype == idOROP || atype == idANDOP) {
9825 if (!popped) {
9826 ADD_INSN(ret, node, dup);
9827 }
9828 if (atype == idOROP) {
9829 ADD_INSNL(ret, node, branchif, lcfin);
9830 }
9831 else { /* idANDOP */
9832 ADD_INSNL(ret, node, branchunless, lcfin);
9833 }
9834 if (!popped) {
9835 ADD_INSN(ret, node, pop);
9836 }
9837 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9838 if (!popped) {
9839 ADD_INSN(ret, node, swap);
9840 ADD_INSN1(ret, node, topn, INT2FIX(1));
9841 }
9842 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9843 ADD_INSNL(ret, node, jump, lfin);
9844
9845 ADD_LABEL(ret, lcfin);
9846 if (!popped) {
9847 ADD_INSN(ret, node, swap);
9848 }
9849
9850 ADD_LABEL(ret, lfin);
9851 }
9852 else {
9853 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9854 ADD_SEND(ret, node, atype, INT2FIX(1));
9855 if (!popped) {
9856 ADD_INSN(ret, node, swap);
9857 ADD_INSN1(ret, node, topn, INT2FIX(1));
9858 }
9859 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9860 }
9861 if (lskip && popped) {
9862 ADD_LABEL(ret, lskip);
9863 }
9864 ADD_INSN(ret, node, pop);
9865 if (lskip && !popped) {
9866 ADD_LABEL(ret, lskip);
9867 }
9868 return COMPILE_OK;
9869}
9870
9871static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
9872
9873static int
9874compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9875{
9876 const int line = nd_line(node);
9877 LABEL *lfin = 0;
9878 LABEL *lassign = 0;
9879 ID mid;
9880
9881 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
9882 case NODE_COLON3:
9883 ADD_INSN1(ret, node, putobject, rb_cObject);
9884 break;
9885 case NODE_COLON2:
9886 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
9887 break;
9888 default:
9889 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
9890 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
9891 return COMPILE_NG;
9892 }
9893 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
9894 /* cref */
9895 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
9896 lassign = NEW_LABEL(line);
9897 ADD_INSN(ret, node, dup); /* cref cref */
9898 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
9899 ID2SYM(mid), Qtrue); /* cref bool */
9900 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
9901 }
9902 ADD_INSN(ret, node, dup); /* cref cref */
9903 ADD_INSN1(ret, node, putobject, Qtrue);
9904 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
9905
9906 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
9907 lfin = NEW_LABEL(line);
9908 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
9909 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
9910 ADD_INSNL(ret, node, branchif, lfin);
9911 else /* idANDOP */
9912 ADD_INSNL(ret, node, branchunless, lfin);
9913 /* cref [obj] */
9914 if (!popped) ADD_INSN(ret, node, pop); /* cref */
9915 if (lassign) ADD_LABEL(ret, lassign);
9916 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9917 /* cref value */
9918 if (popped)
9919 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
9920 else {
9921 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
9922 ADD_INSN(ret, node, swap); /* cref value value cref */
9923 }
9924 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
9925 ADD_LABEL(ret, lfin); /* cref [value] */
9926 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
9927 ADD_INSN(ret, node, pop); /* [value] */
9928 }
9929 else {
9930 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9931 /* cref obj value */
9932 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
9933 /* cref value */
9934 ADD_INSN(ret, node, swap); /* value cref */
9935 if (!popped) {
9936 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
9937 ADD_INSN(ret, node, swap); /* value value cref */
9938 }
9939 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
9940 }
9941 return COMPILE_OK;
9942}
9943
9944static int
9945compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9946{
9947 const int line = nd_line(node);
9948 LABEL *lfin = NEW_LABEL(line);
9949 LABEL *lassign;
9950
9951 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
9952 LABEL *lfinish[2];
9953 lfinish[0] = lfin;
9954 lfinish[1] = 0;
9955 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
9956 lassign = lfinish[1];
9957 if (!lassign) {
9958 lassign = NEW_LABEL(line);
9959 }
9960 ADD_INSNL(ret, node, branchunless, lassign);
9961 }
9962 else {
9963 lassign = NEW_LABEL(line);
9964 }
9965
9966 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
9967
9968 if (!popped) {
9969 ADD_INSN(ret, node, dup);
9970 }
9971
9972 if (type == NODE_OP_ASGN_AND) {
9973 ADD_INSNL(ret, node, branchunless, lfin);
9974 }
9975 else {
9976 ADD_INSNL(ret, node, branchif, lfin);
9977 }
9978
9979 if (!popped) {
9980 ADD_INSN(ret, node, pop);
9981 }
9982
9983 ADD_LABEL(ret, lassign);
9984 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
9985 ADD_LABEL(ret, lfin);
9986 return COMPILE_OK;
9987}
9988
9989static int
9990compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9991{
9992 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9993 DECL_ANCHOR(args);
9994 int argc;
9995 unsigned int flag = 0;
9996 struct rb_callinfo_kwarg *keywords = NULL;
9997 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9998 int use_block = 1;
9999
10000 INIT_ANCHOR(args);
10001 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
10002
10003 if (type == NODE_SUPER) {
10004 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
10005 CHECK(!NIL_P(vargc));
10006 argc = FIX2INT(vargc);
10007 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
10008 ADD_INSN(args, node, splatkw);
10009 }
10010
10011 if (flag & VM_CALL_ARGS_BLOCKARG) {
10012 use_block = 0;
10013 }
10014 }
10015 else {
10016 /* NODE_ZSUPER */
10017 int i;
10018 const rb_iseq_t *liseq = body->local_iseq;
10019 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
10020 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
10021 int lvar_level = get_lvar_level(iseq);
10022
10023 argc = local_body->param.lead_num;
10024
10025 /* normal arguments */
10026 for (i = 0; i < local_body->param.lead_num; i++) {
10027 int idx = local_body->local_table_size - i;
10028 ADD_GETLOCAL(args, node, idx, lvar_level);
10029 }
10030
10031 /* forward ... */
10032 if (local_body->param.flags.forwardable) {
10033 flag |= VM_CALL_FORWARDING;
10034 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
10035 ADD_GETLOCAL(args, node, idx, lvar_level);
10036 }
10037
10038 if (local_body->param.flags.has_opt) {
10039 /* optional arguments */
10040 int j;
10041 for (j = 0; j < local_body->param.opt_num; j++) {
10042 int idx = local_body->local_table_size - (i + j);
10043 ADD_GETLOCAL(args, node, idx, lvar_level);
10044 }
10045 i += j;
10046 argc = i;
10047 }
10048 if (local_body->param.flags.has_rest) {
10049 /* rest argument */
10050 int idx = local_body->local_table_size - local_body->param.rest_start;
10051 ADD_GETLOCAL(args, node, idx, lvar_level);
10052 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
10053
10054 argc = local_body->param.rest_start + 1;
10055 flag |= VM_CALL_ARGS_SPLAT;
10056 }
10057 if (local_body->param.flags.has_post) {
10058 /* post arguments */
10059 int post_len = local_body->param.post_num;
10060 int post_start = local_body->param.post_start;
10061
10062 if (local_body->param.flags.has_rest) {
10063 int j;
10064 for (j=0; j<post_len; j++) {
10065 int idx = local_body->local_table_size - (post_start + j);
10066 ADD_GETLOCAL(args, node, idx, lvar_level);
10067 }
10068 ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
10069 flag |= VM_CALL_ARGS_SPLAT_MUT;
10070 /* argc is settled at above */
10071 }
10072 else {
10073 int j;
10074 for (j=0; j<post_len; j++) {
10075 int idx = local_body->local_table_size - (post_start + j);
10076 ADD_GETLOCAL(args, node, idx, lvar_level);
10077 }
10078 argc = post_len + post_start;
10079 }
10080 }
10081
10082 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
10083 int local_size = local_body->local_table_size;
10084 argc++;
10085
10086 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10087
10088 if (local_body->param.flags.has_kwrest) {
10089 int idx = local_body->local_table_size - local_kwd->rest_start;
10090 ADD_GETLOCAL(args, node, idx, lvar_level);
10091 RUBY_ASSERT(local_kwd->num > 0);
10092 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
10093 }
10094 else {
10095 ADD_INSN1(args, node, newhash, INT2FIX(0));
10096 }
10097 for (i = 0; i < local_kwd->num; ++i) {
10098 ID id = local_kwd->table[i];
10099 int idx = local_size - get_local_var_idx(liseq, id);
10100 ADD_INSN1(args, node, putobject, ID2SYM(id));
10101 ADD_GETLOCAL(args, node, idx, lvar_level);
10102 }
10103 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
10104 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
10105 }
10106 else if (local_body->param.flags.has_kwrest) {
10107 int idx = local_body->local_table_size - local_kwd->rest_start;
10108 ADD_GETLOCAL(args, node, idx, lvar_level);
10109 argc++;
10110 flag |= VM_CALL_KW_SPLAT;
10111 }
10112 }
10113
10114 if (use_block && parent_block == NULL) {
10115 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10116 }
10117
10118 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
10119 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
10120 ADD_INSN(ret, node, putself);
10121 ADD_SEQ(ret, args);
10122
10123 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
10124
10125 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
10126 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
10127 }
10128 else {
10129 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
10130 }
10131
10132 if (popped) {
10133 ADD_INSN(ret, node, pop);
10134 }
10135 return COMPILE_OK;
10136}
10137
10138static int
10139compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10140{
10141 DECL_ANCHOR(args);
10142 VALUE argc;
10143 unsigned int flag = 0;
10144 struct rb_callinfo_kwarg *keywords = NULL;
10145
10146 INIT_ANCHOR(args);
10147
10148 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
10149 case ISEQ_TYPE_TOP:
10150 case ISEQ_TYPE_MAIN:
10151 case ISEQ_TYPE_CLASS:
10152 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
10153 return COMPILE_NG;
10154 default: /* valid */;
10155 }
10156
10157 if (RNODE_YIELD(node)->nd_head) {
10158 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
10159 CHECK(!NIL_P(argc));
10160 }
10161 else {
10162 argc = INT2FIX(0);
10163 }
10164
10165 ADD_SEQ(ret, args);
10166 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
10167 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10168
10169 if (popped) {
10170 ADD_INSN(ret, node, pop);
10171 }
10172
10173 int level = 0;
10174 const rb_iseq_t *tmp_iseq = iseq;
10175 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
10176 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
10177 }
10178 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
10179
10180 return COMPILE_OK;
10181}
10182
10183static int
10184compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10185{
10186 DECL_ANCHOR(recv);
10187 DECL_ANCHOR(val);
10188
10189 INIT_ANCHOR(recv);
10190 INIT_ANCHOR(val);
10191 switch ((int)type) {
10192 case NODE_MATCH:
10193 {
10194 VALUE re = rb_node_regx_string_val(node);
10195 RB_OBJ_SET_FROZEN_SHAREABLE(re);
10196 ADD_INSN1(recv, node, putobject, re);
10197 ADD_INSN2(val, node, getspecial, INT2FIX(0),
10198 INT2FIX(0));
10199 }
10200 break;
10201 case NODE_MATCH2:
10202 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
10203 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
10204 break;
10205 case NODE_MATCH3:
10206 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
10207 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
10208 break;
10209 }
10210
10211 ADD_SEQ(ret, recv);
10212 ADD_SEQ(ret, val);
10213 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
10214
10215 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10216 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10217 }
10218
10219 if (popped) {
10220 ADD_INSN(ret, node, pop);
10221 }
10222 return COMPILE_OK;
10223}
10224
10225static int
10226compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10227{
10228 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10229 /* constant */
10230 VALUE segments;
10231 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10232 (segments = collect_const_segments(iseq, node))) {
10233 ISEQ_BODY(iseq)->ic_size++;
10234 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10235 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10236 }
10237 else {
10238 /* constant */
10239 DECL_ANCHOR(pref);
10240 DECL_ANCHOR(body);
10241
10242 INIT_ANCHOR(pref);
10243 INIT_ANCHOR(body);
10244 CHECK(compile_const_prefix(iseq, node, pref, body));
10245 if (LIST_INSN_SIZE_ZERO(pref)) {
10246 ADD_INSN(ret, node, putnil);
10247 ADD_SEQ(ret, body);
10248 }
10249 else {
10250 ADD_SEQ(ret, pref);
10251 ADD_SEQ(ret, body);
10252 }
10253 }
10254 }
10255 else {
10256 /* function call */
10257 ADD_CALL_RECEIVER(ret, node);
10258 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10259 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10260 }
10261 if (popped) {
10262 ADD_INSN(ret, node, pop);
10263 }
10264 return COMPILE_OK;
10265}
10266
10267static int
10268compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10269{
10270 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10271
10272 /* add cache insn */
10273 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10274 ISEQ_BODY(iseq)->ic_size++;
10275 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10276 RB_OBJ_SET_FROZEN_SHAREABLE(segments);
10277 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10278 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10279 }
10280 else {
10281 ADD_INSN1(ret, node, putobject, rb_cObject);
10282 ADD_INSN1(ret, node, putobject, Qtrue);
10283 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10284 }
10285
10286 if (popped) {
10287 ADD_INSN(ret, node, pop);
10288 }
10289 return COMPILE_OK;
10290}
10291
10292static int
10293compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10294{
10295 VALUE flag = INT2FIX(excl);
10296 const NODE *b = RNODE_DOT2(node)->nd_beg;
10297 const NODE *e = RNODE_DOT2(node)->nd_end;
10298
10299 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10300 if (!popped) {
10301 VALUE bv = optimized_range_item(b);
10302 VALUE ev = optimized_range_item(e);
10303 VALUE val = rb_range_new(bv, ev, excl);
10304 rb_ractor_make_shareable(rb_obj_freeze(val));
10305 ADD_INSN1(ret, node, putobject, val);
10306 RB_OBJ_WRITTEN(iseq, Qundef, val);
10307 }
10308 }
10309 else {
10310 CHECK(COMPILE_(ret, "min", b, popped));
10311 CHECK(COMPILE_(ret, "max", e, popped));
10312 if (!popped) {
10313 ADD_INSN1(ret, node, newrange, flag);
10314 }
10315 }
10316 return COMPILE_OK;
10317}
10318
10319static int
10320compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10321{
10322 if (!popped) {
10323 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10324 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10325 }
10326 else {
10327 const rb_iseq_t *ip = iseq;
10328 int level = 0;
10329 while (ip) {
10330 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10331 break;
10332 }
10333 ip = ISEQ_BODY(ip)->parent_iseq;
10334 level++;
10335 }
10336 if (ip) {
10337 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10338 }
10339 else {
10340 ADD_INSN(ret, node, putnil);
10341 }
10342 }
10343 }
10344 return COMPILE_OK;
10345}
10346
10347static int
10348compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10349{
10350 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10351 LABEL *end_label = NEW_LABEL(nd_line(node));
10352 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10353
10354 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10355 /* required argument. do nothing */
10356 COMPILE_ERROR(ERROR_ARGS "unreachable");
10357 return COMPILE_NG;
10358 }
10359 else if (nd_type_p(default_value, NODE_SYM) ||
10360 nd_type_p(default_value, NODE_REGX) ||
10361 nd_type_p(default_value, NODE_LINE) ||
10362 nd_type_p(default_value, NODE_INTEGER) ||
10363 nd_type_p(default_value, NODE_FLOAT) ||
10364 nd_type_p(default_value, NODE_RATIONAL) ||
10365 nd_type_p(default_value, NODE_IMAGINARY) ||
10366 nd_type_p(default_value, NODE_NIL) ||
10367 nd_type_p(default_value, NODE_TRUE) ||
10368 nd_type_p(default_value, NODE_FALSE)) {
10369 COMPILE_ERROR(ERROR_ARGS "unreachable");
10370 return COMPILE_NG;
10371 }
10372 else {
10373 /* if keywordcheck(_kw_bits, nth_keyword)
10374 * kw = default_value
10375 * end
10376 */
10377 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10378 int keyword_idx = body->param.keyword->num;
10379
10380 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10381 ADD_INSNL(ret, node, branchif, end_label);
10382 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10383 ADD_LABEL(ret, end_label);
10384 }
10385 return COMPILE_OK;
10386}
10387
10388static int
10389compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10390{
10391 DECL_ANCHOR(recv);
10392 DECL_ANCHOR(args);
10393 unsigned int flag = 0;
10394 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10395 VALUE argc;
10396 LABEL *else_label = NULL;
10397 VALUE branches = Qfalse;
10398
10399 INIT_ANCHOR(recv);
10400 INIT_ANCHOR(args);
10401 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10402 CHECK(!NIL_P(argc));
10403
10404 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10405 CHECK(asgnflag != -1);
10406 flag |= (unsigned int)asgnflag;
10407
10408 debugp_param("argc", argc);
10409 debugp_param("nd_mid", ID2SYM(mid));
10410
10411 if (!rb_is_attrset_id(mid)) {
10412 /* safe nav attr */
10413 mid = rb_id_attrset(mid);
10414 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10415 }
10416 if (!popped) {
10417 ADD_INSN(ret, node, putnil);
10418 ADD_SEQ(ret, recv);
10419 ADD_SEQ(ret, args);
10420
10421 if (flag & VM_CALL_ARGS_SPLAT) {
10422 ADD_INSN(ret, node, dup);
10423 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10424 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10425 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10426 ADD_INSN (ret, node, pop);
10427 }
10428 else {
10429 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10430 }
10431 }
10432 else {
10433 ADD_SEQ(ret, recv);
10434 ADD_SEQ(ret, args);
10435 }
10436 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10437 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10438 ADD_INSN(ret, node, pop);
10439 return COMPILE_OK;
10440}
10441
10442static int
10443compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10444{
10445 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10446 ADD_SEQ(ret, sub);
10447
10448 if (copy) {
10449 /*
10450 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10451 * NEW_LIST(value, loc), loc);
10452 */
10453 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10454 }
10455 else {
10456 /*
10457 * NEW_CALL(fcore, rb_intern("make_shareable"),
10458 * NEW_LIST(value, loc), loc);
10459 */
10460 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10461 }
10462
10463 return COMPILE_OK;
10464}
10465
10466static VALUE
10467node_const_decl_val(const NODE *node)
10468{
10469 VALUE path;
10470 switch (nd_type(node)) {
10471 case NODE_CDECL:
10472 if (RNODE_CDECL(node)->nd_vid) {
10473 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10474 goto end;
10475 }
10476 else {
10477 node = RNODE_CDECL(node)->nd_else;
10478 }
10479 break;
10480 case NODE_COLON2:
10481 break;
10482 case NODE_COLON3:
10483 // ::Const
10484 path = rb_str_new_cstr("::");
10485 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10486 goto end;
10487 default:
10488 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10489 UNREACHABLE_RETURN(0);
10490 }
10491
10492 path = rb_ary_new();
10493 if (node) {
10494 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10495 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10496 }
10497 if (node && nd_type_p(node, NODE_CONST)) {
10498 // Const::Name
10499 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10500 }
10501 else if (node && nd_type_p(node, NODE_COLON3)) {
10502 // ::Const::Name
10503 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10504 rb_ary_push(path, rb_str_new(0, 0));
10505 }
10506 else {
10507 // expression::Name
10508 rb_ary_push(path, rb_str_new_cstr("..."));
10509 }
10510 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10511 }
10512 end:
10513 path = rb_fstring(path);
10514 return path;
10515}
10516
10517static VALUE
10518const_decl_path(NODE *dest)
10519{
10520 VALUE path = Qnil;
10521 if (!nd_type_p(dest, NODE_CALL)) {
10522 path = node_const_decl_val(dest);
10523 }
10524 return path;
10525}
10526
10527static int
10528compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10529{
10530 /*
10531 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10532 */
10533 VALUE path = const_decl_path(dest);
10534 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10535 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10536 ADD_INSN1(ret, value, putobject, path);
10537 RB_OBJ_WRITTEN(iseq, Qundef, path);
10538 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10539
10540 return COMPILE_OK;
10541}
10542
10543#ifndef SHAREABLE_BARE_EXPRESSION
10544#define SHAREABLE_BARE_EXPRESSION 1
10545#endif
10546
10547static int
10548compile_shareable_literal_constant(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, NODE *dest, const NODE *node, size_t level, VALUE *value_p, int *shareable_literal_p)
10549{
10550# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10551 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10552 VALUE lit = Qnil;
10553 DECL_ANCHOR(anchor);
10554
10555 enum node_type type = node ? nd_type(node) : NODE_NIL;
10556 switch (type) {
10557 case NODE_TRUE:
10558 *value_p = Qtrue;
10559 goto compile;
10560 case NODE_FALSE:
10561 *value_p = Qfalse;
10562 goto compile;
10563 case NODE_NIL:
10564 *value_p = Qnil;
10565 goto compile;
10566 case NODE_SYM:
10567 *value_p = rb_node_sym_string_val(node);
10568 goto compile;
10569 case NODE_REGX:
10570 *value_p = rb_node_regx_string_val(node);
10571 goto compile;
10572 case NODE_LINE:
10573 *value_p = rb_node_line_lineno_val(node);
10574 goto compile;
10575 case NODE_INTEGER:
10576 *value_p = rb_node_integer_literal_val(node);
10577 goto compile;
10578 case NODE_FLOAT:
10579 *value_p = rb_node_float_literal_val(node);
10580 goto compile;
10581 case NODE_RATIONAL:
10582 *value_p = rb_node_rational_literal_val(node);
10583 goto compile;
10584 case NODE_IMAGINARY:
10585 *value_p = rb_node_imaginary_literal_val(node);
10586 goto compile;
10587 case NODE_ENCODING:
10588 *value_p = rb_node_encoding_val(node);
10589
10590 compile:
10591 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10592 *shareable_literal_p = 1;
10593 return COMPILE_OK;
10594
10595 case NODE_DSTR:
10596 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10597 if (shareable == rb_parser_shareable_literal) {
10598 /*
10599 * NEW_CALL(node, idUMinus, 0, loc);
10600 *
10601 * -"#{var}"
10602 */
10603 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10604 }
10605 *value_p = Qundef;
10606 *shareable_literal_p = 1;
10607 return COMPILE_OK;
10608
10609 case NODE_STR:{
10610 VALUE lit = rb_node_str_string_val(node);
10611 ADD_INSN1(ret, node, putobject, lit);
10612 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10613 *value_p = lit;
10614 *shareable_literal_p = 1;
10615
10616 return COMPILE_OK;
10617 }
10618
10619 case NODE_FILE:{
10620 VALUE lit = rb_node_file_path_val(node);
10621 ADD_INSN1(ret, node, putobject, lit);
10622 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10623 *value_p = lit;
10624 *shareable_literal_p = 1;
10625
10626 return COMPILE_OK;
10627 }
10628
10629 case NODE_ZLIST:{
10630 VALUE lit = rb_ary_new();
10631 OBJ_FREEZE(lit);
10632 ADD_INSN1(ret, node, putobject, lit);
10633 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10634 *value_p = lit;
10635 *shareable_literal_p = 1;
10636
10637 return COMPILE_OK;
10638 }
10639
10640 case NODE_LIST:{
10641 INIT_ANCHOR(anchor);
10642 lit = rb_ary_new();
10643 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10644 VALUE val;
10645 int shareable_literal_p2;
10646 NODE *elt = RNODE_LIST(n)->nd_head;
10647 if (elt) {
10648 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10649 if (shareable_literal_p2) {
10650 /* noop */
10651 }
10652 else if (RTEST(lit)) {
10653 rb_ary_clear(lit);
10654 lit = Qfalse;
10655 }
10656 }
10657 if (RTEST(lit)) {
10658 if (!UNDEF_P(val)) {
10659 rb_ary_push(lit, val);
10660 }
10661 else {
10662 rb_ary_clear(lit);
10663 lit = Qnil; /* make shareable at runtime */
10664 }
10665 }
10666 }
10667 break;
10668 }
10669 case NODE_HASH:{
10670 if (!RNODE_HASH(node)->nd_brace) {
10671 *value_p = Qundef;
10672 *shareable_literal_p = 0;
10673 return COMPILE_OK;
10674 }
10675 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10676 if (!RNODE_LIST(n)->nd_head) {
10677 // If the hash node have a keyword splat, fall back to the default case.
10678 goto compile_shareable;
10679 }
10680 }
10681
10682 INIT_ANCHOR(anchor);
10683 lit = rb_hash_new();
10684 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10685 VALUE key_val = 0;
10686 VALUE value_val = 0;
10687 int shareable_literal_p2;
10688 NODE *key = RNODE_LIST(n)->nd_head;
10689 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10690 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10691 if (shareable_literal_p2) {
10692 /* noop */
10693 }
10694 else if (RTEST(lit)) {
10695 rb_hash_clear(lit);
10696 lit = Qfalse;
10697 }
10698 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10699 if (shareable_literal_p2) {
10700 /* noop */
10701 }
10702 else if (RTEST(lit)) {
10703 rb_hash_clear(lit);
10704 lit = Qfalse;
10705 }
10706 if (RTEST(lit)) {
10707 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10708 rb_hash_aset(lit, key_val, value_val);
10709 }
10710 else {
10711 rb_hash_clear(lit);
10712 lit = Qnil; /* make shareable at runtime */
10713 }
10714 }
10715 }
10716 break;
10717 }
10718
10719 default:
10720
10721 compile_shareable:
10722 if (shareable == rb_parser_shareable_literal &&
10723 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10724 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10725 *value_p = Qundef;
10726 *shareable_literal_p = 1;
10727 return COMPILE_OK;
10728 }
10729 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10730 *value_p = Qundef;
10731 *shareable_literal_p = 0;
10732 return COMPILE_OK;
10733 }
10734
10735 /* Array or Hash that does not have keyword splat */
10736 if (!lit) {
10737 if (nd_type(node) == NODE_LIST) {
10738 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10739 }
10740 else if (nd_type(node) == NODE_HASH) {
10741 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10742 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10743 }
10744 *value_p = Qundef;
10745 *shareable_literal_p = 0;
10746 ADD_SEQ(ret, anchor);
10747 return COMPILE_OK;
10748 }
10749 if (NIL_P(lit)) {
10750 // if shareable_literal, all elements should have been ensured
10751 // as shareable
10752 if (nd_type(node) == NODE_LIST) {
10753 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10754 }
10755 else if (nd_type(node) == NODE_HASH) {
10756 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10757 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10758 }
10759 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
10760 *value_p = Qundef;
10761 *shareable_literal_p = 1;
10762 }
10763 else {
10764 VALUE val = rb_ractor_make_shareable(lit);
10765 ADD_INSN1(ret, node, putobject, val);
10766 RB_OBJ_WRITTEN(iseq, Qundef, val);
10767 *value_p = val;
10768 *shareable_literal_p = 1;
10769 }
10770
10771 return COMPILE_OK;
10772}
10773
10774static int
10775compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
10776{
10777 int literal_p = 0;
10778 VALUE val;
10779 DECL_ANCHOR(anchor);
10780 INIT_ANCHOR(anchor);
10781
10782 switch (shareable) {
10783 case rb_parser_shareable_none:
10784 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
10785 return COMPILE_OK;
10786
10787 case rb_parser_shareable_literal:
10788 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10789 ADD_SEQ(ret, anchor);
10790 return COMPILE_OK;
10791
10792 case rb_parser_shareable_copy:
10793 case rb_parser_shareable_everything:
10794 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10795 if (!literal_p) {
10796 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
10797 }
10798 else {
10799 ADD_SEQ(ret, anchor);
10800 }
10801 return COMPILE_OK;
10802 default:
10803 rb_bug("unexpected rb_parser_shareability: %d", shareable);
10804 }
10805}
10806
10807static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
10815static int
10816iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
10817{
10818 if (node == 0) {
10819 if (!popped) {
10820 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
10821 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
10822 debugs("node: NODE_NIL(implicit)\n");
10823 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
10824 }
10825 return COMPILE_OK;
10826 }
10827 return iseq_compile_each0(iseq, ret, node, popped);
10828}
10829
10830static int
10831iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10832{
10833 const int line = (int)nd_line(node);
10834 const enum node_type type = nd_type(node);
10835 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10836
10837 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
10838 /* ignore */
10839 }
10840 else {
10841 if (nd_fl_newline(node)) {
10842 int event = RUBY_EVENT_LINE;
10843 ISEQ_COMPILE_DATA(iseq)->last_line = line;
10844 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
10845 event |= RUBY_EVENT_COVERAGE_LINE;
10846 }
10847 ADD_TRACE(ret, event);
10848 }
10849 }
10850
10851 debug_node_start(node);
10852#undef BEFORE_RETURN
10853#define BEFORE_RETURN debug_node_end()
10854
10855 switch (type) {
10856 case NODE_BLOCK:
10857 CHECK(compile_block(iseq, ret, node, popped));
10858 break;
10859 case NODE_IF:
10860 case NODE_UNLESS:
10861 CHECK(compile_if(iseq, ret, node, popped, type));
10862 break;
10863 case NODE_CASE:
10864 CHECK(compile_case(iseq, ret, node, popped));
10865 break;
10866 case NODE_CASE2:
10867 CHECK(compile_case2(iseq, ret, node, popped));
10868 break;
10869 case NODE_CASE3:
10870 CHECK(compile_case3(iseq, ret, node, popped));
10871 break;
10872 case NODE_WHILE:
10873 case NODE_UNTIL:
10874 CHECK(compile_loop(iseq, ret, node, popped, type));
10875 break;
10876 case NODE_FOR:
10877 case NODE_ITER:
10878 CHECK(compile_iter(iseq, ret, node, popped));
10879 break;
10880 case NODE_FOR_MASGN:
10881 CHECK(compile_for_masgn(iseq, ret, node, popped));
10882 break;
10883 case NODE_BREAK:
10884 CHECK(compile_break(iseq, ret, node, popped));
10885 break;
10886 case NODE_NEXT:
10887 CHECK(compile_next(iseq, ret, node, popped));
10888 break;
10889 case NODE_REDO:
10890 CHECK(compile_redo(iseq, ret, node, popped));
10891 break;
10892 case NODE_RETRY:
10893 CHECK(compile_retry(iseq, ret, node, popped));
10894 break;
10895 case NODE_BEGIN:{
10896 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
10897 break;
10898 }
10899 case NODE_RESCUE:
10900 CHECK(compile_rescue(iseq, ret, node, popped));
10901 break;
10902 case NODE_RESBODY:
10903 CHECK(compile_resbody(iseq, ret, node, popped));
10904 break;
10905 case NODE_ENSURE:
10906 CHECK(compile_ensure(iseq, ret, node, popped));
10907 break;
10908
10909 case NODE_AND:
10910 case NODE_OR:{
10911 LABEL *end_label = NEW_LABEL(line);
10912 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
10913 if (!popped) {
10914 ADD_INSN(ret, node, dup);
10915 }
10916 if (type == NODE_AND) {
10917 ADD_INSNL(ret, node, branchunless, end_label);
10918 }
10919 else {
10920 ADD_INSNL(ret, node, branchif, end_label);
10921 }
10922 if (!popped) {
10923 ADD_INSN(ret, node, pop);
10924 }
10925 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
10926 ADD_LABEL(ret, end_label);
10927 break;
10928 }
10929
10930 case NODE_MASGN:{
10931 bool prev_in_masgn = ISEQ_COMPILE_DATA(iseq)->in_masgn;
10932 ISEQ_COMPILE_DATA(iseq)->in_masgn = true;
10933 compile_massign(iseq, ret, node, popped);
10934 ISEQ_COMPILE_DATA(iseq)->in_masgn = prev_in_masgn;
10935 break;
10936 }
10937
10938 case NODE_LASGN:{
10939 ID id = RNODE_LASGN(node)->nd_vid;
10940 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
10941
10942 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
10943 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
10944
10945 if (!popped) {
10946 ADD_INSN(ret, node, dup);
10947 }
10948 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
10949 break;
10950 }
10951 case NODE_DASGN: {
10952 int idx, lv, ls;
10953 ID id = RNODE_DASGN(node)->nd_vid;
10954 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
10955 debugi("dassn id", rb_id2str(id) ? id : '*');
10956
10957 if (!popped) {
10958 ADD_INSN(ret, node, dup);
10959 }
10960
10961 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
10962
10963 if (idx < 0) {
10964 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
10965 rb_id2str(id));
10966 goto ng;
10967 }
10968 ADD_SETLOCAL(ret, node, ls - idx, lv);
10969 break;
10970 }
10971 case NODE_GASGN:{
10972 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
10973
10974 if (!popped) {
10975 ADD_INSN(ret, node, dup);
10976 }
10977 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
10978 break;
10979 }
10980 case NODE_IASGN:{
10981 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
10982 if (!popped) {
10983 ADD_INSN(ret, node, dup);
10984 }
10985 ADD_INSN2(ret, node, setinstancevariable,
10986 ID2SYM(RNODE_IASGN(node)->nd_vid),
10987 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
10988 break;
10989 }
10990 case NODE_CDECL:{
10991 if (RNODE_CDECL(node)->nd_vid) {
10992 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10993
10994 if (!popped) {
10995 ADD_INSN(ret, node, dup);
10996 }
10997
10998 ADD_INSN1(ret, node, putspecialobject,
10999 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
11000 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
11001 }
11002 else {
11003 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
11004 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11005 ADD_INSN(ret, node, swap);
11006
11007 if (!popped) {
11008 ADD_INSN1(ret, node, topn, INT2FIX(1));
11009 ADD_INSN(ret, node, swap);
11010 }
11011
11012 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
11013 }
11014 break;
11015 }
11016 case NODE_CVASGN:{
11017 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
11018 if (!popped) {
11019 ADD_INSN(ret, node, dup);
11020 }
11021 ADD_INSN2(ret, node, setclassvariable,
11022 ID2SYM(RNODE_CVASGN(node)->nd_vid),
11023 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
11024 break;
11025 }
11026 case NODE_OP_ASGN1:
11027 CHECK(compile_op_asgn1(iseq, ret, node, popped));
11028 break;
11029 case NODE_OP_ASGN2:
11030 CHECK(compile_op_asgn2(iseq, ret, node, popped));
11031 break;
11032 case NODE_OP_CDECL:
11033 CHECK(compile_op_cdecl(iseq, ret, node, popped));
11034 break;
11035 case NODE_OP_ASGN_AND:
11036 case NODE_OP_ASGN_OR:
11037 CHECK(compile_op_log(iseq, ret, node, popped, type));
11038 break;
11039 case NODE_CALL: /* obj.foo */
11040 case NODE_OPCALL: /* foo[] */
11041 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
11042 break;
11043 }
11044 case NODE_QCALL: /* obj&.foo */
11045 case NODE_FCALL: /* foo() */
11046 case NODE_VCALL: /* foo (variable or call) */
11047 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
11048 goto ng;
11049 }
11050 break;
11051 case NODE_SUPER:
11052 case NODE_ZSUPER:
11053 CHECK(compile_super(iseq, ret, node, popped, type));
11054 break;
11055 case NODE_LIST:{
11056 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
11057 break;
11058 }
11059 case NODE_ZLIST:{
11060 if (!popped) {
11061 ADD_INSN1(ret, node, newarray, INT2FIX(0));
11062 }
11063 break;
11064 }
11065 case NODE_HASH:
11066 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
11067 break;
11068 case NODE_RETURN:
11069 CHECK(compile_return(iseq, ret, node, popped));
11070 break;
11071 case NODE_YIELD:
11072 CHECK(compile_yield(iseq, ret, node, popped));
11073 break;
11074 case NODE_LVAR:{
11075 if (!popped) {
11076 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
11077 }
11078 break;
11079 }
11080 case NODE_DVAR:{
11081 int lv, idx, ls;
11082 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
11083 if (!popped) {
11084 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
11085 if (idx < 0) {
11086 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
11087 rb_id2str(RNODE_DVAR(node)->nd_vid));
11088 goto ng;
11089 }
11090 ADD_GETLOCAL(ret, node, ls - idx, lv);
11091 }
11092 break;
11093 }
11094 case NODE_GVAR:{
11095 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
11096 if (popped) {
11097 ADD_INSN(ret, node, pop);
11098 }
11099 break;
11100 }
11101 case NODE_IVAR:{
11102 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
11103 if (!popped) {
11104 ADD_INSN2(ret, node, getinstancevariable,
11105 ID2SYM(RNODE_IVAR(node)->nd_vid),
11106 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
11107 }
11108 break;
11109 }
11110 case NODE_CONST:{
11111 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
11112
11113 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
11114 body->ic_size++;
11115 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
11116 RB_OBJ_SET_FROZEN_SHAREABLE(segments);
11117 ADD_INSN1(ret, node, opt_getconstant_path, segments);
11118 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11119 }
11120 else {
11121 ADD_INSN(ret, node, putnil);
11122 ADD_INSN1(ret, node, putobject, Qtrue);
11123 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
11124 }
11125
11126 if (popped) {
11127 ADD_INSN(ret, node, pop);
11128 }
11129 break;
11130 }
11131 case NODE_CVAR:{
11132 if (!popped) {
11133 ADD_INSN2(ret, node, getclassvariable,
11134 ID2SYM(RNODE_CVAR(node)->nd_vid),
11135 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
11136 }
11137 break;
11138 }
11139 case NODE_NTH_REF:{
11140 if (!popped) {
11141 if (!RNODE_NTH_REF(node)->nd_nth) {
11142 ADD_INSN(ret, node, putnil);
11143 break;
11144 }
11145 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11146 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
11147 }
11148 break;
11149 }
11150 case NODE_BACK_REF:{
11151 if (!popped) {
11152 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11153 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
11154 }
11155 break;
11156 }
11157 case NODE_MATCH:
11158 case NODE_MATCH2:
11159 case NODE_MATCH3:
11160 CHECK(compile_match(iseq, ret, node, popped, type));
11161 break;
11162 case NODE_SYM:{
11163 if (!popped) {
11164 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
11165 }
11166 break;
11167 }
11168 case NODE_LINE:{
11169 if (!popped) {
11170 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
11171 }
11172 break;
11173 }
11174 case NODE_ENCODING:{
11175 if (!popped) {
11176 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11177 }
11178 break;
11179 }
11180 case NODE_INTEGER:{
11181 VALUE lit = rb_node_integer_literal_val(node);
11182 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11183 debugp_param("integer", lit);
11184 if (!popped) {
11185 ADD_INSN1(ret, node, putobject, lit);
11186 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11187 }
11188 break;
11189 }
11190 case NODE_FLOAT:{
11191 VALUE lit = rb_node_float_literal_val(node);
11192 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11193 debugp_param("float", lit);
11194 if (!popped) {
11195 ADD_INSN1(ret, node, putobject, lit);
11196 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11197 }
11198 break;
11199 }
11200 case NODE_RATIONAL:{
11201 VALUE lit = rb_node_rational_literal_val(node);
11202 rb_ractor_make_shareable(lit);
11203 debugp_param("rational", lit);
11204 if (!popped) {
11205 ADD_INSN1(ret, node, putobject, lit);
11206 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11207 }
11208 break;
11209 }
11210 case NODE_IMAGINARY:{
11211 VALUE lit = rb_node_imaginary_literal_val(node);
11212 rb_ractor_make_shareable(lit);
11213 debugp_param("imaginary", lit);
11214 if (!popped) {
11215 ADD_INSN1(ret, node, putobject, lit);
11216 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11217 }
11218 break;
11219 }
11220 case NODE_FILE:
11221 case NODE_STR:{
11222 debugp_param("nd_lit", get_string_value(node));
11223 if (!popped) {
11224 VALUE lit = get_string_value(node);
11225 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11226 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11227 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11228 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11229 RB_OBJ_SET_SHAREABLE(lit);
11230 }
11231 switch (option->frozen_string_literal) {
11232 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11233 ADD_INSN1(ret, node, putchilledstring, lit);
11234 break;
11235 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11236 ADD_INSN1(ret, node, putstring, lit);
11237 break;
11238 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11239 ADD_INSN1(ret, node, putobject, lit);
11240 break;
11241 default:
11242 rb_bug("invalid frozen_string_literal");
11243 }
11244 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11245 }
11246 break;
11247 }
11248 case NODE_DSTR:{
11249 compile_dstr(iseq, ret, node);
11250
11251 if (popped) {
11252 ADD_INSN(ret, node, pop);
11253 }
11254 break;
11255 }
11256 case NODE_XSTR:{
11257 ADD_CALL_RECEIVER(ret, node);
11258 VALUE str = rb_node_str_string_val(node);
11259 ADD_INSN1(ret, node, putobject, str);
11260 RB_OBJ_WRITTEN(iseq, Qundef, str);
11261 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11262
11263 if (popped) {
11264 ADD_INSN(ret, node, pop);
11265 }
11266 break;
11267 }
11268 case NODE_DXSTR:{
11269 ADD_CALL_RECEIVER(ret, node);
11270 compile_dstr(iseq, ret, node);
11271 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11272
11273 if (popped) {
11274 ADD_INSN(ret, node, pop);
11275 }
11276 break;
11277 }
11278 case NODE_EVSTR:
11279 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11280 break;
11281 case NODE_REGX:{
11282 if (!popped) {
11283 VALUE lit = rb_node_regx_string_val(node);
11284 RB_OBJ_SET_SHAREABLE(lit);
11285 ADD_INSN1(ret, node, putobject, lit);
11286 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11287 }
11288 break;
11289 }
11290 case NODE_DREGX:
11291 compile_dregx(iseq, ret, node, popped);
11292 break;
11293 case NODE_ONCE:{
11294 int ic_index = body->ise_size++;
11295 const rb_iseq_t *block_iseq;
11296 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11297
11298 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11299 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11300
11301 if (popped) {
11302 ADD_INSN(ret, node, pop);
11303 }
11304 break;
11305 }
11306 case NODE_ARGSCAT:{
11307 if (popped) {
11308 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11309 ADD_INSN1(ret, node, splatarray, Qfalse);
11310 ADD_INSN(ret, node, pop);
11311 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11312 ADD_INSN1(ret, node, splatarray, Qfalse);
11313 ADD_INSN(ret, node, pop);
11314 }
11315 else {
11316 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11317 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11318 if (nd_type_p(body_node, NODE_LIST)) {
11319 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11320 }
11321 else {
11322 CHECK(COMPILE(ret, "argscat body", body_node));
11323 ADD_INSN(ret, node, concattoarray);
11324 }
11325 }
11326 break;
11327 }
11328 case NODE_ARGSPUSH:{
11329 if (popped) {
11330 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11331 ADD_INSN1(ret, node, splatarray, Qfalse);
11332 ADD_INSN(ret, node, pop);
11333 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11334 }
11335 else {
11336 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11337 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11338 if (keyword_node_p(body_node)) {
11339 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11340 ADD_INSN(ret, node, pushtoarraykwsplat);
11341 }
11342 else if (static_literal_node_p(body_node, iseq, false)) {
11343 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11344 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11345 }
11346 else {
11347 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11348 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11349 }
11350 }
11351 break;
11352 }
11353 case NODE_SPLAT:{
11354 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11355 ADD_INSN1(ret, node, splatarray, Qtrue);
11356
11357 if (popped) {
11358 ADD_INSN(ret, node, pop);
11359 }
11360 break;
11361 }
11362 case NODE_DEFN:{
11363 ID mid = RNODE_DEFN(node)->nd_mid;
11364 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11365 rb_id2str(mid),
11366 ISEQ_TYPE_METHOD, line);
11367
11368 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11369 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11370 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11371
11372 if (!popped) {
11373 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11374 }
11375
11376 break;
11377 }
11378 case NODE_DEFS:{
11379 ID mid = RNODE_DEFS(node)->nd_mid;
11380 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11381 rb_id2str(mid),
11382 ISEQ_TYPE_METHOD, line);
11383
11384 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11385 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11386 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11387 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11388
11389 if (!popped) {
11390 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11391 }
11392 break;
11393 }
11394 case NODE_ALIAS:{
11395 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11396 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11397 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11398 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11399 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11400
11401 if (popped) {
11402 ADD_INSN(ret, node, pop);
11403 }
11404 break;
11405 }
11406 case NODE_VALIAS:{
11407 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11408 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11409 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11410 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11411
11412 if (popped) {
11413 ADD_INSN(ret, node, pop);
11414 }
11415 break;
11416 }
11417 case NODE_UNDEF:{
11418 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11419
11420 for (long i = 0; i < ary->len; i++) {
11421 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11422 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11423 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11424 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11425
11426 if (i < ary->len - 1) {
11427 ADD_INSN(ret, node, pop);
11428 }
11429 }
11430
11431 if (popped) {
11432 ADD_INSN(ret, node, pop);
11433 }
11434 break;
11435 }
11436 case NODE_CLASS:{
11437 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11438 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11439 ISEQ_TYPE_CLASS, line);
11440 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11441 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11442 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11443
11444 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11445 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11446 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11447
11448 if (popped) {
11449 ADD_INSN(ret, node, pop);
11450 }
11451 break;
11452 }
11453 case NODE_MODULE:{
11454 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11455 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11456 ISEQ_TYPE_CLASS, line);
11457 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11458 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11459
11460 ADD_INSN (ret, node, putnil); /* dummy */
11461 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11462 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11463
11464 if (popped) {
11465 ADD_INSN(ret, node, pop);
11466 }
11467 break;
11468 }
11469 case NODE_SCLASS:{
11470 ID singletonclass;
11471 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11472 ISEQ_TYPE_CLASS, line);
11473
11474 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11475 ADD_INSN (ret, node, putnil);
11476 CONST_ID(singletonclass, "singletonclass");
11477 ADD_INSN3(ret, node, defineclass,
11478 ID2SYM(singletonclass), singleton_class,
11479 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
11480 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11481
11482 if (popped) {
11483 ADD_INSN(ret, node, pop);
11484 }
11485 break;
11486 }
11487 case NODE_COLON2:
11488 CHECK(compile_colon2(iseq, ret, node, popped));
11489 break;
11490 case NODE_COLON3:
11491 CHECK(compile_colon3(iseq, ret, node, popped));
11492 break;
11493 case NODE_DOT2:
11494 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11495 break;
11496 case NODE_DOT3:
11497 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11498 break;
11499 case NODE_FLIP2:
11500 case NODE_FLIP3:{
11501 LABEL *lend = NEW_LABEL(line);
11502 LABEL *ltrue = NEW_LABEL(line);
11503 LABEL *lfalse = NEW_LABEL(line);
11504 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11505 ltrue, lfalse));
11506 ADD_LABEL(ret, ltrue);
11507 ADD_INSN1(ret, node, putobject, Qtrue);
11508 ADD_INSNL(ret, node, jump, lend);
11509 ADD_LABEL(ret, lfalse);
11510 ADD_INSN1(ret, node, putobject, Qfalse);
11511 ADD_LABEL(ret, lend);
11512 break;
11513 }
11514 case NODE_SELF:{
11515 if (!popped) {
11516 ADD_INSN(ret, node, putself);
11517 }
11518 break;
11519 }
11520 case NODE_NIL:{
11521 if (!popped) {
11522 ADD_INSN(ret, node, putnil);
11523 }
11524 break;
11525 }
11526 case NODE_TRUE:{
11527 if (!popped) {
11528 ADD_INSN1(ret, node, putobject, Qtrue);
11529 }
11530 break;
11531 }
11532 case NODE_FALSE:{
11533 if (!popped) {
11534 ADD_INSN1(ret, node, putobject, Qfalse);
11535 }
11536 break;
11537 }
11538 case NODE_ERRINFO:
11539 CHECK(compile_errinfo(iseq, ret, node, popped));
11540 break;
11541 case NODE_DEFINED:
11542 if (!popped) {
11543 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11544 }
11545 break;
11546 case NODE_POSTEXE:{
11547 /* compiled to:
11548 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11549 */
11550 int is_index = body->ise_size++;
11551 struct rb_iseq_new_with_callback_callback_func *ifunc =
11552 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11553 const rb_iseq_t *once_iseq =
11554 NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc, rb_fstring(make_name_for_block(iseq)), ISEQ_TYPE_BLOCK, line);
11555
11556 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11557 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11558
11559 if (popped) {
11560 ADD_INSN(ret, node, pop);
11561 }
11562 break;
11563 }
11564 case NODE_KW_ARG:
11565 CHECK(compile_kw_arg(iseq, ret, node, popped));
11566 break;
11567 case NODE_DSYM:{
11568 compile_dstr(iseq, ret, node);
11569 if (!popped) {
11570 ADD_INSN(ret, node, intern);
11571 }
11572 else {
11573 ADD_INSN(ret, node, pop);
11574 }
11575 break;
11576 }
11577 case NODE_ATTRASGN:
11578 CHECK(compile_attrasgn(iseq, ret, node, popped));
11579 break;
11580 case NODE_LAMBDA:{
11581 /* compile same as lambda{...} */
11582 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11583 VALUE argc = INT2FIX(0);
11584
11585 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11586 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11587 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11588
11589 if (popped) {
11590 ADD_INSN(ret, node, pop);
11591 }
11592 break;
11593 }
11594 default:
11595 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11596 ng:
11597 debug_node_end();
11598 return COMPILE_NG;
11599 }
11600
11601 debug_node_end();
11602 return COMPILE_OK;
11603}
11604
11605/***************************/
11606/* instruction information */
11607/***************************/
11608
11609static int
11610insn_data_length(INSN *iobj)
11611{
11612 return insn_len(iobj->insn_id);
11613}
11614
11615static int
11616calc_sp_depth(int depth, INSN *insn)
11617{
11618 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11619}
11620
11621static VALUE
11622opobj_inspect(VALUE obj)
11623{
11624 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11625 switch (BUILTIN_TYPE(obj)) {
11626 case T_STRING:
11627 obj = rb_str_new_cstr(RSTRING_PTR(obj));
11628 break;
11629 case T_ARRAY:
11630 obj = rb_ary_dup(obj);
11631 break;
11632 default:
11633 break;
11634 }
11635 }
11636 return rb_inspect(obj);
11637}
11638
11639
11640
11641static VALUE
11642insn_data_to_s_detail(INSN *iobj)
11643{
11644 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11645
11646 if (iobj->operands) {
11647 const char *types = insn_op_types(iobj->insn_id);
11648 int j;
11649
11650 for (j = 0; types[j]; j++) {
11651 char type = types[j];
11652
11653 switch (type) {
11654 case TS_OFFSET: /* label(destination position) */
11655 {
11656 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11657 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11658 break;
11659 }
11660 break;
11661 case TS_ISEQ: /* iseq */
11662 {
11663 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11664 VALUE val = Qnil;
11665 if (0 && iseq) { /* TODO: invalidate now */
11666 val = (VALUE)iseq;
11667 }
11668 rb_str_concat(str, opobj_inspect(val));
11669 }
11670 break;
11671 case TS_LINDEX:
11672 case TS_NUM: /* ulong */
11673 case TS_VALUE: /* VALUE */
11674 {
11675 VALUE v = OPERAND_AT(iobj, j);
11676 if (!CLASS_OF(v))
11677 rb_str_cat2(str, "<hidden>");
11678 else {
11679 rb_str_concat(str, opobj_inspect(v));
11680 }
11681 break;
11682 }
11683 case TS_ID: /* ID */
11684 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11685 break;
11686 case TS_IC: /* inline cache */
11687 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11688 break;
11689 case TS_IVC: /* inline ivar cache */
11690 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11691 break;
11692 case TS_ICVARC: /* inline cvar cache */
11693 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11694 break;
11695 case TS_ISE: /* inline storage entry */
11696 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11697 break;
11698 case TS_CALLDATA: /* we store these as call infos at compile time */
11699 {
11700 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11701 rb_str_cat2(str, "<calldata:");
11702 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
11703 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11704 break;
11705 }
11706 case TS_CDHASH: /* case/when condition cache */
11707 rb_str_cat2(str, "<ch>");
11708 break;
11709 case TS_FUNCPTR:
11710 {
11711 void *func = (void *)OPERAND_AT(iobj, j);
11712#ifdef HAVE_DLADDR
11713 Dl_info info;
11714 if (dladdr(func, &info) && info.dli_sname) {
11715 rb_str_cat2(str, info.dli_sname);
11716 break;
11717 }
11718#endif
11719 rb_str_catf(str, "<%p>", func);
11720 }
11721 break;
11722 case TS_BUILTIN:
11723 rb_str_cat2(str, "<TS_BUILTIN>");
11724 break;
11725 default:{
11726 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
11727 }
11728 }
11729 if (types[j + 1]) {
11730 rb_str_cat2(str, ", ");
11731 }
11732 }
11733 }
11734 return str;
11735}
11736
11737static void
11738dump_disasm_list(const LINK_ELEMENT *link)
11739{
11740 dump_disasm_list_with_cursor(link, NULL, NULL);
11741}
11742
11743static void
11744dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
11745{
11746 int pos = 0;
11747 INSN *iobj;
11748 LABEL *lobj;
11749 VALUE str;
11750
11751 printf("-- raw disasm--------\n");
11752
11753 while (link) {
11754 if (curr) printf(curr == link ? "*" : " ");
11755 switch (link->type) {
11756 case ISEQ_ELEMENT_INSN:
11757 {
11758 iobj = (INSN *)link;
11759 str = insn_data_to_s_detail(iobj);
11760 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
11761 pos += insn_data_length(iobj);
11762 break;
11763 }
11764 case ISEQ_ELEMENT_LABEL:
11765 {
11766 lobj = (LABEL *)link;
11767 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11768 dest == lobj ? " <---" : "");
11769 break;
11770 }
11771 case ISEQ_ELEMENT_TRACE:
11772 {
11773 TRACE *trace = (TRACE *)link;
11774 printf(" trace: %0x\n", trace->event);
11775 break;
11776 }
11777 case ISEQ_ELEMENT_ADJUST:
11778 {
11779 ADJUST *adjust = (ADJUST *)link;
11780 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11781 break;
11782 }
11783 default:
11784 /* ignore */
11785 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
11786 }
11787 link = link->next;
11788 }
11789 printf("---------------------\n");
11790 fflush(stdout);
11791}
11792
11793int
11794rb_insn_len(VALUE insn)
11795{
11796 return insn_len(insn);
11797}
11798
11799const char *
11800rb_insns_name(int i)
11801{
11802 return insn_name(i);
11803}
11804
11805 VALUE
11806rb_insns_name_array(void)
11807{
11808 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
11809 int i;
11810 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
11811 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
11812 }
11813 return rb_ary_freeze(ary);
11814}
11815
11816static LABEL *
11817register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
11818{
11819 LABEL *label = 0;
11820 st_data_t tmp;
11821 obj = rb_to_symbol_type(obj);
11822
11823 if (st_lookup(labels_table, obj, &tmp) == 0) {
11824 label = NEW_LABEL(0);
11825 st_insert(labels_table, obj, (st_data_t)label);
11826 }
11827 else {
11828 label = (LABEL *)tmp;
11829 }
11830 LABEL_REF(label);
11831 return label;
11832}
11833
11834static VALUE
11835get_exception_sym2type(VALUE sym)
11836{
11837 static VALUE symRescue, symEnsure, symRetry;
11838 static VALUE symBreak, symRedo, symNext;
11839
11840 if (symRescue == 0) {
11841 symRescue = ID2SYM(rb_intern_const("rescue"));
11842 symEnsure = ID2SYM(rb_intern_const("ensure"));
11843 symRetry = ID2SYM(rb_intern_const("retry"));
11844 symBreak = ID2SYM(rb_intern_const("break"));
11845 symRedo = ID2SYM(rb_intern_const("redo"));
11846 symNext = ID2SYM(rb_intern_const("next"));
11847 }
11848
11849 if (sym == symRescue) return CATCH_TYPE_RESCUE;
11850 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
11851 if (sym == symRetry) return CATCH_TYPE_RETRY;
11852 if (sym == symBreak) return CATCH_TYPE_BREAK;
11853 if (sym == symRedo) return CATCH_TYPE_REDO;
11854 if (sym == symNext) return CATCH_TYPE_NEXT;
11855 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
11856 return 0;
11857}
11858
11859static int
11860iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
11861 VALUE exception)
11862{
11863 int i;
11864
11865 for (i=0; i<RARRAY_LEN(exception); i++) {
11866 const rb_iseq_t *eiseq;
11867 VALUE v, type;
11868 LABEL *lstart, *lend, *lcont;
11869 unsigned int sp;
11870
11871 v = rb_to_array_type(RARRAY_AREF(exception, i));
11872 if (RARRAY_LEN(v) != 6) {
11873 rb_raise(rb_eSyntaxError, "wrong exception entry");
11874 }
11875 type = get_exception_sym2type(RARRAY_AREF(v, 0));
11876 if (NIL_P(RARRAY_AREF(v, 1))) {
11877 eiseq = NULL;
11878 }
11879 else {
11880 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
11881 }
11882
11883 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
11884 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
11885 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
11886 sp = NUM2UINT(RARRAY_AREF(v, 5));
11887
11888 /* TODO: Dirty Hack! Fix me */
11889 if (type == CATCH_TYPE_RESCUE ||
11890 type == CATCH_TYPE_BREAK ||
11891 type == CATCH_TYPE_NEXT) {
11892 ++sp;
11893 }
11894
11895 lcont->sp = sp;
11896
11897 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
11898
11899 RB_GC_GUARD(v);
11900 }
11901 return COMPILE_OK;
11902}
11903
11904static struct st_table *
11905insn_make_insn_table(void)
11906{
11907 struct st_table *table;
11908 int i;
11909 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
11910
11911 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
11912 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
11913 }
11914
11915 return table;
11916}
11917
11918static const rb_iseq_t *
11919iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
11920{
11921 VALUE iseqw;
11922 const rb_iseq_t *loaded_iseq;
11923
11924 if (RB_TYPE_P(op, T_ARRAY)) {
11925 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
11926 }
11927 else if (CLASS_OF(op) == rb_cISeq) {
11928 iseqw = op;
11929 }
11930 else {
11931 rb_raise(rb_eSyntaxError, "ISEQ is required");
11932 }
11933
11934 loaded_iseq = rb_iseqw_to_iseq(iseqw);
11935 return loaded_iseq;
11936}
11937
11938static VALUE
11939iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
11940{
11941 ID mid = 0;
11942 int orig_argc = 0;
11943 unsigned int flag = 0;
11944 struct rb_callinfo_kwarg *kw_arg = 0;
11945
11946 if (!NIL_P(op)) {
11947 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
11948 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
11949 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
11950 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
11951
11952 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
11953 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
11954 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
11955
11956 if (!NIL_P(vkw_arg)) {
11957 int i;
11958 int len = RARRAY_LENINT(vkw_arg);
11959 size_t n = rb_callinfo_kwarg_bytes(len);
11960
11961 kw_arg = xmalloc(n);
11962 kw_arg->references = 0;
11963 kw_arg->keyword_len = len;
11964 for (i = 0; i < len; i++) {
11965 VALUE kw = RARRAY_AREF(vkw_arg, i);
11966 SYM2ID(kw); /* make immortal */
11967 kw_arg->keywords[i] = kw;
11968 }
11969 }
11970 }
11971
11972 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
11973 RB_OBJ_WRITTEN(iseq, Qundef, ci);
11974 return (VALUE)ci;
11975}
11976
11977static rb_event_flag_t
11978event_name_to_flag(VALUE sym)
11979{
11980#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
11981 CHECK_EVENT(RUBY_EVENT_LINE);
11982 CHECK_EVENT(RUBY_EVENT_CLASS);
11983 CHECK_EVENT(RUBY_EVENT_END);
11984 CHECK_EVENT(RUBY_EVENT_CALL);
11985 CHECK_EVENT(RUBY_EVENT_RETURN);
11986 CHECK_EVENT(RUBY_EVENT_B_CALL);
11987 CHECK_EVENT(RUBY_EVENT_B_RETURN);
11988 CHECK_EVENT(RUBY_EVENT_RESCUE);
11989#undef CHECK_EVENT
11990 return RUBY_EVENT_NONE;
11991}
11992
11993static int
11994iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
11995 VALUE body, VALUE node_ids, VALUE labels_wrapper)
11996{
11997 /* TODO: body should be frozen */
11998 long i, len = RARRAY_LEN(body);
11999 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
12000 int j;
12001 int line_no = 0, node_id = -1, insn_idx = 0;
12002 int ret = COMPILE_OK;
12003
12004 /*
12005 * index -> LABEL *label
12006 */
12007 static struct st_table *insn_table;
12008
12009 if (insn_table == 0) {
12010 insn_table = insn_make_insn_table();
12011 }
12012
12013 for (i=0; i<len; i++) {
12014 VALUE obj = RARRAY_AREF(body, i);
12015
12016 if (SYMBOL_P(obj)) {
12017 rb_event_flag_t event;
12018 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
12019 ADD_TRACE(anchor, event);
12020 }
12021 else {
12022 LABEL *label = register_label(iseq, labels_table, obj);
12023 ADD_LABEL(anchor, label);
12024 }
12025 }
12026 else if (FIXNUM_P(obj)) {
12027 line_no = NUM2INT(obj);
12028 }
12029 else if (RB_TYPE_P(obj, T_ARRAY)) {
12030 VALUE *argv = 0;
12031 int argc = RARRAY_LENINT(obj) - 1;
12032 st_data_t insn_id;
12033 VALUE insn;
12034
12035 if (node_ids) {
12036 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
12037 }
12038
12039 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
12040 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
12041 /* TODO: exception */
12042 COMPILE_ERROR(iseq, line_no,
12043 "unknown instruction: %+"PRIsVALUE, insn);
12044 ret = COMPILE_NG;
12045 break;
12046 }
12047
12048 if (argc != insn_len((VALUE)insn_id)-1) {
12049 COMPILE_ERROR(iseq, line_no,
12050 "operand size mismatch");
12051 ret = COMPILE_NG;
12052 break;
12053 }
12054
12055 if (argc > 0) {
12056 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
12057
12058 // add element before operand setup to make GC root
12059 ADD_ELEM(anchor,
12060 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12061 (enum ruby_vminsn_type)insn_id, argc, argv));
12062
12063 for (j=0; j<argc; j++) {
12064 VALUE op = rb_ary_entry(obj, j+1);
12065 switch (insn_op_type((VALUE)insn_id, j)) {
12066 case TS_OFFSET: {
12067 LABEL *label = register_label(iseq, labels_table, op);
12068 argv[j] = (VALUE)label;
12069 break;
12070 }
12071 case TS_LINDEX:
12072 case TS_NUM:
12073 (void)NUM2INT(op);
12074 argv[j] = op;
12075 break;
12076 case TS_VALUE:
12077 argv[j] = op;
12078 RB_OBJ_WRITTEN(iseq, Qundef, op);
12079 break;
12080 case TS_ISEQ:
12081 {
12082 if (op != Qnil) {
12083 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
12084 argv[j] = v;
12085 RB_OBJ_WRITTEN(iseq, Qundef, v);
12086 }
12087 else {
12088 argv[j] = 0;
12089 }
12090 }
12091 break;
12092 case TS_ISE:
12093 argv[j] = op;
12094 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
12095 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
12096 }
12097 break;
12098 case TS_IC:
12099 {
12100 VALUE segments = rb_ary_new();
12101 op = rb_to_array_type(op);
12102
12103 for (int i = 0; i < RARRAY_LEN(op); i++) {
12104 VALUE sym = RARRAY_AREF(op, i);
12105 sym = rb_to_symbol_type(sym);
12106 rb_ary_push(segments, sym);
12107 }
12108
12109 RB_GC_GUARD(op);
12110 argv[j] = segments;
12111 RB_OBJ_WRITTEN(iseq, Qundef, segments);
12112 ISEQ_BODY(iseq)->ic_size++;
12113 }
12114 break;
12115 case TS_IVC: /* inline ivar cache */
12116 argv[j] = op;
12117 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
12118 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
12119 }
12120 break;
12121 case TS_ICVARC: /* inline cvar cache */
12122 argv[j] = op;
12123 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
12124 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
12125 }
12126 break;
12127 case TS_CALLDATA:
12128 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
12129 break;
12130 case TS_ID:
12131 argv[j] = rb_to_symbol_type(op);
12132 break;
12133 case TS_CDHASH:
12134 {
12135 int i;
12136 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
12137
12138 RHASH_TBL_RAW(map)->type = &cdhash_type;
12139 op = rb_to_array_type(op);
12140 for (i=0; i<RARRAY_LEN(op); i+=2) {
12141 VALUE key = RARRAY_AREF(op, i);
12142 VALUE sym = RARRAY_AREF(op, i+1);
12143 LABEL *label =
12144 register_label(iseq, labels_table, sym);
12145 rb_hash_aset(map, key, (VALUE)label | 1);
12146 }
12147 RB_GC_GUARD(op);
12148 RB_OBJ_SET_SHAREABLE(rb_obj_hide(map)); // allow mutation while compiling
12149 argv[j] = map;
12150 RB_OBJ_WRITTEN(iseq, Qundef, map);
12151 }
12152 break;
12153 case TS_FUNCPTR:
12154 {
12155#if SIZEOF_VALUE <= SIZEOF_LONG
12156 long funcptr = NUM2LONG(op);
12157#else
12158 LONG_LONG funcptr = NUM2LL(op);
12159#endif
12160 argv[j] = (VALUE)funcptr;
12161 }
12162 break;
12163 default:
12164 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
12165 }
12166 }
12167 }
12168 else {
12169 ADD_ELEM(anchor,
12170 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12171 (enum ruby_vminsn_type)insn_id, argc, NULL));
12172 }
12173 }
12174 else {
12175 rb_raise(rb_eTypeError, "unexpected object for instruction");
12176 }
12177 }
12178 RTYPEDDATA_DATA(labels_wrapper) = 0;
12179 RB_GC_GUARD(labels_wrapper);
12180 validate_labels(iseq, labels_table);
12181 if (!ret) return ret;
12182 return iseq_setup(iseq, anchor);
12183}
12184
12185#define CHECK_ARRAY(v) rb_to_array_type(v)
12186#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12187
12188static int
12189int_param(int *dst, VALUE param, VALUE sym)
12190{
12191 VALUE val = rb_hash_aref(param, sym);
12192 if (FIXNUM_P(val)) {
12193 *dst = FIX2INT(val);
12194 return TRUE;
12195 }
12196 else if (!NIL_P(val)) {
12197 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
12198 sym, val);
12199 }
12200 return FALSE;
12201}
12202
12203static const struct rb_iseq_param_keyword *
12204iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12205{
12206 int i, j;
12207 int len = RARRAY_LENINT(keywords);
12208 int default_len;
12209 VALUE key, sym, default_val;
12210 VALUE *dvs;
12211 ID *ids;
12212 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12213
12214 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12215
12216 keyword->num = len;
12217#define SYM(s) ID2SYM(rb_intern_const(#s))
12218 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12219 i = keyword->bits_start - keyword->num;
12220 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12221#undef SYM
12222
12223 /* required args */
12224 for (i = 0; i < len; i++) {
12225 VALUE val = RARRAY_AREF(keywords, i);
12226
12227 if (!SYMBOL_P(val)) {
12228 goto default_values;
12229 }
12230 ids[i] = SYM2ID(val);
12231 keyword->required_num++;
12232 }
12233
12234 default_values: /* note: we intentionally preserve `i' from previous loop */
12235 default_len = len - i;
12236 if (default_len == 0) {
12237 keyword->table = ids;
12238 return keyword;
12239 }
12240 else if (default_len < 0) {
12241 UNREACHABLE;
12242 }
12243
12244 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12245
12246 for (j = 0; i < len; i++, j++) {
12247 key = RARRAY_AREF(keywords, i);
12248 CHECK_ARRAY(key);
12249
12250 switch (RARRAY_LEN(key)) {
12251 case 1:
12252 sym = RARRAY_AREF(key, 0);
12253 default_val = Qundef;
12254 break;
12255 case 2:
12256 sym = RARRAY_AREF(key, 0);
12257 default_val = RARRAY_AREF(key, 1);
12258 break;
12259 default:
12260 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12261 }
12262 ids[i] = SYM2ID(sym);
12263 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12264 }
12265
12266 keyword->table = ids;
12267 keyword->default_values = dvs;
12268
12269 return keyword;
12270}
12271
12272static void
12273iseq_insn_each_object_mark_and_move(VALUE * obj, VALUE _)
12274{
12275 rb_gc_mark_and_move(obj);
12276}
12277
12278void
12279rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
12280{
12281 INSN *iobj = 0;
12282 size_t size = sizeof(INSN);
12283 unsigned int pos = 0;
12284
12285 while (storage) {
12286#ifdef STRICT_ALIGNMENT
12287 size_t padding = calc_padding((void *)&storage->buff[pos], size);
12288#else
12289 const size_t padding = 0; /* expected to be optimized by compiler */
12290#endif /* STRICT_ALIGNMENT */
12291 size_t offset = pos + size + padding;
12292 if (offset > storage->size || offset > storage->pos) {
12293 pos = 0;
12294 storage = storage->next;
12295 }
12296 else {
12297#ifdef STRICT_ALIGNMENT
12298 pos += (int)padding;
12299#endif /* STRICT_ALIGNMENT */
12300
12301 iobj = (INSN *)&storage->buff[pos];
12302
12303 if (iobj->operands) {
12304 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (VALUE)0);
12305 }
12306 pos += (int)size;
12307 }
12308 }
12309}
12310
12311static const rb_data_type_t labels_wrapper_type = {
12312 .wrap_struct_name = "compiler/labels_wrapper",
12313 .function = {
12314 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12315 .dfree = (RUBY_DATA_FUNC)st_free_table,
12316 },
12317 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
12318};
12319
12320void
12321rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12322 VALUE exception, VALUE body)
12323{
12324#define SYM(s) ID2SYM(rb_intern_const(#s))
12325 int i, len;
12326 unsigned int arg_size, local_size, stack_max;
12327 ID *tbl;
12328 struct st_table *labels_table = st_init_numtable();
12329 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12330 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12331 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12332 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12333 DECL_ANCHOR(anchor);
12334 INIT_ANCHOR(anchor);
12335
12336 len = RARRAY_LENINT(locals);
12337 ISEQ_BODY(iseq)->local_table_size = len;
12338 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12339
12340 for (i = 0; i < len; i++) {
12341 VALUE lv = RARRAY_AREF(locals, i);
12342
12343 if (sym_arg_rest == lv) {
12344 tbl[i] = 0;
12345 }
12346 else {
12347 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12348 }
12349 }
12350
12351#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12352 if (INT_PARAM(lead_num)) {
12353 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12354 }
12355 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12356 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12357 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12358 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12359#undef INT_PARAM
12360 {
12361#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12362 int x;
12363 INT_PARAM(arg_size);
12364 INT_PARAM(local_size);
12365 INT_PARAM(stack_max);
12366#undef INT_PARAM
12367 }
12368
12369 VALUE node_ids = Qfalse;
12370#ifdef USE_ISEQ_NODE_ID
12371 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12372 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12373 rb_raise(rb_eTypeError, "node_ids is not an array");
12374 }
12375#endif
12376
12377 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12378 len = RARRAY_LENINT(arg_opt_labels);
12379 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12380
12381 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12382 VALUE *opt_table = ALLOC_N(VALUE, len);
12383
12384 for (i = 0; i < len; i++) {
12385 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12386 LABEL *label = register_label(iseq, labels_table, ent);
12387 opt_table[i] = (VALUE)label;
12388 }
12389
12390 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12391 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12392 }
12393 }
12394 else if (!NIL_P(arg_opt_labels)) {
12395 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12396 arg_opt_labels);
12397 }
12398
12399 if (RB_TYPE_P(keywords, T_ARRAY)) {
12400 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12401 }
12402 else if (!NIL_P(keywords)) {
12403 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12404 keywords);
12405 }
12406
12407 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12408 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12409 }
12410
12411 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12412 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12413 }
12414
12415 if (int_param(&i, params, SYM(kwrest))) {
12416 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12417 if (keyword == NULL) {
12418 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12419 }
12420 keyword->rest_start = i;
12421 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12422 }
12423#undef SYM
12424 iseq_calc_param_size(iseq);
12425
12426 /* exception */
12427 iseq_build_from_ary_exception(iseq, labels_table, exception);
12428
12429 /* body */
12430 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12431
12432 ISEQ_BODY(iseq)->param.size = arg_size;
12433 ISEQ_BODY(iseq)->local_table_size = local_size;
12434 ISEQ_BODY(iseq)->stack_max = stack_max;
12435}
12436
12437/* for parser */
12438
12439int
12440rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12441{
12442 if (iseq) {
12443 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12444 while (body->type == ISEQ_TYPE_BLOCK ||
12445 body->type == ISEQ_TYPE_RESCUE ||
12446 body->type == ISEQ_TYPE_ENSURE ||
12447 body->type == ISEQ_TYPE_EVAL ||
12448 body->type == ISEQ_TYPE_MAIN
12449 ) {
12450 unsigned int i;
12451
12452 for (i = 0; i < body->local_table_size; i++) {
12453 if (body->local_table[i] == id) {
12454 return 1;
12455 }
12456 }
12457 iseq = body->parent_iseq;
12458 body = ISEQ_BODY(iseq);
12459 }
12460 }
12461 return 0;
12462}
12463
12464int
12465rb_local_defined(ID id, const rb_iseq_t *iseq)
12466{
12467 if (iseq) {
12468 unsigned int i;
12469 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12470
12471 for (i=0; i<body->local_table_size; i++) {
12472 if (body->local_table[i] == id) {
12473 return 1;
12474 }
12475 }
12476 }
12477 return 0;
12478}
12479
12480/* ISeq binary format */
12481
12482#ifndef IBF_ISEQ_DEBUG
12483#define IBF_ISEQ_DEBUG 0
12484#endif
12485
12486#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12487#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12488#endif
12489
12490typedef uint32_t ibf_offset_t;
12491#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12492
12493#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12494#ifdef RUBY_DEVEL
12495#define IBF_DEVEL_VERSION 5
12496#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12497#else
12498#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12499#endif
12500
12501static const char IBF_ENDIAN_MARK =
12502#ifdef WORDS_BIGENDIAN
12503 'b'
12504#else
12505 'l'
12506#endif
12507 ;
12508
12509 struct ibf_header {
12510 char magic[4]; /* YARB */
12511 uint32_t major_version;
12512 uint32_t minor_version;
12513 uint32_t size;
12514 uint32_t extra_size;
12515
12516 uint32_t iseq_list_size;
12517 uint32_t global_object_list_size;
12518 ibf_offset_t iseq_list_offset;
12519 ibf_offset_t global_object_list_offset;
12520 uint8_t endian;
12521 uint8_t wordsize; /* assume no 2048-bit CPU */
12522};
12523
12524 struct ibf_dump_buffer {
12525 VALUE str;
12526 st_table *obj_table; /* obj -> obj number */
12527};
12528
12529 struct ibf_dump {
12530 st_table *iseq_table; /* iseq -> iseq number */
12531 struct ibf_dump_buffer global_buffer;
12532 struct ibf_dump_buffer *current_buffer;
12533};
12534
12535 struct ibf_load_buffer {
12536 const char *buff;
12537 ibf_offset_t size;
12538
12539 VALUE obj_list; /* [obj0, ...] */
12540 unsigned int obj_list_size;
12541 ibf_offset_t obj_list_offset;
12542};
12543
12544 struct ibf_load {
12545 const struct ibf_header *header;
12546 VALUE iseq_list; /* [iseq0, ...] */
12547 struct ibf_load_buffer global_buffer;
12548 VALUE loader_obj;
12549 rb_iseq_t *iseq;
12550 VALUE str;
12551 struct ibf_load_buffer *current_buffer;
12552};
12553
12554 struct pinned_list {
12555 long size;
12556 VALUE buffer[1];
12557};
12558
12559static void
12560pinned_list_mark(void *ptr)
12561{
12562 long i;
12563 struct pinned_list *list = (struct pinned_list *)ptr;
12564 for (i = 0; i < list->size; i++) {
12565 if (list->buffer[i]) {
12566 rb_gc_mark(list->buffer[i]);
12567 }
12568 }
12569}
12570
12571static const rb_data_type_t pinned_list_type = {
12572 "pinned_list",
12573 {
12574 pinned_list_mark,
12575 RUBY_DEFAULT_FREE,
12576 NULL, // No external memory to report,
12577 },
12578 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
12579};
12580
12581static VALUE
12582pinned_list_fetch(VALUE list, long offset)
12583{
12584 struct pinned_list * ptr;
12585
12586 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12587
12588 if (offset >= ptr->size) {
12589 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12590 }
12591
12592 return ptr->buffer[offset];
12593}
12594
12595static void
12596pinned_list_store(VALUE list, long offset, VALUE object)
12597{
12598 struct pinned_list * ptr;
12599
12600 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12601
12602 if (offset >= ptr->size) {
12603 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12604 }
12605
12606 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12607}
12608
12609static VALUE
12610pinned_list_new(long size)
12611{
12612 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12613 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12614 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12615 ptr->size = size;
12616 return obj_list;
12617}
12618
12619static ibf_offset_t
12620ibf_dump_pos(struct ibf_dump *dump)
12621{
12622 long pos = RSTRING_LEN(dump->current_buffer->str);
12623#if SIZEOF_LONG > SIZEOF_INT
12624 if (pos >= UINT_MAX) {
12625 rb_raise(rb_eRuntimeError, "dump size exceeds");
12626 }
12627#endif
12628 return (unsigned int)pos;
12629}
12630
12631static void
12632ibf_dump_align(struct ibf_dump *dump, size_t align)
12633{
12634 ibf_offset_t pos = ibf_dump_pos(dump);
12635 if (pos % align) {
12636 static const char padding[sizeof(VALUE)];
12637 size_t size = align - ((size_t)pos % align);
12638#if SIZEOF_LONG > SIZEOF_INT
12639 if (pos + size >= UINT_MAX) {
12640 rb_raise(rb_eRuntimeError, "dump size exceeds");
12641 }
12642#endif
12643 for (; size > sizeof(padding); size -= sizeof(padding)) {
12644 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12645 }
12646 rb_str_cat(dump->current_buffer->str, padding, size);
12647 }
12648}
12649
12650static ibf_offset_t
12651ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12652{
12653 ibf_offset_t pos = ibf_dump_pos(dump);
12654#if SIZEOF_LONG > SIZEOF_INT
12655 /* ensure the resulting dump does not exceed UINT_MAX */
12656 if (size >= UINT_MAX || pos + size >= UINT_MAX) {
12657 rb_raise(rb_eRuntimeError, "dump size exceeds");
12658 }
12659#endif
12660 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12661 return pos;
12662}
12663
12664static ibf_offset_t
12665ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12666{
12667 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12668}
12669
12670static void
12671ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12672{
12673 VALUE str = dump->current_buffer->str;
12674 char *ptr = RSTRING_PTR(str);
12675 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12676 rb_bug("ibf_dump_overwrite: overflow");
12677 memcpy(ptr + offset, buff, size);
12678}
12679
12680static const void *
12681ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12682{
12683 ibf_offset_t beg = *offset;
12684 *offset += size;
12685 return load->current_buffer->buff + beg;
12686}
12687
12688static void *
12689ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12690{
12691 void *buff = ruby_xmalloc2(x, y);
12692 size_t size = x * y;
12693 memcpy(buff, load->current_buffer->buff + offset, size);
12694 return buff;
12695}
12696
12697#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12698
12699#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12700#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12701#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12702#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12703#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12704
12705static int
12706ibf_table_lookup(struct st_table *table, st_data_t key)
12707{
12708 st_data_t val;
12709
12710 if (st_lookup(table, key, &val)) {
12711 return (int)val;
12712 }
12713 else {
12714 return -1;
12715 }
12716}
12717
12718static int
12719ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12720{
12721 int index = ibf_table_lookup(table, key);
12722
12723 if (index < 0) { /* not found */
12724 index = (int)table->num_entries;
12725 st_insert(table, key, (st_data_t)index);
12726 }
12727
12728 return index;
12729}
12730
12731/* dump/load generic */
12732
12733static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
12734
12735static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
12736static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
12737
12738static st_table *
12739ibf_dump_object_table_new(void)
12740{
12741 st_table *obj_table = st_init_numtable(); /* need free */
12742 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
12743
12744 return obj_table;
12745}
12746
12747static VALUE
12748ibf_dump_object(struct ibf_dump *dump, VALUE obj)
12749{
12750 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12751}
12752
12753static VALUE
12754ibf_dump_id(struct ibf_dump *dump, ID id)
12755{
12756 if (id == 0 || rb_id2name(id) == NULL) {
12757 return 0;
12758 }
12759 return ibf_dump_object(dump, rb_id2sym(id));
12760}
12761
12762static ID
12763ibf_load_id(const struct ibf_load *load, const ID id_index)
12764{
12765 if (id_index == 0) {
12766 return 0;
12767 }
12768 VALUE sym = ibf_load_object(load, id_index);
12769 if (rb_integer_type_p(sym)) {
12770 /* Load hidden local variables as indexes */
12771 return NUM2ULONG(sym);
12772 }
12773 return rb_sym2id(sym);
12774}
12775
12776/* dump/load: code */
12777
12778static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
12779
12780static int
12781ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
12782{
12783 if (iseq == NULL) {
12784 return -1;
12785 }
12786 else {
12787 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
12788 }
12789}
12790
12791static unsigned char
12792ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
12793{
12794 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
12795 return (unsigned char)load->current_buffer->buff[(*offset)++];
12796}
12797
12798/*
12799 * Small uint serialization
12800 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
12801 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
12802 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
12803 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12804 * ...
12805 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12806 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12807 */
12808static void
12809ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
12810{
12811 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12812 ibf_dump_write(dump, &x, sizeof(VALUE));
12813 return;
12814 }
12815
12816 enum { max_byte_length = sizeof(VALUE) + 1 };
12817
12818 unsigned char bytes[max_byte_length];
12819 ibf_offset_t n;
12820
12821 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
12822 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12823 }
12824
12825 x <<= 1;
12826 x |= 1;
12827 x <<= n;
12828 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12829 n++;
12830
12831 ibf_dump_write(dump, bytes + max_byte_length - n, n);
12832}
12833
12834static VALUE
12835ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
12836{
12837 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12838 union { char s[sizeof(VALUE)]; VALUE v; } x;
12839
12840 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
12841 *offset += sizeof(VALUE);
12842
12843 return x.v;
12844 }
12845
12846 enum { max_byte_length = sizeof(VALUE) + 1 };
12847
12848 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
12849 const unsigned char c = buffer[*offset];
12850
12851 ibf_offset_t n =
12852 c & 1 ? 1 :
12853 c == 0 ? 9 : ntz_int32(c) + 1;
12854 VALUE x = (VALUE)c >> n;
12855
12856 if (*offset + n > load->current_buffer->size) {
12857 rb_raise(rb_eRuntimeError, "invalid byte sequence");
12858 }
12859
12860 ibf_offset_t i;
12861 for (i = 1; i < n; i++) {
12862 x <<= 8;
12863 x |= (VALUE)buffer[*offset + i];
12864 }
12865
12866 *offset += n;
12867 return x;
12868}
12869
12870static void
12871ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
12872{
12873 // short: index
12874 // short: name.length
12875 // bytes: name
12876 // // omit argc (only verify with name)
12877 ibf_dump_write_small_value(dump, (VALUE)bf->index);
12878
12879 size_t len = strlen(bf->name);
12880 ibf_dump_write_small_value(dump, (VALUE)len);
12881 ibf_dump_write(dump, bf->name, len);
12882}
12883
12884static const struct rb_builtin_function *
12885ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
12886{
12887 int i = (int)ibf_load_small_value(load, offset);
12888 int len = (int)ibf_load_small_value(load, offset);
12889 const char *name = (char *)ibf_load_ptr(load, offset, len);
12890
12891 if (0) {
12892 fprintf(stderr, "%.*s!!\n", len, name);
12893 }
12894
12895 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
12896 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
12897 if (strncmp(table[i].name, name, len) != 0) {
12898 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
12899 }
12900 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
12901
12902 return &table[i];
12903}
12904
12905static ibf_offset_t
12906ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
12907{
12908 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12909 const int iseq_size = body->iseq_size;
12910 int code_index;
12911 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
12912
12913 ibf_offset_t offset = ibf_dump_pos(dump);
12914
12915 for (code_index=0; code_index<iseq_size;) {
12916 const VALUE insn = orig_code[code_index++];
12917 const char *types = insn_op_types(insn);
12918 int op_index;
12919
12920 /* opcode */
12921 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
12922 ibf_dump_write_small_value(dump, insn);
12923
12924 /* operands */
12925 for (op_index=0; types[op_index]; op_index++, code_index++) {
12926 VALUE op = orig_code[code_index];
12927 VALUE wv;
12928
12929 switch (types[op_index]) {
12930 case TS_CDHASH:
12931 case TS_VALUE:
12932 wv = ibf_dump_object(dump, op);
12933 break;
12934 case TS_ISEQ:
12935 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
12936 break;
12937 case TS_IC:
12938 {
12939 IC ic = (IC)op;
12940 VALUE arr = idlist_to_array(ic->segments);
12941 wv = ibf_dump_object(dump, arr);
12942 }
12943 break;
12944 case TS_ISE:
12945 case TS_IVC:
12946 case TS_ICVARC:
12947 {
12948 union iseq_inline_storage_entry *is = (union iseq_inline_storage_entry *)op;
12949 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
12950 }
12951 break;
12952 case TS_CALLDATA:
12953 {
12954 goto skip_wv;
12955 }
12956 case TS_ID:
12957 wv = ibf_dump_id(dump, (ID)op);
12958 break;
12959 case TS_FUNCPTR:
12960 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12961 goto skip_wv;
12962 case TS_BUILTIN:
12963 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
12964 goto skip_wv;
12965 default:
12966 wv = op;
12967 break;
12968 }
12969 ibf_dump_write_small_value(dump, wv);
12970 skip_wv:;
12971 }
12972 RUBY_ASSERT(insn_len(insn) == op_index+1);
12973 }
12974
12975 return offset;
12976}
12977
12978static VALUE *
12979ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecode_offset, ibf_offset_t bytecode_size, unsigned int iseq_size)
12980{
12981 VALUE iseqv = (VALUE)iseq;
12982 unsigned int code_index;
12983 ibf_offset_t reading_pos = bytecode_offset;
12984 VALUE *code = ALLOC_N(VALUE, iseq_size);
12985
12986 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
12987 struct rb_call_data *cd_entries = load_body->call_data;
12988 int ic_index = 0;
12989
12990 load_body->iseq_encoded = code;
12991 load_body->iseq_size = 0;
12992
12993 iseq_bits_t * mark_offset_bits;
12994
12995 iseq_bits_t tmp[1] = {0};
12996
12997 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
12998 mark_offset_bits = tmp;
12999 }
13000 else {
13001 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
13002 }
13003 bool needs_bitmap = false;
13004
13005 for (code_index=0; code_index<iseq_size;) {
13006 /* opcode */
13007 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
13008 const char *types = insn_op_types(insn);
13009 int op_index;
13010
13011 code_index++;
13012
13013 /* operands */
13014 for (op_index=0; types[op_index]; op_index++, code_index++) {
13015 const char operand_type = types[op_index];
13016 switch (operand_type) {
13017 case TS_VALUE:
13018 {
13019 VALUE op = ibf_load_small_value(load, &reading_pos);
13020 VALUE v = ibf_load_object(load, op);
13021 code[code_index] = v;
13022 if (!SPECIAL_CONST_P(v)) {
13023 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13024 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13025 needs_bitmap = true;
13026 }
13027 break;
13028 }
13029 case TS_CDHASH:
13030 {
13031 VALUE op = ibf_load_small_value(load, &reading_pos);
13032 VALUE v = ibf_load_object(load, op);
13033 v = rb_hash_dup(v); // hash dumped as frozen
13034 RHASH_TBL_RAW(v)->type = &cdhash_type;
13035 rb_hash_rehash(v); // hash function changed
13036 RB_OBJ_SET_SHAREABLE(freeze_hide_obj(v));
13037
13038 // Overwrite the existing hash in the object list. This
13039 // is to keep the object alive during load time.
13040 // [Bug #17984] [ruby-core:104259]
13041 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
13042
13043 code[code_index] = v;
13044 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13045 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13046 needs_bitmap = true;
13047 break;
13048 }
13049 case TS_ISEQ:
13050 {
13051 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
13052 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
13053 code[code_index] = v;
13054 if (!SPECIAL_CONST_P(v)) {
13055 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13056 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13057 needs_bitmap = true;
13058 }
13059 break;
13060 }
13061 case TS_IC:
13062 {
13063 VALUE op = ibf_load_small_value(load, &reading_pos);
13064 VALUE arr = ibf_load_object(load, op);
13065
13066 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
13067 ic->segments = array_to_idlist(arr);
13068
13069 code[code_index] = (VALUE)ic;
13070 }
13071 break;
13072 case TS_ISE:
13073 case TS_ICVARC:
13074 case TS_IVC:
13075 {
13076 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
13077
13078 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
13079 code[code_index] = (VALUE)ic;
13080
13081 if (operand_type == TS_IVC) {
13082 IVC cache = (IVC)ic;
13083
13084 if (insn == BIN(setinstancevariable)) {
13085 ID iv_name = (ID)code[code_index - 1];
13086 cache->iv_set_name = iv_name;
13087 }
13088 else {
13089 cache->iv_set_name = 0;
13090 }
13091
13092 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
13093 }
13094
13095 }
13096 break;
13097 case TS_CALLDATA:
13098 {
13099 code[code_index] = (VALUE)cd_entries++;
13100 }
13101 break;
13102 case TS_ID:
13103 {
13104 VALUE op = ibf_load_small_value(load, &reading_pos);
13105 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
13106 }
13107 break;
13108 case TS_FUNCPTR:
13109 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13110 break;
13111 case TS_BUILTIN:
13112 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
13113 break;
13114 default:
13115 code[code_index] = ibf_load_small_value(load, &reading_pos);
13116 continue;
13117 }
13118 }
13119 if (insn_len(insn) != op_index+1) {
13120 rb_raise(rb_eRuntimeError, "operand size mismatch");
13121 }
13122 }
13123
13124 load_body->iseq_size = code_index;
13125
13126 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
13127 load_body->mark_bits.single = mark_offset_bits[0];
13128 }
13129 else {
13130 if (needs_bitmap) {
13131 load_body->mark_bits.list = mark_offset_bits;
13132 }
13133 else {
13134 load_body->mark_bits.list = 0;
13135 ruby_xfree(mark_offset_bits);
13136 }
13137 }
13138
13139 RUBY_ASSERT(code_index == iseq_size);
13140 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
13141 return code;
13142}
13143
13144static ibf_offset_t
13145ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13146{
13147 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
13148
13149 if (opt_num > 0) {
13150 IBF_W_ALIGN(VALUE);
13151 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
13152 }
13153 else {
13154 return ibf_dump_pos(dump);
13155 }
13156}
13157
13158static VALUE *
13159ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
13160{
13161 if (opt_num > 0) {
13162 VALUE *table = ALLOC_N(VALUE, opt_num+1);
13163 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
13164 return table;
13165 }
13166 else {
13167 return NULL;
13168 }
13169}
13170
13171static ibf_offset_t
13172ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
13173{
13174 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
13175
13176 if (kw) {
13177 struct rb_iseq_param_keyword dump_kw = *kw;
13178 int dv_num = kw->num - kw->required_num;
13179 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
13180 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
13181 int i;
13182
13183 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
13184 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
13185
13186 dump_kw.table = IBF_W(ids, ID, kw->num);
13187 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
13188 IBF_W_ALIGN(struct rb_iseq_param_keyword);
13189 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
13190 }
13191 else {
13192 return 0;
13193 }
13194}
13195
13196static const struct rb_iseq_param_keyword *
13197ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13198{
13199 if (param_keyword_offset) {
13200 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
13201 int dv_num = kw->num - kw->required_num;
13202 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
13203
13204 int i;
13205 for (i=0; i<dv_num; i++) {
13206 dvs[i] = ibf_load_object(load, dvs[i]);
13207 }
13208
13209 // Will be set once the local table is loaded.
13210 kw->table = NULL;
13211
13212 kw->default_values = dvs;
13213 return kw;
13214 }
13215 else {
13216 return NULL;
13217 }
13218}
13219
13220static ibf_offset_t
13221ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13222{
13223 ibf_offset_t offset = ibf_dump_pos(dump);
13224 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13225
13226 unsigned int i;
13227 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13228 ibf_dump_write_small_value(dump, entries[i].line_no);
13229#ifdef USE_ISEQ_NODE_ID
13230 ibf_dump_write_small_value(dump, entries[i].node_id);
13231#endif
13232 ibf_dump_write_small_value(dump, entries[i].events);
13233 }
13234
13235 return offset;
13236}
13237
13238static struct iseq_insn_info_entry *
13239ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13240{
13241 ibf_offset_t reading_pos = body_offset;
13242 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13243
13244 unsigned int i;
13245 for (i = 0; i < size; i++) {
13246 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13247#ifdef USE_ISEQ_NODE_ID
13248 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13249#endif
13250 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13251 }
13252
13253 return entries;
13254}
13255
13256static ibf_offset_t
13257ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13258{
13259 ibf_offset_t offset = ibf_dump_pos(dump);
13260
13261 unsigned int last = 0;
13262 unsigned int i;
13263 for (i = 0; i < size; i++) {
13264 ibf_dump_write_small_value(dump, positions[i] - last);
13265 last = positions[i];
13266 }
13267
13268 return offset;
13269}
13270
13271static unsigned int *
13272ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13273{
13274 ibf_offset_t reading_pos = positions_offset;
13275 unsigned int *positions = ALLOC_N(unsigned int, size);
13276
13277 unsigned int last = 0;
13278 unsigned int i;
13279 for (i = 0; i < size; i++) {
13280 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13281 last = positions[i];
13282 }
13283
13284 return positions;
13285}
13286
13287static ibf_offset_t
13288ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13289{
13290 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13291 const int size = body->local_table_size;
13292 ID *table = ALLOCA_N(ID, size);
13293 int i;
13294
13295 for (i=0; i<size; i++) {
13296 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13297 if (v == 0) {
13298 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13299 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13300 }
13301 table[i] = v;
13302 }
13303
13304 IBF_W_ALIGN(ID);
13305 return ibf_dump_write(dump, table, sizeof(ID) * size);
13306}
13307
13308static const ID *
13309ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13310{
13311 if (size > 0) {
13312 ID *table = IBF_R(local_table_offset, ID, size);
13313 int i;
13314
13315 for (i=0; i<size; i++) {
13316 table[i] = ibf_load_id(load, table[i]);
13317 }
13318
13319 if (size == 1 && table[0] == idERROR_INFO) {
13320 xfree(table);
13321 return rb_iseq_shared_exc_local_tbl;
13322 }
13323 else {
13324 return table;
13325 }
13326 }
13327 else {
13328 return NULL;
13329 }
13330}
13331
13332static ibf_offset_t
13333ibf_dump_lvar_states(struct ibf_dump *dump, const rb_iseq_t *iseq)
13334{
13335 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13336 const int size = body->local_table_size;
13337 IBF_W_ALIGN(enum lvar_state);
13338 return ibf_dump_write(dump, body->lvar_states, sizeof(enum lvar_state) * (body->lvar_states ? size : 0));
13339}
13340
13341static enum lvar_state *
13342ibf_load_lvar_states(const struct ibf_load *load, ibf_offset_t lvar_states_offset, int size, const ID *local_table)
13343{
13344 if (local_table == rb_iseq_shared_exc_local_tbl ||
13345 size <= 0) {
13346 return NULL;
13347 }
13348 else {
13349 enum lvar_state *states = IBF_R(lvar_states_offset, enum lvar_state, size);
13350 return states;
13351 }
13352}
13353
13354static ibf_offset_t
13355ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13356{
13357 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13358
13359 if (table) {
13360 int *iseq_indices = ALLOCA_N(int, table->size);
13361 unsigned int i;
13362
13363 for (i=0; i<table->size; i++) {
13364 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13365 }
13366
13367 const ibf_offset_t offset = ibf_dump_pos(dump);
13368
13369 for (i=0; i<table->size; i++) {
13370 ibf_dump_write_small_value(dump, iseq_indices[i]);
13371 ibf_dump_write_small_value(dump, table->entries[i].type);
13372 ibf_dump_write_small_value(dump, table->entries[i].start);
13373 ibf_dump_write_small_value(dump, table->entries[i].end);
13374 ibf_dump_write_small_value(dump, table->entries[i].cont);
13375 ibf_dump_write_small_value(dump, table->entries[i].sp);
13376 }
13377 return offset;
13378 }
13379 else {
13380 return ibf_dump_pos(dump);
13381 }
13382}
13383
13384static void
13385ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size, const rb_iseq_t *parent_iseq)
13386{
13387 if (size) {
13388 struct iseq_catch_table *table = ruby_xcalloc(1, iseq_catch_table_bytes(size));
13389 table->size = size;
13390 ISEQ_BODY(parent_iseq)->catch_table = table;
13391
13392 ibf_offset_t reading_pos = catch_table_offset;
13393
13394 unsigned int i;
13395 for (i=0; i<table->size; i++) {
13396 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13397 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13398 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13399 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13400 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13401 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13402
13403 rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13404 RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
13405 }
13406 }
13407 else {
13408 ISEQ_BODY(parent_iseq)->catch_table = NULL;
13409 }
13410}
13411
13412static ibf_offset_t
13413ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13414{
13415 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13416 const unsigned int ci_size = body->ci_size;
13417 const struct rb_call_data *cds = body->call_data;
13418
13419 ibf_offset_t offset = ibf_dump_pos(dump);
13420
13421 unsigned int i;
13422
13423 for (i = 0; i < ci_size; i++) {
13424 const struct rb_callinfo *ci = cds[i].ci;
13425 if (ci != NULL) {
13426 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13427 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13428 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13429
13430 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13431 if (kwarg) {
13432 int len = kwarg->keyword_len;
13433 ibf_dump_write_small_value(dump, len);
13434 for (int j=0; j<len; j++) {
13435 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13436 ibf_dump_write_small_value(dump, keyword);
13437 }
13438 }
13439 else {
13440 ibf_dump_write_small_value(dump, 0);
13441 }
13442 }
13443 else {
13444 // TODO: truncate NULL ci from call_data.
13445 ibf_dump_write_small_value(dump, (VALUE)-1);
13446 }
13447 }
13448
13449 return offset;
13450}
13451
13452 struct outer_variable_pair {
13453 ID id;
13454 VALUE name;
13455 VALUE val;
13456};
13457
13458 struct outer_variable_list {
13459 size_t num;
13460 struct outer_variable_pair pairs[1];
13461};
13462
13463static enum rb_id_table_iterator_result
13464store_outer_variable(ID id, VALUE val, void *dump)
13465{
13466 struct outer_variable_list *ovlist = dump;
13467 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13468 pair->id = id;
13469 pair->name = rb_id2str(id);
13470 pair->val = val;
13471 return ID_TABLE_CONTINUE;
13472}
13473
13474static int
13475outer_variable_cmp(const void *a, const void *b, void *arg)
13476{
13477 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13478 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13479
13480 if (!ap->name) {
13481 return -1;
13482 }
13483 else if (!bp->name) {
13484 return 1;
13485 }
13486
13487 return rb_str_cmp(ap->name, bp->name);
13488}
13489
13490static ibf_offset_t
13491ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13492{
13493 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13494
13495 ibf_offset_t offset = ibf_dump_pos(dump);
13496
13497 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13498 ibf_dump_write_small_value(dump, (VALUE)size);
13499 if (size > 0) {
13500 VALUE buff;
13501 size_t buffsize =
13502 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13503 offsetof(struct outer_variable_list, pairs),
13504 rb_eArgError);
13505 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13506 ovlist->num = 0;
13507 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13508 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13509 for (size_t i = 0; i < size; ++i) {
13510 ID id = ovlist->pairs[i].id;
13511 ID val = ovlist->pairs[i].val;
13512 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13513 ibf_dump_write_small_value(dump, val);
13514 }
13515 }
13516
13517 return offset;
13518}
13519
13520/* note that we dump out rb_call_info but load back rb_call_data */
13521static void
13522ibf_load_ci_entries(const struct ibf_load *load,
13523 ibf_offset_t ci_entries_offset,
13524 unsigned int ci_size,
13525 struct rb_call_data **cd_ptr)
13526{
13527 if (!ci_size) {
13528 *cd_ptr = NULL;
13529 return;
13530 }
13531
13532 ibf_offset_t reading_pos = ci_entries_offset;
13533
13534 unsigned int i;
13535
13536 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13537 *cd_ptr = cds;
13538
13539 for (i = 0; i < ci_size; i++) {
13540 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13541 if (mid_index != (VALUE)-1) {
13542 ID mid = ibf_load_id(load, mid_index);
13543 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13544 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13545
13546 struct rb_callinfo_kwarg *kwarg = NULL;
13547 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13548 if (kwlen > 0) {
13549 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13550 kwarg->references = 0;
13551 kwarg->keyword_len = kwlen;
13552 for (int j=0; j<kwlen; j++) {
13553 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13554 kwarg->keywords[j] = ibf_load_object(load, keyword);
13555 }
13556 }
13557
13558 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13559 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13560 cds[i].cc = vm_cc_empty();
13561 }
13562 else {
13563 // NULL ci
13564 cds[i].ci = NULL;
13565 cds[i].cc = NULL;
13566 }
13567 }
13568}
13569
13570static struct rb_id_table *
13571ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13572{
13573 ibf_offset_t reading_pos = outer_variables_offset;
13574
13575 struct rb_id_table *tbl = NULL;
13576
13577 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13578
13579 if (table_size > 0) {
13580 tbl = rb_id_table_create(table_size);
13581 }
13582
13583 for (size_t i = 0; i < table_size; i++) {
13584 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13585 VALUE value = ibf_load_small_value(load, &reading_pos);
13586 if (!key) key = rb_make_temporary_id(i);
13587 rb_id_table_insert(tbl, key, value);
13588 }
13589
13590 return tbl;
13591}
13592
13593static ibf_offset_t
13594ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13595{
13596 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13597
13598 unsigned int *positions;
13599
13600 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13601
13602 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13603 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
13604 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13605
13606#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13607 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13608
13609 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13610 struct ibf_dump_buffer buffer;
13611 buffer.str = rb_str_new(0, 0);
13612 buffer.obj_table = ibf_dump_object_table_new();
13613 dump->current_buffer = &buffer;
13614#endif
13615
13616 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13617 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13618 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13619 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13620 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13621
13622 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13623 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13624 ruby_xfree(positions);
13625
13626 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13627 const ibf_offset_t lvar_states_offset = ibf_dump_lvar_states(dump, iseq);
13628 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13629 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13630 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
13631 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
13632 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13633 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13634 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13635
13636#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13637 ibf_offset_t local_obj_list_offset;
13638 unsigned int local_obj_list_size;
13639
13640 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13641#endif
13642
13643 ibf_offset_t body_offset = ibf_dump_pos(dump);
13644
13645 /* dump the constant body */
13646 unsigned int param_flags =
13647 (body->param.flags.has_lead << 0) |
13648 (body->param.flags.has_opt << 1) |
13649 (body->param.flags.has_rest << 2) |
13650 (body->param.flags.has_post << 3) |
13651 (body->param.flags.has_kw << 4) |
13652 (body->param.flags.has_kwrest << 5) |
13653 (body->param.flags.has_block << 6) |
13654 (body->param.flags.ambiguous_param0 << 7) |
13655 (body->param.flags.accepts_no_kwarg << 8) |
13656 (body->param.flags.ruby2_keywords << 9) |
13657 (body->param.flags.anon_rest << 10) |
13658 (body->param.flags.anon_kwrest << 11) |
13659 (body->param.flags.use_block << 12) |
13660 (body->param.flags.forwardable << 13) ;
13661
13662#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13663# define IBF_BODY_OFFSET(x) (x)
13664#else
13665# define IBF_BODY_OFFSET(x) (body_offset - (x))
13666#endif
13667
13668 ibf_dump_write_small_value(dump, body->type);
13669 ibf_dump_write_small_value(dump, body->iseq_size);
13670 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13671 ibf_dump_write_small_value(dump, bytecode_size);
13672 ibf_dump_write_small_value(dump, param_flags);
13673 ibf_dump_write_small_value(dump, body->param.size);
13674 ibf_dump_write_small_value(dump, body->param.lead_num);
13675 ibf_dump_write_small_value(dump, body->param.opt_num);
13676 ibf_dump_write_small_value(dump, body->param.rest_start);
13677 ibf_dump_write_small_value(dump, body->param.post_start);
13678 ibf_dump_write_small_value(dump, body->param.post_num);
13679 ibf_dump_write_small_value(dump, body->param.block_start);
13680 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13681 ibf_dump_write_small_value(dump, param_keyword_offset);
13682 ibf_dump_write_small_value(dump, location_pathobj_index);
13683 ibf_dump_write_small_value(dump, location_base_label_index);
13684 ibf_dump_write_small_value(dump, location_label_index);
13685 ibf_dump_write_small_value(dump, body->location.first_lineno);
13686 ibf_dump_write_small_value(dump, body->location.node_id);
13687 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13688 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13689 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13690 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13691 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13692 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13693 ibf_dump_write_small_value(dump, body->insns_info.size);
13694 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13695 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(lvar_states_offset));
13696 ibf_dump_write_small_value(dump, catch_table_size);
13697 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13698 ibf_dump_write_small_value(dump, parent_iseq_index);
13699 ibf_dump_write_small_value(dump, local_iseq_index);
13700 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13701 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13702 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13703 ibf_dump_write_small_value(dump, body->variable.flip_count);
13704 ibf_dump_write_small_value(dump, body->local_table_size);
13705 ibf_dump_write_small_value(dump, body->ivc_size);
13706 ibf_dump_write_small_value(dump, body->icvarc_size);
13707 ibf_dump_write_small_value(dump, body->ise_size);
13708 ibf_dump_write_small_value(dump, body->ic_size);
13709 ibf_dump_write_small_value(dump, body->ci_size);
13710 ibf_dump_write_small_value(dump, body->stack_max);
13711 ibf_dump_write_small_value(dump, body->builtin_attrs);
13712 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13713
13714#undef IBF_BODY_OFFSET
13715
13716#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13717 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13718
13719 dump->current_buffer = saved_buffer;
13720 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13721
13722 ibf_offset_t offset = ibf_dump_pos(dump);
13723 ibf_dump_write_small_value(dump, iseq_start);
13724 ibf_dump_write_small_value(dump, iseq_length_bytes);
13725 ibf_dump_write_small_value(dump, body_offset);
13726
13727 ibf_dump_write_small_value(dump, local_obj_list_offset);
13728 ibf_dump_write_small_value(dump, local_obj_list_size);
13729
13730 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
13731
13732 return offset;
13733#else
13734 return body_offset;
13735#endif
13736}
13737
13738static VALUE
13739ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
13740{
13741 VALUE str = ibf_load_object(load, str_index);
13742 if (str != Qnil) {
13743 str = rb_fstring(str);
13744 }
13745 return str;
13746}
13747
13748static void
13749ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13750{
13751 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
13752
13753 ibf_offset_t reading_pos = offset;
13754
13755#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13756 struct ibf_load_buffer *saved_buffer = load->current_buffer;
13757 load->current_buffer = &load->global_buffer;
13758
13759 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13760 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13761 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13762
13763 struct ibf_load_buffer buffer;
13764 buffer.buff = load->global_buffer.buff + iseq_start;
13765 buffer.size = iseq_length_bytes;
13766 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13767 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13768 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13769
13770 load->current_buffer = &buffer;
13771 reading_pos = body_offset;
13772#endif
13773
13774#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13775# define IBF_BODY_OFFSET(x) (x)
13776#else
13777# define IBF_BODY_OFFSET(x) (offset - (x))
13778#endif
13779
13780 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
13781 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13782 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13783 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13784 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
13785 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13786 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
13787 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
13788 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
13789 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
13790 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
13791 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
13792 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13793 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13794 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
13795 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
13796 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
13797 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
13798 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
13799 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13800 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13801 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13802 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13803 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13804 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13805 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13806 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13807 const ibf_offset_t lvar_states_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13808 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13809 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13810 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13811 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13812 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13813 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13814 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13815 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
13816 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13817
13818 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13819 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13820 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13821 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13822
13823 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13824 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
13825 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
13826 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
13827
13828 // setup fname and dummy frame
13829 VALUE path = ibf_load_object(load, location_pathobj_index);
13830 {
13831 VALUE realpath = Qnil;
13832
13833 if (RB_TYPE_P(path, T_STRING)) {
13834 realpath = path = rb_fstring(path);
13835 }
13836 else if (RB_TYPE_P(path, T_ARRAY)) {
13837 VALUE pathobj = path;
13838 if (RARRAY_LEN(pathobj) != 2) {
13839 rb_raise(rb_eRuntimeError, "path object size mismatch");
13840 }
13841 path = rb_fstring(RARRAY_AREF(pathobj, 0));
13842 realpath = RARRAY_AREF(pathobj, 1);
13843 if (!NIL_P(realpath)) {
13844 if (!RB_TYPE_P(realpath, T_STRING)) {
13845 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
13846 "(%x), path=%+"PRIsVALUE,
13847 realpath, TYPE(realpath), path);
13848 }
13849 realpath = rb_fstring(realpath);
13850 }
13851 }
13852 else {
13853 rb_raise(rb_eRuntimeError, "unexpected path object");
13854 }
13855 rb_iseq_pathobj_set(iseq, path, realpath);
13856 }
13857
13858 // push dummy frame
13859 rb_execution_context_t *ec = GET_EC();
13860 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
13861
13862#undef IBF_BODY_OFFSET
13863
13864 load_body->type = type;
13865 load_body->stack_max = stack_max;
13866 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
13867 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
13868 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
13869 load_body->param.flags.has_post = (param_flags >> 3) & 1;
13870 load_body->param.flags.has_kw = FALSE;
13871 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
13872 load_body->param.flags.has_block = (param_flags >> 6) & 1;
13873 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
13874 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
13875 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
13876 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
13877 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
13878 load_body->param.flags.use_block = (param_flags >> 12) & 1;
13879 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
13880 load_body->param.size = param_size;
13881 load_body->param.lead_num = param_lead_num;
13882 load_body->param.opt_num = param_opt_num;
13883 load_body->param.rest_start = param_rest_start;
13884 load_body->param.post_start = param_post_start;
13885 load_body->param.post_num = param_post_num;
13886 load_body->param.block_start = param_block_start;
13887 load_body->local_table_size = local_table_size;
13888 load_body->ci_size = ci_size;
13889 load_body->insns_info.size = insns_info_size;
13890
13891 ISEQ_COVERAGE_SET(iseq, Qnil);
13892 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
13893 load_body->variable.flip_count = variable_flip_count;
13894 load_body->variable.script_lines = Qnil;
13895
13896 load_body->location.first_lineno = location_first_lineno;
13897 load_body->location.node_id = location_node_id;
13898 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
13899 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
13900 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
13901 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
13902 load_body->builtin_attrs = builtin_attrs;
13903 load_body->prism = prism;
13904
13905 load_body->ivc_size = ivc_size;
13906 load_body->icvarc_size = icvarc_size;
13907 load_body->ise_size = ise_size;
13908 load_body->ic_size = ic_size;
13909
13910 if (ISEQ_IS_SIZE(load_body)) {
13911 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
13912 }
13913 else {
13914 load_body->is_entries = NULL;
13915 }
13916 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
13917 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
13918 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
13919 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
13920 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
13921 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
13922 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
13923 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
13924 load_body->lvar_states = ibf_load_lvar_states(load, lvar_states_offset, local_table_size, load_body->local_table);
13925 ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
13926
13927 const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
13928 const rb_iseq_t *local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
13929 const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
13930
13931 RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
13932 RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
13933 RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
13934
13935 // This must be done after the local table is loaded.
13936 if (load_body->param.keyword != NULL) {
13937 RUBY_ASSERT(load_body->local_table);
13938 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
13939 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
13940 }
13941
13942 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
13943#if VM_INSN_INFO_TABLE_IMPL == 2
13944 rb_iseq_insns_info_encode_positions(iseq);
13945#endif
13946
13947 rb_iseq_translate_threaded_code(iseq);
13948
13949#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13950 load->current_buffer = &load->global_buffer;
13951#endif
13952
13953 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
13954 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
13955
13956#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13957 load->current_buffer = saved_buffer;
13958#endif
13959 verify_call_cache(iseq);
13960
13961 RB_GC_GUARD(dummy_frame);
13962 rb_vm_pop_frame_no_int(ec);
13963}
13964
13965 struct ibf_dump_iseq_list_arg
13966{
13967 struct ibf_dump *dump;
13968 VALUE offset_list;
13969};
13970
13971static int
13972ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13973{
13974 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
13975 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
13976
13977 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
13978 rb_ary_push(args->offset_list, UINT2NUM(offset));
13979
13980 return ST_CONTINUE;
13981}
13982
13983static void
13984ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
13985{
13986 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
13987
13988 struct ibf_dump_iseq_list_arg args;
13989 args.dump = dump;
13990 args.offset_list = offset_list;
13991
13992 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
13993
13994 st_index_t i;
13995 st_index_t size = dump->iseq_table->num_entries;
13996 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
13997
13998 for (i = 0; i < size; i++) {
13999 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
14000 }
14001
14002 ibf_dump_align(dump, sizeof(ibf_offset_t));
14003 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
14004 header->iseq_list_size = (unsigned int)size;
14005}
14006
14007/*
14008 * Binary format
14009 * - ibf_object_header
14010 * - ibf_object_xxx (xxx is type)
14011 */
14012
14013 struct ibf_object_header {
14014 unsigned int type: 5;
14015 unsigned int special_const: 1;
14016 unsigned int frozen: 1;
14017 unsigned int internal: 1;
14018};
14019
14020enum ibf_object_class_index {
14021 IBF_OBJECT_CLASS_OBJECT,
14022 IBF_OBJECT_CLASS_ARRAY,
14023 IBF_OBJECT_CLASS_STANDARD_ERROR,
14024 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
14025 IBF_OBJECT_CLASS_TYPE_ERROR,
14026 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
14027};
14028
14029 struct ibf_object_regexp {
14030 long srcstr;
14031 char option;
14032};
14033
14034 struct ibf_object_hash {
14035 long len;
14036 long keyval[FLEX_ARY_LEN];
14037};
14038
14039 struct ibf_object_struct_range {
14040 long class_index;
14041 long len;
14042 long beg;
14043 long end;
14044 int excl;
14045};
14046
14047 struct ibf_object_bignum {
14048 ssize_t slen;
14049 BDIGIT digits[FLEX_ARY_LEN];
14050};
14051
14052enum ibf_object_data_type {
14053 IBF_OBJECT_DATA_ENCODING,
14054};
14055
14056 struct ibf_object_complex_rational {
14057 long a, b;
14058};
14059
14060 struct ibf_object_symbol {
14061 long str;
14062};
14063
14064#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
14065 ((((offset) - 1) / (align) + 1) * (align))
14066/* No cast, since it's UB to create an unaligned pointer.
14067 * Leave as void* for use with memcpy in those cases.
14068 * We align the offset, but the buffer pointer is only VALUE aligned,
14069 * so the returned pointer may be unaligned for `type` .*/
14070#define IBF_OBJBODY(type, offset) \
14071 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
14072
14073static const void *
14074ibf_load_check_offset(const struct ibf_load *load, size_t offset)
14075{
14076 if (offset >= load->current_buffer->size) {
14077 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
14078 }
14079 return load->current_buffer->buff + offset;
14080}
14081
14082NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
14083
14084static void
14085ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
14086{
14087 char buff[0x100];
14088 rb_raw_obj_info(buff, sizeof(buff), obj);
14089 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
14090}
14091
14092NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
14093
14094static VALUE
14095ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14096{
14097 rb_raise(rb_eArgError, "unsupported");
14098 UNREACHABLE_RETURN(Qnil);
14099}
14100
14101static void
14102ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
14103{
14104 enum ibf_object_class_index cindex;
14105 if (obj == rb_cObject) {
14106 cindex = IBF_OBJECT_CLASS_OBJECT;
14107 }
14108 else if (obj == rb_cArray) {
14109 cindex = IBF_OBJECT_CLASS_ARRAY;
14110 }
14111 else if (obj == rb_eStandardError) {
14112 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
14113 }
14114 else if (obj == rb_eNoMatchingPatternError) {
14115 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
14116 }
14117 else if (obj == rb_eTypeError) {
14118 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
14119 }
14120 else if (obj == rb_eNoMatchingPatternKeyError) {
14121 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
14122 }
14123 else {
14124 rb_obj_info_dump(obj);
14125 rb_p(obj);
14126 rb_bug("unsupported class");
14127 }
14128 ibf_dump_write_small_value(dump, (VALUE)cindex);
14129}
14130
14131static VALUE
14132ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14133{
14134 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
14135
14136 switch (cindex) {
14137 case IBF_OBJECT_CLASS_OBJECT:
14138 return rb_cObject;
14139 case IBF_OBJECT_CLASS_ARRAY:
14140 return rb_cArray;
14141 case IBF_OBJECT_CLASS_STANDARD_ERROR:
14142 return rb_eStandardError;
14143 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
14144 return rb_eNoMatchingPatternError;
14145 case IBF_OBJECT_CLASS_TYPE_ERROR:
14146 return rb_eTypeError;
14147 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
14148 return rb_eNoMatchingPatternKeyError;
14149 }
14150
14151 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
14152}
14153
14154
14155static void
14156ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
14157{
14158 double dbl = RFLOAT_VALUE(obj);
14159 (void)IBF_W(&dbl, double, 1);
14160}
14161
14162static VALUE
14163ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14164{
14165 double d;
14166 /* Avoid unaligned VFP load on ARMv7; IBF payload may be unaligned (C99 6.3.2.3 p7). */
14167 memcpy(&d, IBF_OBJBODY(double, offset), sizeof(d));
14168 VALUE f = DBL2NUM(d);
14169 if (!FLONUM_P(f)) RB_OBJ_SET_SHAREABLE(f);
14170 return f;
14171}
14172
14173static void
14174ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
14175{
14176 long encindex = (long)rb_enc_get_index(obj);
14177 long len = RSTRING_LEN(obj);
14178 const char *ptr = RSTRING_PTR(obj);
14179
14180 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14181 rb_encoding *enc = rb_enc_from_index((int)encindex);
14182 const char *enc_name = rb_enc_name(enc);
14183 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
14184 }
14185
14186 ibf_dump_write_small_value(dump, encindex);
14187 ibf_dump_write_small_value(dump, len);
14188 IBF_WP(ptr, char, len);
14189}
14190
14191static VALUE
14192ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14193{
14194 ibf_offset_t reading_pos = offset;
14195
14196 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14197 const long len = (long)ibf_load_small_value(load, &reading_pos);
14198 const char *ptr = load->current_buffer->buff + reading_pos;
14199
14200 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14201 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14202 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14203 }
14204
14205 VALUE str;
14206 if (header->frozen && !header->internal) {
14207 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
14208 }
14209 else {
14210 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
14211
14212 if (header->internal) rb_obj_hide(str);
14213 if (header->frozen) str = rb_fstring(str);
14214 }
14215 return str;
14216}
14217
14218static void
14219ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
14220{
14221 VALUE srcstr = RREGEXP_SRC(obj);
14222 struct ibf_object_regexp regexp;
14223 regexp.option = (char)rb_reg_options(obj);
14224 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
14225
14226 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
14227 ibf_dump_write_small_value(dump, regexp.srcstr);
14228}
14229
14230static VALUE
14231ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14232{
14233 struct ibf_object_regexp regexp;
14234 regexp.option = ibf_load_byte(load, &offset);
14235 regexp.srcstr = ibf_load_small_value(load, &offset);
14236
14237 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14238 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
14239
14240 if (header->internal) rb_obj_hide(reg);
14241 if (header->frozen) RB_OBJ_SET_SHAREABLE(rb_obj_freeze(reg));
14242
14243 return reg;
14244}
14245
14246static void
14247ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
14248{
14249 long i, len = RARRAY_LEN(obj);
14250 ibf_dump_write_small_value(dump, len);
14251 for (i=0; i<len; i++) {
14252 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
14253 ibf_dump_write_small_value(dump, index);
14254 }
14255}
14256
14257static VALUE
14258ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14259{
14260 ibf_offset_t reading_pos = offset;
14261
14262 const long len = (long)ibf_load_small_value(load, &reading_pos);
14263
14264 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
14265 int i;
14266
14267 for (i=0; i<len; i++) {
14268 const VALUE index = ibf_load_small_value(load, &reading_pos);
14269 rb_ary_push(ary, ibf_load_object(load, index));
14270 }
14271
14272 if (header->frozen) {
14273 rb_ary_freeze(ary);
14274 rb_ractor_make_shareable(ary); // TODO: check elements
14275 }
14276
14277 return ary;
14278}
14279
14280static int
14281ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14282{
14283 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14284
14285 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14286 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14287
14288 ibf_dump_write_small_value(dump, key_index);
14289 ibf_dump_write_small_value(dump, val_index);
14290 return ST_CONTINUE;
14291}
14292
14293static void
14294ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14295{
14296 long len = RHASH_SIZE(obj);
14297 ibf_dump_write_small_value(dump, (VALUE)len);
14298
14299 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14300}
14301
14302static VALUE
14303ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14304{
14305 long len = (long)ibf_load_small_value(load, &offset);
14306 VALUE obj = rb_hash_new_with_size(len);
14307 int i;
14308
14309 for (i = 0; i < len; i++) {
14310 VALUE key_index = ibf_load_small_value(load, &offset);
14311 VALUE val_index = ibf_load_small_value(load, &offset);
14312
14313 VALUE key = ibf_load_object(load, key_index);
14314 VALUE val = ibf_load_object(load, val_index);
14315 rb_hash_aset(obj, key, val);
14316 }
14317 rb_hash_rehash(obj);
14318
14319 if (header->internal) rb_obj_hide(obj);
14320 if (header->frozen) {
14321 RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14322 }
14323
14324 return obj;
14325}
14326
14327static void
14328ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14329{
14330 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14331 struct ibf_object_struct_range range;
14332 VALUE beg, end;
14333 IBF_ZERO(range);
14334 range.len = 3;
14335 range.class_index = 0;
14336
14337 rb_range_values(obj, &beg, &end, &range.excl);
14338 range.beg = (long)ibf_dump_object(dump, beg);
14339 range.end = (long)ibf_dump_object(dump, end);
14340
14341 IBF_W_ALIGN(struct ibf_object_struct_range);
14342 IBF_WV(range);
14343 }
14344 else {
14345 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14346 rb_class_name(CLASS_OF(obj)));
14347 }
14348}
14349
14350static VALUE
14351ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14352{
14353 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14354 VALUE beg = ibf_load_object(load, range->beg);
14355 VALUE end = ibf_load_object(load, range->end);
14356 VALUE obj = rb_range_new(beg, end, range->excl);
14357 if (header->internal) rb_obj_hide(obj);
14358 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14359 return obj;
14360}
14361
14362static void
14363ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14364{
14365 ssize_t len = BIGNUM_LEN(obj);
14366 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14367 BDIGIT *d = BIGNUM_DIGITS(obj);
14368
14369 (void)IBF_W(&slen, ssize_t, 1);
14370 IBF_WP(d, BDIGIT, len);
14371}
14372
14373static VALUE
14374ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14375{
14376 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14377 int sign = bignum->slen > 0;
14378 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14379 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14380 INTEGER_PACK_LSWORD_FIRST |
14381 INTEGER_PACK_NATIVE_BYTE_ORDER;
14382 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14383 big_unpack_flags |
14384 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14385 if (header->internal) rb_obj_hide(obj);
14386 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14387 return obj;
14388}
14389
14390static void
14391ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14392{
14393 if (rb_data_is_encoding(obj)) {
14394 rb_encoding *enc = rb_to_encoding(obj);
14395 const char *name = rb_enc_name(enc);
14396 long len = strlen(name) + 1;
14397 long data[2];
14398 data[0] = IBF_OBJECT_DATA_ENCODING;
14399 data[1] = len;
14400 (void)IBF_W(data, long, 2);
14401 IBF_WP(name, char, len);
14402 }
14403 else {
14404 ibf_dump_object_unsupported(dump, obj);
14405 }
14406}
14407
14408static VALUE
14409ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14410{
14411 const long *body = IBF_OBJBODY(long, offset);
14412 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14413 /* const long len = body[1]; */
14414 const char *data = (const char *)&body[2];
14415
14416 switch (type) {
14417 case IBF_OBJECT_DATA_ENCODING:
14418 {
14419 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14420 return encobj;
14421 }
14422 }
14423
14424 return ibf_load_object_unsupported(load, header, offset);
14425}
14426
14427static void
14428ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14429{
14430 long data[2];
14431 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14432 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14433
14434 (void)IBF_W(data, long, 2);
14435}
14436
14437static VALUE
14438ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14439{
14440 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14441 VALUE a = ibf_load_object(load, nums->a);
14442 VALUE b = ibf_load_object(load, nums->b);
14443 VALUE obj = header->type == T_COMPLEX ?
14444 rb_complex_new(a, b) : rb_rational_new(a, b);
14445
14446 if (header->internal) rb_obj_hide(obj);
14447 if (header->frozen) rb_ractor_make_shareable(rb_obj_freeze(obj));
14448 return obj;
14449}
14450
14451static void
14452ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14453{
14454 ibf_dump_object_string(dump, rb_sym2str(obj));
14455}
14456
14457static VALUE
14458ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14459{
14460 ibf_offset_t reading_pos = offset;
14461
14462 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14463 const long len = (long)ibf_load_small_value(load, &reading_pos);
14464 const char *ptr = load->current_buffer->buff + reading_pos;
14465
14466 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14467 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14468 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14469 }
14470
14471 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14472 return ID2SYM(id);
14473}
14474
14475typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14476static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14477 ibf_dump_object_unsupported, /* T_NONE */
14478 ibf_dump_object_unsupported, /* T_OBJECT */
14479 ibf_dump_object_class, /* T_CLASS */
14480 ibf_dump_object_unsupported, /* T_MODULE */
14481 ibf_dump_object_float, /* T_FLOAT */
14482 ibf_dump_object_string, /* T_STRING */
14483 ibf_dump_object_regexp, /* T_REGEXP */
14484 ibf_dump_object_array, /* T_ARRAY */
14485 ibf_dump_object_hash, /* T_HASH */
14486 ibf_dump_object_struct, /* T_STRUCT */
14487 ibf_dump_object_bignum, /* T_BIGNUM */
14488 ibf_dump_object_unsupported, /* T_FILE */
14489 ibf_dump_object_data, /* T_DATA */
14490 ibf_dump_object_unsupported, /* T_MATCH */
14491 ibf_dump_object_complex_rational, /* T_COMPLEX */
14492 ibf_dump_object_complex_rational, /* T_RATIONAL */
14493 ibf_dump_object_unsupported, /* 0x10 */
14494 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14495 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14496 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14497 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14498 ibf_dump_object_unsupported, /* T_FIXNUM */
14499 ibf_dump_object_unsupported, /* T_UNDEF */
14500 ibf_dump_object_unsupported, /* 0x17 */
14501 ibf_dump_object_unsupported, /* 0x18 */
14502 ibf_dump_object_unsupported, /* 0x19 */
14503 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
14504 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14505 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14506 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14507 ibf_dump_object_unsupported, /* 0x1e */
14508 ibf_dump_object_unsupported, /* 0x1f */
14509};
14510
14511static void
14512ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14513{
14514 unsigned char byte =
14515 (header.type << 0) |
14516 (header.special_const << 5) |
14517 (header.frozen << 6) |
14518 (header.internal << 7);
14519
14520 IBF_WV(byte);
14521}
14522
14523static struct ibf_object_header
14524ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14525{
14526 unsigned char byte = ibf_load_byte(load, offset);
14527
14528 struct ibf_object_header header;
14529 header.type = (byte >> 0) & 0x1f;
14530 header.special_const = (byte >> 5) & 0x01;
14531 header.frozen = (byte >> 6) & 0x01;
14532 header.internal = (byte >> 7) & 0x01;
14533
14534 return header;
14535}
14536
14537static ibf_offset_t
14538ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14539{
14540 struct ibf_object_header obj_header;
14541 ibf_offset_t current_offset;
14542 IBF_ZERO(obj_header);
14543 obj_header.type = TYPE(obj);
14544
14545 IBF_W_ALIGN(ibf_offset_t);
14546 current_offset = ibf_dump_pos(dump);
14547
14548 if (SPECIAL_CONST_P(obj) &&
14549 ! (SYMBOL_P(obj) ||
14550 RB_FLOAT_TYPE_P(obj))) {
14551 obj_header.special_const = TRUE;
14552 obj_header.frozen = TRUE;
14553 obj_header.internal = TRUE;
14554 ibf_dump_object_object_header(dump, obj_header);
14555 ibf_dump_write_small_value(dump, obj);
14556 }
14557 else {
14558 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14559 obj_header.special_const = FALSE;
14560 obj_header.frozen = OBJ_FROZEN(obj) ? TRUE : FALSE;
14561 ibf_dump_object_object_header(dump, obj_header);
14562 (*dump_object_functions[obj_header.type])(dump, obj);
14563 }
14564
14565 return current_offset;
14566}
14567
14568typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14569static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14570 ibf_load_object_unsupported, /* T_NONE */
14571 ibf_load_object_unsupported, /* T_OBJECT */
14572 ibf_load_object_class, /* T_CLASS */
14573 ibf_load_object_unsupported, /* T_MODULE */
14574 ibf_load_object_float, /* T_FLOAT */
14575 ibf_load_object_string, /* T_STRING */
14576 ibf_load_object_regexp, /* T_REGEXP */
14577 ibf_load_object_array, /* T_ARRAY */
14578 ibf_load_object_hash, /* T_HASH */
14579 ibf_load_object_struct, /* T_STRUCT */
14580 ibf_load_object_bignum, /* T_BIGNUM */
14581 ibf_load_object_unsupported, /* T_FILE */
14582 ibf_load_object_data, /* T_DATA */
14583 ibf_load_object_unsupported, /* T_MATCH */
14584 ibf_load_object_complex_rational, /* T_COMPLEX */
14585 ibf_load_object_complex_rational, /* T_RATIONAL */
14586 ibf_load_object_unsupported, /* 0x10 */
14587 ibf_load_object_unsupported, /* T_NIL */
14588 ibf_load_object_unsupported, /* T_TRUE */
14589 ibf_load_object_unsupported, /* T_FALSE */
14590 ibf_load_object_symbol,
14591 ibf_load_object_unsupported, /* T_FIXNUM */
14592 ibf_load_object_unsupported, /* T_UNDEF */
14593 ibf_load_object_unsupported, /* 0x17 */
14594 ibf_load_object_unsupported, /* 0x18 */
14595 ibf_load_object_unsupported, /* 0x19 */
14596 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
14597 ibf_load_object_unsupported, /* T_NODE 0x1b */
14598 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14599 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14600 ibf_load_object_unsupported, /* 0x1e */
14601 ibf_load_object_unsupported, /* 0x1f */
14602};
14603
14604static VALUE
14605ibf_load_object(const struct ibf_load *load, VALUE object_index)
14606{
14607 if (object_index == 0) {
14608 return Qnil;
14609 }
14610 else {
14611 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14612 if (!obj) {
14613 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14614 ibf_offset_t offset = offsets[object_index];
14615 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14616
14617#if IBF_ISEQ_DEBUG
14618 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14619 load->current_buffer->obj_list_offset, (void *)offsets, offset);
14620 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14621 header.type, header.special_const, header.frozen, header.internal);
14622#endif
14623 if (offset >= load->current_buffer->size) {
14624 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14625 }
14626
14627 if (header.special_const) {
14628 ibf_offset_t reading_pos = offset;
14629
14630 obj = ibf_load_small_value(load, &reading_pos);
14631 }
14632 else {
14633 obj = (*load_object_functions[header.type])(load, &header, offset);
14634 }
14635
14636 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14637 }
14638#if IBF_ISEQ_DEBUG
14639 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14640 object_index, obj);
14641#endif
14642 return obj;
14643 }
14644}
14645
14646 struct ibf_dump_object_list_arg
14647{
14648 struct ibf_dump *dump;
14649 VALUE offset_list;
14650};
14651
14652static int
14653ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14654{
14655 VALUE obj = (VALUE)key;
14656 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14657
14658 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14659 rb_ary_push(args->offset_list, UINT2NUM(offset));
14660
14661 return ST_CONTINUE;
14662}
14663
14664static void
14665ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14666{
14667 st_table *obj_table = dump->current_buffer->obj_table;
14668 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14669
14670 struct ibf_dump_object_list_arg args;
14671 args.dump = dump;
14672 args.offset_list = offset_list;
14673
14674 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14675
14676 IBF_W_ALIGN(ibf_offset_t);
14677 *obj_list_offset = ibf_dump_pos(dump);
14678
14679 st_index_t size = obj_table->num_entries;
14680 st_index_t i;
14681
14682 for (i=0; i<size; i++) {
14683 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
14684 IBF_WV(offset);
14685 }
14686
14687 *obj_list_size = (unsigned int)size;
14688}
14689
14690static void
14691ibf_dump_mark(void *ptr)
14692{
14693 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14694 rb_gc_mark(dump->global_buffer.str);
14695
14696 rb_mark_set(dump->global_buffer.obj_table);
14697 rb_mark_set(dump->iseq_table);
14698}
14699
14700static void
14701ibf_dump_free(void *ptr)
14702{
14703 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14704 if (dump->global_buffer.obj_table) {
14705 st_free_table(dump->global_buffer.obj_table);
14706 dump->global_buffer.obj_table = 0;
14707 }
14708 if (dump->iseq_table) {
14709 st_free_table(dump->iseq_table);
14710 dump->iseq_table = 0;
14711 }
14712}
14713
14714static size_t
14715ibf_dump_memsize(const void *ptr)
14716{
14717 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14718 size_t size = 0;
14719 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14720 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14721 return size;
14722}
14723
14724static const rb_data_type_t ibf_dump_type = {
14725 "ibf_dump",
14726 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14727 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
14728};
14729
14730static void
14731ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
14732{
14733 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
14734 dump->iseq_table = NULL;
14735
14736 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
14737 dump->global_buffer.obj_table = ibf_dump_object_table_new();
14738 dump->iseq_table = st_init_numtable(); /* need free */
14739
14740 dump->current_buffer = &dump->global_buffer;
14741}
14742
14743 VALUE
14744rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
14745{
14746 struct ibf_dump *dump;
14747 struct ibf_header header = {{0}};
14748 VALUE dump_obj;
14749 VALUE str;
14750
14751 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
14752 ISEQ_BODY(iseq)->local_iseq != iseq) {
14753 rb_raise(rb_eRuntimeError, "should be top of iseq");
14754 }
14755 if (RTEST(ISEQ_COVERAGE(iseq))) {
14756 rb_raise(rb_eRuntimeError, "should not compile with coverage");
14757 }
14758
14759 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
14760 ibf_dump_setup(dump, dump_obj);
14761
14762 ibf_dump_write(dump, &header, sizeof(header));
14763 ibf_dump_iseq(dump, iseq);
14764
14765 header.magic[0] = 'Y'; /* YARB */
14766 header.magic[1] = 'A';
14767 header.magic[2] = 'R';
14768 header.magic[3] = 'B';
14769 header.major_version = IBF_MAJOR_VERSION;
14770 header.minor_version = IBF_MINOR_VERSION;
14771 header.endian = IBF_ENDIAN_MARK;
14772 header.wordsize = (uint8_t)SIZEOF_VALUE;
14773 ibf_dump_iseq_list(dump, &header);
14774 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
14775 header.size = ibf_dump_pos(dump);
14776
14777 if (RTEST(opt)) {
14778 VALUE opt_str = opt;
14779 const char *ptr = StringValuePtr(opt_str);
14780 header.extra_size = RSTRING_LENINT(opt_str);
14781 ibf_dump_write(dump, ptr, header.extra_size);
14782 }
14783 else {
14784 header.extra_size = 0;
14785 }
14786
14787 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
14788
14789 str = dump->global_buffer.str;
14790 RB_GC_GUARD(dump_obj);
14791 return str;
14792}
14793
14794static const ibf_offset_t *
14795ibf_iseq_list(const struct ibf_load *load)
14796{
14797 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
14798}
14799
14800void
14801rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
14802{
14803 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
14804 rb_iseq_t *prev_src_iseq = load->iseq;
14805 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
14806 load->iseq = iseq;
14807#if IBF_ISEQ_DEBUG
14808 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
14809 iseq->aux.loader.index, offset,
14810 load->header->size);
14811#endif
14812 ibf_load_iseq_each(load, iseq, offset);
14813 ISEQ_COMPILE_DATA_CLEAR(iseq);
14814 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14815 rb_iseq_init_trace(iseq);
14816 load->iseq = prev_src_iseq;
14817}
14818
14819#if USE_LAZY_LOAD
14820const rb_iseq_t *
14821rb_iseq_complete(const rb_iseq_t *iseq)
14822{
14823 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
14824 return iseq;
14825}
14826#endif
14827
14828static rb_iseq_t *
14829ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
14830{
14831 int iseq_index = (int)(VALUE)index_iseq;
14832
14833#if IBF_ISEQ_DEBUG
14834 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
14835 (void *)index_iseq, (void *)load->iseq_list);
14836#endif
14837 if (iseq_index == -1) {
14838 return NULL;
14839 }
14840 else {
14841 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
14842
14843#if IBF_ISEQ_DEBUG
14844 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
14845#endif
14846 if (iseqv) {
14847 return (rb_iseq_t *)iseqv;
14848 }
14849 else {
14850 rb_iseq_t *iseq = iseq_imemo_alloc();
14851#if IBF_ISEQ_DEBUG
14852 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
14853#endif
14854 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14855 iseq->aux.loader.obj = load->loader_obj;
14856 iseq->aux.loader.index = iseq_index;
14857#if IBF_ISEQ_DEBUG
14858 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
14859 (void *)iseq, (void *)load->loader_obj, iseq_index);
14860#endif
14861 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
14862
14863 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
14864#if IBF_ISEQ_DEBUG
14865 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
14866#endif
14867 rb_ibf_load_iseq_complete(iseq);
14868 }
14869
14870#if IBF_ISEQ_DEBUG
14871 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
14872 (void *)iseq, (void *)load->iseq);
14873#endif
14874 return iseq;
14875 }
14876 }
14877}
14878
14879static void
14880ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
14881{
14882 struct ibf_header *header = (struct ibf_header *)bytes;
14883 load->loader_obj = loader_obj;
14884 load->global_buffer.buff = bytes;
14885 load->header = header;
14886 load->global_buffer.size = header->size;
14887 load->global_buffer.obj_list_offset = header->global_object_list_offset;
14888 load->global_buffer.obj_list_size = header->global_object_list_size;
14889 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
14890 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
14891 load->iseq = NULL;
14892
14893 load->current_buffer = &load->global_buffer;
14894
14895 if (size < header->size) {
14896 rb_raise(rb_eRuntimeError, "broken binary format");
14897 }
14898 if (strncmp(header->magic, "YARB", 4) != 0) {
14899 rb_raise(rb_eRuntimeError, "unknown binary format");
14900 }
14901 if (header->major_version != IBF_MAJOR_VERSION ||
14902 header->minor_version != IBF_MINOR_VERSION) {
14903 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
14904 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
14905 }
14906 if (header->endian != IBF_ENDIAN_MARK) {
14907 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
14908 }
14909 if (header->wordsize != SIZEOF_VALUE) {
14910 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
14911 }
14912 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14913 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
14914 header->iseq_list_offset);
14915 }
14916 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14917 rb_raise(rb_eArgError, "unaligned object list offset: %u",
14918 load->global_buffer.obj_list_offset);
14919 }
14920}
14921
14922static void
14923ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
14924{
14925 StringValue(str);
14926
14927 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
14928 rb_raise(rb_eRuntimeError, "broken binary format");
14929 }
14930
14931 if (USE_LAZY_LOAD) {
14932 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
14933 }
14934
14935 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
14936 RB_OBJ_WRITE(loader_obj, &load->str, str);
14937}
14938
14939static void
14940ibf_loader_mark(void *ptr)
14941{
14942 struct ibf_load *load = (struct ibf_load *)ptr;
14943 rb_gc_mark(load->str);
14944 rb_gc_mark(load->iseq_list);
14945 rb_gc_mark(load->global_buffer.obj_list);
14946}
14947
14948static void
14949ibf_loader_free(void *ptr)
14950{
14951 struct ibf_load *load = (struct ibf_load *)ptr;
14952 ruby_xfree(load);
14953}
14954
14955static size_t
14956ibf_loader_memsize(const void *ptr)
14957{
14958 return sizeof(struct ibf_load);
14959}
14960
14961static const rb_data_type_t ibf_load_type = {
14962 "ibf_loader",
14963 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
14964 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
14965};
14966
14967const rb_iseq_t *
14968rb_iseq_ibf_load(VALUE str)
14969{
14970 struct ibf_load *load;
14971 rb_iseq_t *iseq;
14972 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14973
14974 ibf_load_setup(load, loader_obj, str);
14975 iseq = ibf_load_iseq(load, 0);
14976
14977 RB_GC_GUARD(loader_obj);
14978 return iseq;
14979}
14980
14981const rb_iseq_t *
14982rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
14983{
14984 struct ibf_load *load;
14985 rb_iseq_t *iseq;
14986 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14987
14988 ibf_load_setup_bytes(load, loader_obj, bytes, size);
14989 iseq = ibf_load_iseq(load, 0);
14990
14991 RB_GC_GUARD(loader_obj);
14992 return iseq;
14993}
14994
14995 VALUE
14996rb_iseq_ibf_load_extra_data(VALUE str)
14997{
14998 struct ibf_load *load;
14999 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15000 VALUE extra_str;
15001
15002 ibf_load_setup(load, loader_obj, str);
15003 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
15004 RB_GC_GUARD(loader_obj);
15005 return extra_str;
15006}
15007
15008#include "prism_compile.c"
RUBY_ASSERT
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
LONG_LONG
#define LONG_LONG
Definition long_long.h:38
RUBY_ALIGNOF
#define RUBY_ALIGNOF
Wraps (or simulates) alignof.
Definition stdalign.h:28
RUBY_EVENT_END
#define RUBY_EVENT_END
Encountered an end of a class clause.
Definition event.h:40
RUBY_EVENT_C_CALL
#define RUBY_EVENT_C_CALL
A method, written in C, is called.
Definition event.h:43
RUBY_EVENT_B_RETURN
#define RUBY_EVENT_B_RETURN
Encountered a next statement.
Definition event.h:56
RUBY_EVENT_CLASS
#define RUBY_EVENT_CLASS
Encountered a new class.
Definition event.h:39
RUBY_EVENT_NONE
#define RUBY_EVENT_NONE
No events.
Definition event.h:37
RUBY_EVENT_LINE
#define RUBY_EVENT_LINE
Encountered a new line.
Definition event.h:38
RUBY_EVENT_RETURN
#define RUBY_EVENT_RETURN
Encountered a return statement.
Definition event.h:42
RUBY_EVENT_C_RETURN
#define RUBY_EVENT_C_RETURN
Return from a method, written in C.
Definition event.h:44
RUBY_EVENT_B_CALL
#define RUBY_EVENT_B_CALL
Encountered an yield statement.
Definition event.h:55
rb_event_flag_t
uint32_t rb_event_flag_t
Represents event(s).
Definition event.h:108
RUBY_EVENT_CALL
#define RUBY_EVENT_CALL
A method, written in Ruby, is called.
Definition event.h:41
RUBY_EVENT_RESCUE
#define RUBY_EVENT_RESCUE
Encountered a rescue statement.
Definition event.h:61
RBIMPL_ATTR_FORMAT
#define RBIMPL_ATTR_FORMAT(x, y, z)
Wraps (or simulates) __attribute__((format)).
Definition format.h:29
rb_str_new2
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1676
T_COMPLEX
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
Definition value_type.h:59
TYPE
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
NUM2ULONG
#define NUM2ULONG
Old name of RB_NUM2ULONG.
Definition long.h:52
NUM2LL
#define NUM2LL
Old name of RB_NUM2LL.
Definition long_long.h:34
REALLOC_N
#define REALLOC_N
Old name of RB_REALLOC_N.
Definition memory.h:403
ALLOCV
#define ALLOCV
Old name of RB_ALLOCV.
Definition memory.h:404
RFLOAT_VALUE
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
T_STRING
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
xfree
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
Qundef
#define Qundef
Old name of RUBY_Qundef.
Definition special_consts.h:62
INT2FIX
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
OBJ_FROZEN
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
Definition fl_type.h:136
rb_str_cat2
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1684
T_NIL
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
UNREACHABLE
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
T_FLOAT
#define T_FLOAT
Old name of RUBY_T_FLOAT.
Definition value_type.h:64
ID2SYM
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
T_BIGNUM
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
SPECIAL_CONST_P
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
Definition special_consts.h:56
OBJ_FREEZE
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:134
ULONG2NUM
#define ULONG2NUM
Old name of RB_ULONG2NUM.
Definition long.h:60
UNREACHABLE_RETURN
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
SYM2ID
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
FIX2UINT
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
ZALLOC
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
CLASS_OF
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
FIXABLE
#define FIXABLE
Old name of RB_FIXABLE.
Definition fixnum.h:25
xmalloc
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
LONG2FIX
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
FIX2INT
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
NUM2UINT
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
ZALLOC_N
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition memory.h:401
ASSUME
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition assume.h:27
T_RATIONAL
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition value_type.h:76
T_HASH
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
ALLOC_N
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
FL_SET
#define FL_SET
Old name of RB_FL_SET.
Definition fl_type.h:128
FLONUM_P
#define FLONUM_P
Old name of RB_FLONUM_P.
Definition special_consts.h:67
Qtrue
#define Qtrue
Old name of RUBY_Qtrue.
Definition special_consts.h:61
NUM2INT
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
Qnil
#define Qnil
Old name of RUBY_Qnil.
Definition special_consts.h:60
Qfalse
#define Qfalse
Old name of RUBY_Qfalse.
Definition special_consts.h:59
FIX2LONG
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
T_ARRAY
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
NIL_P
#define NIL_P
Old name of RB_NIL_P.
Definition special_consts.h:55
T_SYMBOL
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
DBL2NUM
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
BUILTIN_TYPE
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
NUM2LONG
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
FL_UNSET
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition fl_type.h:132
UINT2NUM
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
FIXNUM_P
#define FIXNUM_P
Old name of RB_FIXNUM_P.
Definition special_consts.h:53
CONST_ID
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
ALLOCV_END
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
SYMBOL_P
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
T_REGEXP
#define T_REGEXP
Old name of RUBY_T_REGEXP.
Definition value_type.h:77
ruby_debug
#define ruby_debug
This variable controls whether the interpreter is in debug mode.
Definition error.h:486
rb_eNotImpError
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1441
rb_eStandardError
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1428
rb_eTypeError
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1431
rb_eNoMatchingPatternError
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1444
rb_exc_fatal
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:666
rb_eRuntimeError
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1429
rb_warn
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
rb_eNoMatchingPatternKeyError
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition error.c:1445
rb_eIndexError
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1433
rb_errinfo
VALUE rb_errinfo(void)
This is the same as $! in Ruby.
Definition eval.c:2045
rb_eSyntaxError
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1448
RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
@ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
Warning is for checking unused block strictly.
Definition error.h:57
rb_obj_reveal
VALUE rb_obj_reveal(VALUE obj, VALUE klass)
Make a hidden object visible again.
Definition object.c:109
rb_cArray
VALUE rb_cArray
Array class.
rb_obj_hide
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:100
rb_cHash
VALUE rb_cHash
Hash class.
Definition hash.c:109
rb_inspect
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:686
rb_cRange
VALUE rb_cRange
Range class.
Definition range.c:31
rb_obj_is_kind_of
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Definition object.c:923
rb_obj_freeze
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1342
RB_OBJ_WRITTEN
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:615
RB_OBJ_WRITE
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:603
rb_memerror
void rb_memerror(void)
Triggers out-of-memory error.
Definition gc.c:5075
rb_ary_reverse
VALUE rb_ary_reverse(VALUE ary)
Destructively reverses the passed array in-place.
rb_ary_dup
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
rb_ary_cat
VALUE rb_ary_cat(VALUE ary, const VALUE *train, long len)
Destructively appends multiple elements at the end of the array.
rb_ary_new
VALUE rb_ary_new(void)
Allocates a new, empty array.
rb_ary_new_capa
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
rb_ary_hidden_new
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
rb_ary_clear
VALUE rb_ary_clear(VALUE ary)
Destructively removes everything form an array.
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
rb_ary_freeze
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
rb_ary_entry
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
rb_ary_join
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
rb_ary_store
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
INTEGER_PACK_NATIVE_BYTE_ORDER
#define INTEGER_PACK_NATIVE_BYTE_ORDER
Means either INTEGER_PACK_MSBYTE_FIRST or INTEGER_PACK_LSBYTE_FIRST, depending on the host processor'...
Definition bignum.h:546
INTEGER_PACK_NEGATIVE
#define INTEGER_PACK_NEGATIVE
Interprets the input as a signed negative number (unpack only).
Definition bignum.h:564
INTEGER_PACK_LSWORD_FIRST
#define INTEGER_PACK_LSWORD_FIRST
Stores/interprets the least significant word as the first word.
Definition bignum.h:528
rb_hash_new
VALUE rb_hash_new(void)
Creates a new, empty hash object.
Definition hash.c:1464
rb_is_const_id
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1079
rb_is_attrset_id
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1103
rb_range_values
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c:1862
rb_range_new
VALUE rb_range_new(VALUE beg, VALUE end, int excl)
Creates a new Range.
Definition range.c:69
rb_rational_new
VALUE rb_rational_new(VALUE num, VALUE den)
Constructs a Rational, with reduction.
Definition rational.c:2000
rb_reg_options
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
Definition re.c:4223
rb_str_append
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:3799
rb_str_tmp_new
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1746
rb_str_hash_cmp
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4162
rb_str_new
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1499
rb_str_hash
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4148
rb_str_cat
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3567
rb_str_buf_append
VALUE rb_str_buf_append(VALUE dst, VALUE src)
Identical to rb_str_cat_cstr(), except it takes Ruby's string instead of C's.
Definition string.c:3765
rb_str_cmp
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4216
rb_str_concat
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:4036
rb_str_freeze
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3280
rb_str_new_cstr
#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:1515
rb_class_name
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:500
rb_intern_const
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:285
rb_id2sym
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
Definition symbol.c:974
rb_sym2str
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:993
rb_sym2id
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:943
len
int len
Length of the buffer.
Definition io.h:8
ractor.h
RB_OBJ_SHAREABLE_P
#define RB_OBJ_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
Definition ractor.h:235
rb_ractor_make_shareable
VALUE rb_ractor_make_shareable(VALUE obj)
Destructively transforms the passed object so that multiple Ractors can share it.
Definition ractor.c:1547
re.h
util.h
DECIMAL_SIZE_OF
#define DECIMAL_SIZE_OF(expr)
An approximation of decimal representation size.
Definition util.h:48
ruby_qsort
void ruby_qsort(void *, const size_t, const size_t, int(*)(const void *, const void *, void *), void *)
Reentrant implementation of quick sort.
rb_long2int
#define rb_long2int
Just another name of rb_long2int_inline.
Definition long.h:62
MEMCPY
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
ALLOCA_N
#define ALLOCA_N(type, n)
Definition memory.h:292
MEMZERO
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
RB_GC_GUARD
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
RB_ALLOCV
#define RB_ALLOCV(v, n)
Identical to RB_ALLOCV_N(), except that it allocates a number of bytes and returns a void* .
Definition memory.h:304
ruby::backward::cxxanyargs::type
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition cxxanyargs.hpp:56
ruby::backward::cxxanyargs::st_foreach
int st_foreach(st_table *q, int_type *w, st_data_t e)
Iteration over the given table.
Definition cxxanyargs.hpp:432
ruby::backward::cxxanyargs::rb_hash_foreach
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
Definition cxxanyargs.hpp:482
RBIMPL_ATTR_NORETURN
#define RBIMPL_ATTR_NORETURN()
Wraps (or simulates) [[noreturn]].
Definition noreturn.h:38
RARRAY_LEN
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
RARRAY_LENINT
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
RARRAY_ASET
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
Definition rarray.h:386
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition rarray.h:403
RARRAY_CONST_PTR
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
RBASIC_CLASS
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition rbasic.h:166
RUBY_DEFAULT_FREE
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition rdata.h:78
RUBY_DATA_FUNC
void(* RUBY_DATA_FUNC)(void *)
This is the type of callbacks registered to RData.
Definition rdata.h:104
RHASH_SIZE
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition rhash.h:69
RREGEXP_SRC
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
Definition rregexp.h:103
StringValue
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
StringValuePtr
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:76
RSTRING_LENINT
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition rstring.h:438
StringValueCStr
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
RTYPEDDATA_DATA
#define RTYPEDDATA_DATA(v)
Convenient getter macro.
Definition rtypeddata.h:103
TypedData_Get_Struct
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:649
TypedData_Wrap_Struct
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:461
rb_data_type_t
struct rb_data_type_struct rb_data_type_t
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:205
TypedData_Make_Struct
#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:508
rb_p
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9056
RB_SPECIAL_CONST_P
static bool RB_SPECIAL_CONST_P(VALUE obj)
Checks if the given object is of enum ruby_special_consts.
Definition special_consts.h:327
RTEST
#define RTEST
This is an old name of RB_TEST.
Definition special_consts.h:51
_
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
METHOD
Definition proc.c:30
RComplex
Internal header for Complex.
Definition complex.h:13
RNode_LIST
Definition rubyparser.h:578
RRational
Internal header for Rational.
Definition rational.h:16
cdhash_set_label_struct
Definition compile.c:2356
dstr_ctxt
Definition compile.c:4624
ensure_range
Definition compile.c:114
ibf_dump_buffer
Definition compile.c:12524
ibf_dump_iseq_list_arg
Definition compile.c:13966
ibf_dump_object_list_arg
Definition compile.c:14647
ibf_dump
Definition compile.c:12529
ibf_header
Definition compile.c:12509
ibf_load_buffer
Definition compile.c:12535
ibf_load
Definition compile.c:12544
ibf_object_bignum
Definition compile.c:14047
ibf_object_complex_rational
Definition compile.c:14056
ibf_object_hash
Definition compile.c:14034
ibf_object_header
Definition compile.c:14013
ibf_object_regexp
Definition compile.c:14029
ibf_object_struct_range
Definition compile.c:14039
ibf_object_symbol
Definition compile.c:14060
iseq_adjust_data
Definition compile.c:102
iseq_catch_table_entry
Definition iseq.h:288
iseq_catch_table
Definition iseq.h:299
iseq_compile_data_ensure_node_stack
Definition compile.c:120
iseq_compile_data_storage
Definition iseq.h:318
iseq_inline_constant_cache::segments
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:285
iseq_insn_data
Definition compile.c:89
iseq_insn_info_entry
Definition iseq.h:259
iseq_label_data
Definition compile.c:77
iseq_link_anchor
Definition compile.c:65
iseq_link_element
Definition compile.c:53
iseq_trace_data
Definition compile.c:108
masgn_lhs_node
Definition compile.c:5676
masgn_state
Definition compile.c:5685
outer_variable_list
Definition compile.c:13458
outer_variable_pair
Definition compile.c:13452
pinned_list
Definition compile.c:12554
rb_args_info
Definition rubyparser.h:768
rb_builtin_function
Definition builtin.h:6
rb_call_data
Definition vm_callinfo.h:590
rb_callcache
Definition vm_callinfo.h:278
rb_callinfo_kwarg
Definition vm_callinfo.h:48
rb_callinfo
Definition vm_callinfo.h:65
rb_id_table
Definition id_table.c:41
rb_iseq_constant_body
Definition vm_core.h:405
rb_iseq_new_with_callback_callback_func
Definition vm_core.h:1252
st_table
Definition st.h:79
iseq_inline_storage_entry
Definition vm_core.h:297
ID
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
SIZEOF_VALUE
#define SIZEOF_VALUE
Identical to sizeof(VALUE), except it is a macro that can also be used inside of preprocessor directi...
Definition value.h:69
VALUE
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
RB_FLOAT_TYPE_P
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
rb_integer_type_p
static bool rb_integer_type_p(VALUE obj)
Queries if the object is an instance of rb_cInteger.
Definition value_type.h:204
RB_TYPE_P
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_T_MASK
@ RUBY_T_MASK
Bitmask of ruby_value_type.
Definition value_type.h:145