Ruby 4.1.0dev (2026-11-10 revision 1f2a4bd5750bb3b685c24aee1fbd7530e895cf3f)
compile.c (1f2a4bd5750bb3b685c24aee1fbd7530e895cf3f)
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/coverage.h"
25#include "internal/complex.h"
26#include "internal/encoding.h"
27#include "internal/error.h"
28#include "internal/gc.h"
29#include "internal/hash.h"
30#include "internal/io.h"
31#include "internal/numeric.h"
32#include "internal/object.h"
33#include "internal/rational.h"
34#include "internal/re.h"
35#include "internal/ruby_parser.h"
36#include "internal/symbol.h"
37#include "internal/thread.h"
38#include "internal/variable.h"
39#include "iseq.h"
40#include "ruby/ractor.h"
41#include "ruby/re.h"
42#include "ruby/util.h"
43#include "vm_core.h"
44#include "vm_callinfo.h"
45#include "vm_debug.h"
46#include "yjit.h"
47
48#include "builtin.h"
49#include "insns.inc"
50#include "insns_info.inc"
51
52#define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
53
54typedef struct iseq_link_element {
55 enum {
56 ISEQ_ELEMENT_ANCHOR,
57 ISEQ_ELEMENT_LABEL,
58 ISEQ_ELEMENT_INSN,
59 ISEQ_ELEMENT_ADJUST,
60 ISEQ_ELEMENT_TRACE,
61 } type;
62 struct iseq_link_element *next;
63 struct iseq_link_element *prev;
65
66typedef struct iseq_link_anchor {
67 LINK_ELEMENT anchor;
68 LINK_ELEMENT *last;
70
71typedef enum {
72 LABEL_RESCUE_NONE,
73 LABEL_RESCUE_BEG,
74 LABEL_RESCUE_END,
75 LABEL_RESCUE_TYPE_MAX
76} LABEL_RESCUE_TYPE;
77
78typedef struct iseq_label_data {
79 LINK_ELEMENT link;
80 int label_no;
81 int position;
82 int sc_state;
83 int sp;
84 int refcnt;
85 unsigned int set: 1;
86 unsigned int rescued: 2;
87 unsigned int unremovable: 1;
88} LABEL;
89
90typedef struct iseq_insn_data {
91 LINK_ELEMENT link;
92 enum ruby_vminsn_type insn_id;
93 int operand_size;
94 int sc_state;
95 VALUE *operands;
96 struct {
97 int line_no;
98 int node_id;
99 rb_event_flag_t events;
100 } insn_info;
101} INSN;
102
103typedef struct iseq_adjust_data {
104 LINK_ELEMENT link;
105 LABEL *label;
106 int line_no;
107} ADJUST;
108
109typedef struct iseq_trace_data {
110 LINK_ELEMENT link;
111 rb_event_flag_t event;
112 long data;
113} TRACE;
114
116 LABEL *begin;
117 LABEL *end;
118 struct ensure_range *next;
119};
120
122 const void *ensure_node;
124 struct ensure_range *erange;
125};
126
127const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
128
142#ifndef CPDEBUG
143#define CPDEBUG 0
144#endif
145
146#if CPDEBUG >= 0
147#define compile_debug CPDEBUG
148#else
149#define compile_debug ISEQ_COMPILE_DATA(iseq)->option->debug_level
150#endif
151
152#if CPDEBUG
153
154#define compile_debug_print_indent(level) \
155 ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
156
157#define debugp(header, value) (void) \
158 (compile_debug_print_indent(1) && \
159 ruby_debug_print_value(1, compile_debug, (header), (value)))
160
161#define debugi(header, id) (void) \
162 (compile_debug_print_indent(1) && \
163 ruby_debug_print_id(1, compile_debug, (header), (id)))
164
165#define debugp_param(header, value) (void) \
166 (compile_debug_print_indent(1) && \
167 ruby_debug_print_value(1, compile_debug, (header), (value)))
168
169#define debugp_verbose(header, value) (void) \
170 (compile_debug_print_indent(2) && \
171 ruby_debug_print_value(2, compile_debug, (header), (value)))
172
173#define debugp_verbose_node(header, value) (void) \
174 (compile_debug_print_indent(10) && \
175 ruby_debug_print_value(10, compile_debug, (header), (value)))
176
177#define debug_node_start(node) ((void) \
178 (compile_debug_print_indent(1) && \
179 (ruby_debug_print_node(1, CPDEBUG, "", (const NODE *)(node)), gl_node_level)), \
180 gl_node_level++)
181
182#define debug_node_end() gl_node_level --
183
184#else
185
186#define debugi(header, id) ((void)0)
187#define debugp(header, value) ((void)0)
188#define debugp_verbose(header, value) ((void)0)
189#define debugp_verbose_node(header, value) ((void)0)
190#define debugp_param(header, value) ((void)0)
191#define debug_node_start(node) ((void)0)
192#define debug_node_end() ((void)0)
193#endif
194
195#if CPDEBUG > 1 || CPDEBUG < 0
196#undef printf
197#define printf ruby_debug_printf
198#define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
199#define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
200#else
201#define debugs if(0)printf
202#define debug_compile(msg, v) (v)
203#endif
204
205#define LVAR_ERRINFO (1)
206
207/* create new label */
208#define NEW_LABEL(l) new_label_body(iseq, (l))
209#define LABEL_FORMAT "<L%03d>"
210
211#define NEW_ISEQ(node, name, type, line_no) \
212 new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
213
214#define NEW_CHILD_ISEQ(node, name, type, line_no) \
215 new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
216
217#define NEW_CHILD_ISEQ_WITH_CALLBACK(callback_func, name, type, line_no) \
218 new_child_iseq_with_callback(iseq, (callback_func), (name), iseq, (type), (line_no))
219
220/* add instructions */
221#define ADD_SEQ(seq1, seq2) \
222 APPEND_LIST((seq1), (seq2))
223
224/* add an instruction */
225#define ADD_INSN(seq, line_node, insn) \
226 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 0))
227
228/* add an instruction with the given line number and node id */
229#define ADD_SYNTHETIC_INSN(seq, line_no, node_id, insn) \
230 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line_no), (node_id), BIN(insn), 0))
231
232/* insert an instruction before next */
233#define INSERT_BEFORE_INSN(next, line_no, node_id, insn) \
234 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
235
236/* insert an instruction after prev */
237#define INSERT_AFTER_INSN(prev, line_no, node_id, insn) \
238 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
239
240/* add an instruction with some operands (1, 2, 3, 5) */
241#define ADD_INSN1(seq, line_node, insn, op1) \
242 ADD_ELEM((seq), (LINK_ELEMENT *) \
243 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 1, (VALUE)(op1)))
244
245/* insert an instruction with some operands (1, 2, 3, 5) before next */
246#define INSERT_BEFORE_INSN1(next, line_no, node_id, insn, op1) \
247 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
248 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
249
250/* insert an instruction with some operands (1, 2, 3, 5) after prev */
251#define INSERT_AFTER_INSN1(prev, line_no, node_id, insn, op1) \
252 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
253 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
254
255#define LABEL_REF(label) ((label)->refcnt++)
256
257/* add an instruction with label operand (alias of ADD_INSN1) */
258#define ADD_INSNL(seq, line_node, insn, label) (ADD_INSN1(seq, line_node, insn, label), LABEL_REF(label))
259
260#define ADD_INSN2(seq, line_node, insn, op1, op2) \
261 ADD_ELEM((seq), (LINK_ELEMENT *) \
262 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
263
264#define ADD_INSN3(seq, line_node, insn, op1, op2, op3) \
265 ADD_ELEM((seq), (LINK_ELEMENT *) \
266 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
267
268/* Specific Insn factory */
269#define ADD_SEND(seq, line_node, id, argc) \
270 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
271
272#define ADD_SEND_WITH_FLAG(seq, line_node, id, argc, flag) \
273 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)(flag), NULL)
274
275#define ADD_SEND_WITH_BLOCK(seq, line_node, id, argc, block) \
276 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
277
278#define ADD_CALL_RECEIVER(seq, line_node) \
279 ADD_INSN((seq), (line_node), putself)
280
281#define ADD_CALL(seq, line_node, id, argc) \
282 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
283
284#define ADD_CALL_WITH_BLOCK(seq, line_node, id, argc, block) \
285 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
286
287#define ADD_SEND_R(seq, line_node, id, argc, block, flag, keywords) \
288 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)))
289
290#define ADD_TRACE(seq, event) \
291 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
292#define ADD_TRACE_WITH_DATA(seq, event, data) \
293 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
294
295static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
296static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
297
298#define ADD_GETLOCAL(seq, line_node, idx, level) iseq_add_getlocal(iseq, (seq), (line_node), (idx), (level))
299#define ADD_SETLOCAL(seq, line_node, idx, level) iseq_add_setlocal(iseq, (seq), (line_node), (idx), (level))
300
301/* add label */
302#define ADD_LABEL(seq, label) \
303 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
304
305#define APPEND_LABEL(seq, before, label) \
306 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
307
308#define ADD_ADJUST(seq, line_node, label) \
309 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), nd_line(line_node)))
310
311#define ADD_ADJUST_RESTORE(seq, label) \
312 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
313
314#define LABEL_UNREMOVABLE(label) \
315 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
316#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
317 VALUE _e = rb_ary_new3(5, (type), \
318 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
319 (VALUE)(iseqv), (VALUE)(lc) | 1); \
320 LABEL_UNREMOVABLE(ls); \
321 LABEL_REF(le); \
322 LABEL_REF(lc); \
323 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
324 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_hidden_new(3)); \
325 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
326} while (0)
327
328/* compile node */
329#define COMPILE(anchor, desc, node) \
330 (debug_compile("== " desc "\n", \
331 iseq_compile_each(iseq, (anchor), (node), 0)))
332
333/* compile node, this node's value will be popped */
334#define COMPILE_POPPED(anchor, desc, node) \
335 (debug_compile("== " desc "\n", \
336 iseq_compile_each(iseq, (anchor), (node), 1)))
337
338/* compile node, which is popped when 'popped' is true */
339#define COMPILE_(anchor, desc, node, popped) \
340 (debug_compile("== " desc "\n", \
341 iseq_compile_each(iseq, (anchor), (node), (popped))))
342
343#define COMPILE_RECV(anchor, desc, node, recv) \
344 (private_recv_p(node) ? \
345 (ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
346 COMPILE(anchor, desc, recv) ? 0 : -1)
347
348#define OPERAND_AT(insn, idx) \
349 (((INSN*)(insn))->operands[(idx)])
350
351#define INSN_OF(insn) \
352 (((INSN*)(insn))->insn_id)
353
354#define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
355#define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
356#define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
357#define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
358#define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
359#define IS_NEXT_INSN_ID(link, insn) \
360 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
361
362static inline bool
363IS_INDEPENDENT_INSN(LINK_ELEMENT *link)
364{
365 if (!IS_INSN(link)) {
366 return false;
367 }
368
369 enum ruby_vminsn_type type = INSN_OF(link);
370
371 return (
372 type == BIN(putobject) ||
373 type == BIN(putspecialobject) ||
374 type == BIN(putnil) ||
375 type == BIN(putself) ||
376 type == BIN(duphash) ||
377 type == BIN(getinstancevariable) ||
378 type == BIN(getlocal) ||
379 type == BIN(getlocal_WC_0) ||
380 type == BIN(getlocal_WC_1) ||
381 type == BIN(putobject_INT2FIX_0_) ||
382 type == BIN(putobject_INT2FIX_1_) ||
383 type == BIN(opt_getconstant_path)
384 );
385}
386
387/* error */
388#if CPDEBUG > 0
390#endif
391RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
392static void
393append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...)
394{
395 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
396 VALUE file = rb_iseq_path(iseq);
397 VALUE err = err_info == Qtrue ? Qfalse : err_info;
398 va_list args;
399
400 va_start(args, fmt);
401 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
402 va_end(args);
403 if (NIL_P(err_info)) {
404 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
405 rb_set_errinfo(err);
406 }
407 else if (!err_info) {
408 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, Qtrue);
409 }
410 if (compile_debug) {
411 if (SPECIAL_CONST_P(err)) err = rb_eSyntaxError;
412 rb_exc_fatal(err);
413 }
414}
415
416#if 0
417static void
418compile_bug(rb_iseq_t *iseq, int line, const char *fmt, ...)
419{
420 va_list args;
421 va_start(args, fmt);
422 rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
423 va_end(args);
424 abort();
425}
426#endif
427
428#define COMPILE_ERROR append_compile_error
429
430#define ERROR_ARGS_AT(n) iseq, nd_line(n),
431#define ERROR_ARGS ERROR_ARGS_AT(node)
432
433#define EXPECT_NODE(prefix, node, ndtype, errval) \
434do { \
435 const NODE *error_node = (node); \
436 enum node_type error_type = nd_type(error_node); \
437 if (error_type != (ndtype)) { \
438 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
439 prefix ": " #ndtype " is expected, but %s", \
440 ruby_node_name(error_type)); \
441 return errval; \
442 } \
443} while (0)
444
445#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
446do { \
447 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
448 prefix ": must be " #ndtype ", but 0"); \
449 return errval; \
450} while (0)
451
452#define UNKNOWN_NODE(prefix, node, errval) \
453do { \
454 const NODE *error_node = (node); \
455 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
456 ruby_node_name(nd_type(error_node))); \
457 return errval; \
458} while (0)
459
460#define COMPILE_OK 1
461#define COMPILE_NG 0
462
463#define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
464#define NO_CHECK(sub) (void)(sub)
465#define BEFORE_RETURN
466
467#define DECL_ANCHOR(name) \
468 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},&name[0].anchor}}
469#define INIT_ANCHOR(name) \
470 ((name->last = &name->anchor)->next = NULL) /* re-initialize */
471
472static inline VALUE
473freeze_hide_obj(VALUE obj)
474{
475 OBJ_FREEZE(obj);
476 RBASIC_CLEAR_CLASS(obj);
477 return obj;
478}
479
480#include "optinsn.inc"
481#if OPT_INSTRUCTIONS_UNIFICATION
482#include "optunifs.inc"
483#endif
484
485/* for debug */
486#if CPDEBUG < 0
487#define ISEQ_ARG iseq,
488#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
489#else
490#define ISEQ_ARG
491#define ISEQ_ARG_DECLARE
492#endif
493
494#if CPDEBUG
495#define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
496#endif
497
498static void dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest);
499static void dump_disasm_list(const LINK_ELEMENT *elem);
500
501static int insn_data_length(INSN *iobj);
502static int calc_sp_depth(int depth, INSN *iobj);
503
504static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...);
505static LABEL *new_label_body(rb_iseq_t *iseq, long line);
506static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
507static TRACE *new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data);
508
509
510static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, const NODE *n, int);
511static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
512static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
513static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
514static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
515
516static int iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args);
517static int iseq_set_exception_local_table(rb_iseq_t *iseq);
518static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
519
520static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
521static int iseq_set_exception_table(rb_iseq_t *iseq);
522static int iseq_set_optargs_table(rb_iseq_t *iseq);
523static int iseq_set_parameters_lvar_state(const rb_iseq_t *iseq);
524
525static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore);
526static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
527
528/*
529 * To make Array to LinkedList, use link_anchor
530 */
531
532static void
533verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *const anchor)
534{
535#if CPDEBUG
536 int flag = 0;
537 LINK_ELEMENT *list, *plist;
538
539 if (!compile_debug) return;
540
541 list = anchor->anchor.next;
542 plist = &anchor->anchor;
543 while (list) {
544 if (plist != list->prev) {
545 flag += 1;
546 }
547 plist = list;
548 list = list->next;
549 }
550
551 if (anchor->last != plist && anchor->last != 0) {
552 flag |= 0x70000;
553 }
554
555 if (flag != 0) {
556 rb_bug("list verify error: %08x (%s)", flag, info);
557 }
558#endif
559}
560#if CPDEBUG < 0
561#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
562#endif
563
564static void
565verify_call_cache(rb_iseq_t *iseq)
566{
567#if CPDEBUG
568 VALUE *original = rb_iseq_original_iseq(iseq);
569 size_t i = 0;
570 while (i < ISEQ_BODY(iseq)->iseq_size) {
571 VALUE insn = original[i];
572 const char *types = insn_op_types(insn);
573
574 for (int j=0; types[j]; j++) {
575 if (types[j] == TS_CALLDATA) {
576 struct rb_call_data *cd = (struct rb_call_data *)original[i+j+1];
577 const struct rb_callinfo *ci = cd->ci;
578 const struct rb_callcache *cc = cd->cc;
579 if (cc != vm_cc_empty()) {
580 vm_ci_dump(ci);
581 rb_bug("call cache is not initialized by vm_cc_empty()");
582 }
583 }
584 }
585 i += insn_len(insn);
586 }
587
588 for (unsigned int i=0; i<ISEQ_BODY(iseq)->ci_size; i++) {
589 struct rb_call_data *cd = &ISEQ_BODY(iseq)->call_data[i];
590 const struct rb_callinfo *ci = cd->ci;
591 const struct rb_callcache *cc = cd->cc;
592 if (cc != NULL && cc != vm_cc_empty()) {
593 vm_ci_dump(ci);
594 rb_bug("call cache is not initialized by vm_cc_empty()");
595 }
596 }
597#endif
598}
599
600/*
601 * elem1, elem2 => elem1, elem2, elem
602 */
603static void
604ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *elem)
605{
606 elem->prev = anchor->last;
607 anchor->last->next = elem;
608 anchor->last = elem;
609 verify_list("add", anchor);
610}
611
612/*
613 * elem1, before, elem2 => elem1, before, elem, elem2
614 */
615static void
616APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
617{
618 elem->prev = before;
619 elem->next = before->next;
620 elem->next->prev = elem;
621 before->next = elem;
622 if (before == anchor->last) anchor->last = elem;
623 verify_list("add", anchor);
624}
625#if CPDEBUG < 0
626#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
627#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
628#endif
629
630static int
631branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
632{
633 if (!ISEQ_COVERAGE(iseq)) return 0;
634 if (!ISEQ_BRANCH_COVERAGE(iseq)) return 0;
635 if (first_line <= 0) return 0;
636 return 1;
637}
638
639static VALUE
640setup_branch(const rb_code_location_t *loc, const char *type, VALUE structure, VALUE key)
641{
642 const int first_lineno = loc->beg_pos.lineno, first_column = loc->beg_pos.column;
643 const int last_lineno = loc->end_pos.lineno, last_column = loc->end_pos.column;
644 VALUE branch = rb_ary_hidden_new(6);
645
646 rb_hash_aset(structure, key, branch);
647 rb_ary_push(branch, ID2SYM(rb_intern(type)));
648 rb_ary_push(branch, INT2FIX(first_lineno));
649 rb_ary_push(branch, INT2FIX(first_column));
650 rb_ary_push(branch, INT2FIX(last_lineno));
651 rb_ary_push(branch, INT2FIX(last_column));
652 return branch;
653}
654
655static VALUE
656decl_branch_base(rb_iseq_t *iseq, int node_id, const rb_code_location_t *loc, const char *type)
657{
658 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return Qundef;
659
660 /*
661 * A branch base is keyed by [source_hash (in two halves), node_id, first_lineno],
662 * which identifies the branch node stably even across (re-)evals against
663 * the same path.
664 *
665 * if !structure[key]
666 * structure[key] = [type, first_lineno, first_column, last_lineno, last_column, branches = {}]
667 * else
668 * branches = structure[key][5]
669 * end
670 */
671 uint64_t source_hash = ISEQ_BODY(iseq)->source_hash;
672 VALUE key = rb_ary_new_from_args(4,
673 ULONG2NUM((unsigned long)(source_hash >> 32)),
674 ULONG2NUM((unsigned long)(source_hash & 0xffffffff)),
675 INT2FIX(node_id),
676 INT2FIX(loc->beg_pos.lineno));
677 rb_ary_freeze(key);
678
679 VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
680 VALUE branch_base = rb_hash_aref(structure, key);
681 VALUE branches;
682
683 if (NIL_P(branch_base)) {
684 branch_base = setup_branch(loc, type, structure, key);
685 branches = rb_hash_new();
686 rb_obj_hide(branches);
687 rb_ary_push(branch_base, branches);
688 }
689 else {
690 branches = RARRAY_AREF(branch_base, 5);
691 }
692
693 return branches;
694}
695
696static NODE
697generate_dummy_line_node(int lineno, int node_id)
698{
699 NODE dummy = { 0 };
700 nd_set_line(&dummy, lineno);
701 nd_set_node_id(&dummy, node_id);
702 return dummy;
703}
704
705static void
706add_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)
707{
708 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return;
709
710 /*
711 * if !branches[branch_id]
712 * branches[branch_id] = [type, first_lineno, first_column, last_lineno, last_column, counter_idx]
713 * else
714 * counter_idx= branches[branch_id][5]
715 * end
716 */
717
718 VALUE key = INT2FIX(branch_id);
719 VALUE branch = rb_hash_aref(branches, key);
720 long counter_idx;
721
722 if (NIL_P(branch)) {
723 branch = setup_branch(loc, type, branches, key);
724 VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
725 counter_idx = RARRAY_LEN(counters);
726 rb_ary_push(branch, LONG2FIX(counter_idx));
727 rb_ary_push(counters, INT2FIX(0));
728 }
729 else {
730 counter_idx = FIX2LONG(RARRAY_AREF(branch, 5));
731 }
732
733 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
734 ADD_SYNTHETIC_INSN(seq, loc->end_pos.lineno, node_id, nop);
735}
736
737#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
738
739static int
740validate_label(st_data_t name, st_data_t label, st_data_t arg)
741{
742 rb_iseq_t *iseq = (rb_iseq_t *)arg;
743 LABEL *lobj = (LABEL *)label;
744 if (!lobj->link.next) {
745 do {
746 COMPILE_ERROR(iseq, lobj->position,
747 "%"PRIsVALUE": undefined label",
748 rb_sym2str((VALUE)name));
749 } while (0);
750 }
751 return ST_CONTINUE;
752}
753
754static void
755validate_labels(rb_iseq_t *iseq, st_table *labels_table)
756{
757 st_foreach(labels_table, validate_label, (st_data_t)iseq);
758 st_free_table(labels_table);
759}
760
761static NODE *
762get_nd_recv(const NODE *node)
763{
764 switch (nd_type(node)) {
765 case NODE_CALL:
766 return RNODE_CALL(node)->nd_recv;
767 case NODE_OPCALL:
768 return RNODE_OPCALL(node)->nd_recv;
769 case NODE_FCALL:
770 return 0;
771 case NODE_QCALL:
772 return RNODE_QCALL(node)->nd_recv;
773 case NODE_VCALL:
774 return 0;
775 case NODE_ATTRASGN:
776 return RNODE_ATTRASGN(node)->nd_recv;
777 case NODE_OP_ASGN1:
778 return RNODE_OP_ASGN1(node)->nd_recv;
779 case NODE_OP_ASGN2:
780 return RNODE_OP_ASGN2(node)->nd_recv;
781 default:
782 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
783 }
784}
785
786static ID
787get_node_call_nd_mid(const NODE *node)
788{
789 switch (nd_type(node)) {
790 case NODE_CALL:
791 return RNODE_CALL(node)->nd_mid;
792 case NODE_OPCALL:
793 return RNODE_OPCALL(node)->nd_mid;
794 case NODE_FCALL:
795 return RNODE_FCALL(node)->nd_mid;
796 case NODE_QCALL:
797 return RNODE_QCALL(node)->nd_mid;
798 case NODE_VCALL:
799 return RNODE_VCALL(node)->nd_mid;
800 case NODE_ATTRASGN:
801 return RNODE_ATTRASGN(node)->nd_mid;
802 default:
803 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
804 }
805}
806
807static NODE *
808get_nd_args(const NODE *node)
809{
810 switch (nd_type(node)) {
811 case NODE_CALL:
812 return RNODE_CALL(node)->nd_args;
813 case NODE_OPCALL:
814 return RNODE_OPCALL(node)->nd_args;
815 case NODE_FCALL:
816 return RNODE_FCALL(node)->nd_args;
817 case NODE_QCALL:
818 return RNODE_QCALL(node)->nd_args;
819 case NODE_VCALL:
820 return 0;
821 case NODE_ATTRASGN:
822 return RNODE_ATTRASGN(node)->nd_args;
823 default:
824 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
825 }
826}
827
828static ID
829get_node_colon_nd_mid(const NODE *node)
830{
831 switch (nd_type(node)) {
832 case NODE_COLON2:
833 return RNODE_COLON2(node)->nd_mid;
834 case NODE_COLON3:
835 return RNODE_COLON3(node)->nd_mid;
836 default:
837 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
838 }
839}
840
841static ID
842get_nd_vid(const NODE *node)
843{
844 switch (nd_type(node)) {
845 case NODE_LASGN:
846 return RNODE_LASGN(node)->nd_vid;
847 case NODE_DASGN:
848 return RNODE_DASGN(node)->nd_vid;
849 case NODE_IASGN:
850 return RNODE_IASGN(node)->nd_vid;
851 case NODE_CVASGN:
852 return RNODE_CVASGN(node)->nd_vid;
853 default:
854 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
855 }
856}
857
858static NODE *
859get_nd_value(const NODE *node)
860{
861 switch (nd_type(node)) {
862 case NODE_LASGN:
863 return RNODE_LASGN(node)->nd_value;
864 case NODE_DASGN:
865 return RNODE_DASGN(node)->nd_value;
866 default:
867 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
868 }
869}
870
871static VALUE
872get_string_value(const NODE *node)
873{
874 switch (nd_type(node)) {
875 case NODE_STR:
876 return RB_OBJ_SET_SHAREABLE(rb_node_str_string_val(node));
877 case NODE_FILE:
878 return RB_OBJ_SET_SHAREABLE(rb_node_file_path_val(node));
879 default:
880 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
881 }
882}
883
884VALUE
885rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
886{
887 DECL_ANCHOR(ret);
888 INIT_ANCHOR(ret);
889
890 (*ifunc->func)(iseq, ret, ifunc->data);
891
892 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
893
894 CHECK(iseq_setup_insn(iseq, ret));
895 return iseq_setup(iseq, ret);
896}
897
898static bool drop_unreachable_return(LINK_ANCHOR *ret);
899
900VALUE
901rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
902{
903 DECL_ANCHOR(ret);
904 INIT_ANCHOR(ret);
905
906 if (node == 0) {
907 NO_CHECK(COMPILE(ret, "nil", node));
908 iseq_set_local_table(iseq, 0, 0);
909 }
910 /* assume node is T_NODE */
911 else if (nd_type_p(node, NODE_SCOPE)) {
912 /* iseq type of top, method, class, block */
913 iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl, (NODE *)RNODE_SCOPE(node)->nd_args);
914 iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
915 iseq_set_parameters_lvar_state(iseq);
916
917 switch (ISEQ_BODY(iseq)->type) {
918 case ISEQ_TYPE_BLOCK:
919 {
920 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
921 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
922
923 start->rescued = LABEL_RESCUE_BEG;
924 end->rescued = LABEL_RESCUE_END;
925
926 ADD_TRACE(ret, RUBY_EVENT_B_CALL);
927 ADD_SYNTHETIC_INSN(ret, ISEQ_BODY(iseq)->location.first_lineno, -1, nop);
928 ADD_LABEL(ret, start);
929 CHECK(COMPILE(ret, "block body", RNODE_SCOPE(node)->nd_body));
930 ADD_LABEL(ret, end);
931 ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
932 ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
933
934 /* wide range catch handler must put at last */
935 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
936 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
937 break;
938 }
939 case ISEQ_TYPE_CLASS:
940 {
941 ADD_TRACE(ret, RUBY_EVENT_CLASS);
942 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
943 ADD_TRACE(ret, RUBY_EVENT_END);
944 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
945 break;
946 }
947 case ISEQ_TYPE_METHOD:
948 {
949 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
950 ADD_TRACE(ret, RUBY_EVENT_CALL);
951 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
952 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
953 ADD_TRACE(ret, RUBY_EVENT_RETURN);
954 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
955 break;
956 }
957 default: {
958 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
959 break;
960 }
961 }
962 }
963 else {
964 const char *m;
965#define INVALID_ISEQ_TYPE(type) \
966 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
967 switch (ISEQ_BODY(iseq)->type) {
968 case INVALID_ISEQ_TYPE(METHOD);
969 case INVALID_ISEQ_TYPE(CLASS);
970 case INVALID_ISEQ_TYPE(BLOCK);
971 case INVALID_ISEQ_TYPE(EVAL);
972 case INVALID_ISEQ_TYPE(MAIN);
973 case INVALID_ISEQ_TYPE(TOP);
974#undef INVALID_ISEQ_TYPE /* invalid iseq types end */
975 case ISEQ_TYPE_RESCUE:
976 iseq_set_exception_local_table(iseq);
977 CHECK(COMPILE(ret, "rescue", node));
978 break;
979 case ISEQ_TYPE_ENSURE:
980 iseq_set_exception_local_table(iseq);
981 CHECK(COMPILE_POPPED(ret, "ensure", node));
982 break;
983 case ISEQ_TYPE_PLAIN:
984 CHECK(COMPILE(ret, "ensure", node));
985 break;
986 default:
987 COMPILE_ERROR(ERROR_ARGS "unknown scope: %d", ISEQ_BODY(iseq)->type);
988 return COMPILE_NG;
989 invalid_iseq_type:
990 COMPILE_ERROR(ERROR_ARGS "compile/ISEQ_TYPE_%s should not be reached", m);
991 return COMPILE_NG;
992 }
993 }
994
995 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE || ISEQ_BODY(iseq)->type == ISEQ_TYPE_ENSURE) {
996 NODE dummy_line_node = generate_dummy_line_node(0, -1);
997 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
998 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0) /* continue throw */ );
999 }
1000 else if (!drop_unreachable_return(ret)) {
1001 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
1002 }
1003
1004#if OPT_SUPPORT_JOKE
1005 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
1006 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
1007 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
1008 validate_labels(iseq, labels_table);
1009 }
1010#endif
1011 CHECK(iseq_setup_insn(iseq, ret));
1012 return iseq_setup(iseq, ret);
1013}
1014
1015static int
1016rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
1017{
1018#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1019 const void * const *table = rb_vm_get_insns_address_table();
1020 unsigned int i;
1021 VALUE *encoded = (VALUE *)ISEQ_BODY(iseq)->iseq_encoded;
1022
1023 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
1024 int insn = (int)ISEQ_BODY(iseq)->iseq_encoded[i];
1025 int len = insn_len(insn);
1026 encoded[i] = (VALUE)table[insn];
1027 i += len;
1028 }
1029#endif
1030 FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
1031
1032#if USE_YJIT
1033 rb_yjit_live_iseq_count++;
1034 rb_yjit_iseq_alloc_count++;
1035#endif
1036
1037 return COMPILE_OK;
1038}
1039
1040VALUE *
1041rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
1042{
1043 struct rb_iseq_variable *v = ISEQ_VARIABLE(iseq);
1044 VALUE *original_code = v ? RUBY_ATOMIC_PTR_LOAD(v->original_iseq) : NULL;
1045
1046 if (original_code) return original_code;
1047 original_code = ALLOC_N(VALUE, ISEQ_BODY(iseq)->iseq_size);
1048 MEMCPY(original_code, ISEQ_BODY(iseq)->iseq_encoded, VALUE, ISEQ_BODY(iseq)->iseq_size);
1049
1050 {
1051 unsigned int i;
1052
1053 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
1054 const void *addr = (const void *)original_code[i];
1055 const int insn = rb_vm_insn_addr2insn(addr);
1056
1057 original_code[i] = insn;
1058 i += insn_len(insn);
1059 }
1060 }
1061
1062 /* Concurrent callers can each build a copy; publish only fully
1063 * translated code and keep the first one. */
1064 v = rb_iseq_variable_ensure((rb_iseq_t *)iseq);
1065 VALUE *prev = ATOMIC_PTR_CAS(v->original_iseq,
1066 NULL, original_code);
1067 if (prev) {
1068 SIZED_FREE_N(original_code, ISEQ_BODY(iseq)->iseq_size);
1069 return prev;
1070 }
1071 return original_code;
1072}
1073
1074/*********************************************/
1075/* definition of data structure for compiler */
1076/*********************************************/
1077
1078#if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
1079# define ALIGNMENT_SIZE SIZEOF_LONG_LONG
1080#else
1081# define ALIGNMENT_SIZE SIZEOF_VALUE
1082#endif
1083#define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
1084
1085#define ALIGNMENT_SIZE_OF(type) alignment_size_assert(RUBY_ALIGNOF(type), #type)
1086
1087static inline size_t
1088alignment_size_assert(size_t align, const char *type)
1089{
1090 RUBY_ASSERT((align & (align - 1)) == 0,
1091 "ALIGNMENT_SIZE_OF(%s):%zd == (2 ** N) is expected", type, align);
1092 return align;
1093}
1094
1095/* calculate padding size for aligned memory access */
1096static inline size_t
1097calc_padding(void *ptr, size_t align)
1098{
1099 size_t mis;
1100 size_t padding = 0;
1101
1102 mis = (size_t)ptr & (align - 1);
1103 if (mis > 0) {
1104 padding = align - mis;
1105 }
1106
1107 return padding;
1108}
1109
1110static void *
1111compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size, size_t align)
1112{
1113 void *ptr = 0;
1114 struct iseq_compile_data_storage *storage = *arena;
1115 size_t padding = calc_padding((void *)&storage->buff[storage->pos], align);
1116
1117 if (size >= INT_MAX - padding) rb_memerror();
1118 if (storage->pos + size + padding > storage->size) {
1119 unsigned int alloc_size = storage->size;
1120
1121 while (alloc_size < size + PADDING_SIZE_MAX) {
1122 if (alloc_size >= INT_MAX / 2) rb_memerror();
1123 alloc_size *= 2;
1124 }
1125 storage->next = (void *)ALLOC_N(char, alloc_size +
1126 offsetof(struct iseq_compile_data_storage, buff));
1127 storage = *arena = storage->next;
1128 storage->next = 0;
1129 storage->pos = 0;
1130 storage->size = alloc_size;
1131 padding = calc_padding((void *)&storage->buff[storage->pos], align);
1132 }
1133
1134 storage->pos += (int)padding;
1135
1136 ptr = (void *)&storage->buff[storage->pos];
1137 storage->pos += (int)size;
1138 return ptr;
1139}
1140
1141static void *
1142compile_data_alloc(rb_iseq_t *iseq, size_t size, size_t align)
1143{
1144 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
1145 return compile_data_alloc_with_arena(arena, size, align);
1146}
1147
1148#define compile_data_alloc_type(iseq, type) \
1149 (type *)compile_data_alloc(iseq, sizeof(type), ALIGNMENT_SIZE_OF(type))
1150
1151static inline void *
1152compile_data_alloc2(rb_iseq_t *iseq, size_t elsize, size_t num, size_t align)
1153{
1154 size_t size = rb_size_mul_or_raise(elsize, num, rb_eRuntimeError);
1155 return compile_data_alloc(iseq, size, align);
1156}
1157
1158#define compile_data_alloc2_type(iseq, type, num) \
1159 (type *)compile_data_alloc2(iseq, sizeof(type), num, ALIGNMENT_SIZE_OF(type))
1160
1161static inline void *
1162compile_data_calloc2(rb_iseq_t *iseq, size_t elsize, size_t num, size_t align)
1163{
1164 size_t size = rb_size_mul_or_raise(elsize, num, rb_eRuntimeError);
1165 void *p = compile_data_alloc(iseq, size, align);
1166 memset(p, 0, size);
1167 return p;
1168}
1169
1170#define compile_data_calloc2_type(iseq, type, num) \
1171 (type *)compile_data_calloc2(iseq, sizeof(type), num, ALIGNMENT_SIZE_OF(type))
1172
1173static INSN *
1174compile_data_alloc_insn(rb_iseq_t *iseq)
1175{
1176 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
1177 return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN), ALIGNMENT_SIZE_OF(INSN));
1178}
1179
1180static LABEL *
1181compile_data_alloc_label(rb_iseq_t *iseq)
1182{
1183 return compile_data_alloc_type(iseq, LABEL);
1184}
1185
1186static ADJUST *
1187compile_data_alloc_adjust(rb_iseq_t *iseq)
1188{
1189 return compile_data_alloc_type(iseq, ADJUST);
1190}
1191
1192static TRACE *
1193compile_data_alloc_trace(rb_iseq_t *iseq)
1194{
1195 return compile_data_alloc_type(iseq, TRACE);
1196}
1197
1198/*
1199 * elem1, elemX => elem1, elem2, elemX
1200 */
1201static void
1202ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1203{
1204 elem2->next = elem1->next;
1205 elem2->prev = elem1;
1206 elem1->next = elem2;
1207 if (elem2->next) {
1208 elem2->next->prev = elem2;
1209 }
1210}
1211
1212/*
1213 * elem1, elemX => elemX, elem2, elem1
1214 */
1215static void
1216ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1217{
1218 elem2->prev = elem1->prev;
1219 elem2->next = elem1;
1220 elem1->prev = elem2;
1221 if (elem2->prev) {
1222 elem2->prev->next = elem2;
1223 }
1224}
1225
1226/*
1227 * elemX, elem1, elemY => elemX, elem2, elemY
1228 */
1229static void
1230ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1231{
1232 elem2->prev = elem1->prev;
1233 elem2->next = elem1->next;
1234 if (elem1->prev) {
1235 elem1->prev->next = elem2;
1236 }
1237 if (elem1->next) {
1238 elem1->next->prev = elem2;
1239 }
1240}
1241
1242static void
1243ELEM_REMOVE(LINK_ELEMENT *elem)
1244{
1245 elem->prev->next = elem->next;
1246 if (elem->next) {
1247 elem->next->prev = elem->prev;
1248 }
1249}
1250
1251/*
1252 * elem1, elem2 => elem2, elem1
1253 */
1254static void
1255ELEM_SWAP(LINK_ELEMENT *first, LINK_ELEMENT *second)
1256{
1257 RUBY_ASSERT(first->next == second);
1258 RUBY_ASSERT(first == second->prev);
1259
1260 first->prev->next = second;
1261 second->next->prev = first;
1262
1263 first->next = second->next;
1264 second->next = first;
1265
1266 second->prev = first->prev;
1267 first->prev = second;
1268
1269 if (IS_INSN(first) && IS_INSN(second)) {
1270 INSN *first_insn = (INSN*)first;
1271 INSN *second_insn = (INSN*)second;
1272
1273 // [Bug #22299] If both instructions are on the same line and the first one carries
1274 // a line event we need to swap the event as well.
1275 if (first_insn->insn_info.line_no == second_insn->insn_info.line_no) {
1276 rb_event_flag_t mask = (RUBY_EVENT_LINE | RUBY_EVENT_COVERAGE_LINE);
1277 rb_event_flag_t first_events = first_insn->insn_info.events & mask;
1278 rb_event_flag_t second_events = second_insn->insn_info.events & mask;
1279 first_insn->insn_info.events = (first_insn->insn_info.events & ~mask) | second_events;
1280 second_insn->insn_info.events = (second_insn->insn_info.events & ~mask) | first_events;
1281 }
1282 }
1283}
1284
1285static LINK_ELEMENT *
1286FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
1287{
1288 return anchor->anchor.next;
1289}
1290
1291static LINK_ELEMENT *
1292LAST_ELEMENT(LINK_ANCHOR *const anchor)
1293{
1294 return anchor->last;
1295}
1296
1297static LINK_ELEMENT *
1298ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1299{
1300 while (elem) {
1301 switch (elem->type) {
1302 case ISEQ_ELEMENT_INSN:
1303 case ISEQ_ELEMENT_ADJUST:
1304 return elem;
1305 default:
1306 elem = elem->next;
1307 }
1308 }
1309 return NULL;
1310}
1311
1312static int
1313LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1314{
1315 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1316 if (first_insn != NULL &&
1317 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1318 return TRUE;
1319 }
1320 else {
1321 return FALSE;
1322 }
1323}
1324
1325static int
1326LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1327{
1328 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1329 return TRUE;
1330 }
1331 else {
1332 return FALSE;
1333 }
1334}
1335
1336/*
1337 * anc1: e1, e2, e3
1338 * anc2: e4, e5
1339 *#=>
1340 * anc1: e1, e2, e3, e4, e5
1341 * anc2: e4, e5 (broken)
1342 */
1343static void
1344APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1345{
1346 if (anc2->anchor.next) {
1347 /* LINK_ANCHOR must not loop */
1348 RUBY_ASSERT(anc2->last != &anc2->anchor);
1349 anc1->last->next = anc2->anchor.next;
1350 anc2->anchor.next->prev = anc1->last;
1351 anc1->last = anc2->last;
1352 }
1353 else {
1354 RUBY_ASSERT(anc2->last == &anc2->anchor);
1355 }
1356 verify_list("append", anc1);
1357}
1358#if CPDEBUG < 0
1359#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1360#endif
1361
1362#if CPDEBUG && 0
1363static void
1364debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *cur)
1365{
1366 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1367 printf("----\n");
1368 printf("anch: %p, frst: %p, last: %p\n", (void *)&anchor->anchor,
1369 (void *)anchor->anchor.next, (void *)anchor->last);
1370 while (list) {
1371 printf("curr: %p, next: %p, prev: %p, type: %d\n", (void *)list, (void *)list->next,
1372 (void *)list->prev, (int)list->type);
1373 list = list->next;
1374 }
1375 printf("----\n");
1376
1377 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1378 verify_list("debug list", anchor);
1379}
1380#if CPDEBUG < 0
1381#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1382#endif
1383#else
1384#define debug_list(anc, cur) ((void)0)
1385#endif
1386
1387static TRACE *
1388new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1389{
1390 TRACE *trace = compile_data_alloc_trace(iseq);
1391
1392 trace->link.type = ISEQ_ELEMENT_TRACE;
1393 trace->link.next = NULL;
1394 trace->event = event;
1395 trace->data = data;
1396
1397 return trace;
1398}
1399
1400static LABEL *
1401new_label_body(rb_iseq_t *iseq, long line)
1402{
1403 LABEL *labelobj = compile_data_alloc_label(iseq);
1404
1405 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1406 labelobj->link.next = 0;
1407
1408 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1409 labelobj->sc_state = 0;
1410 labelobj->sp = -1;
1411 labelobj->refcnt = 0;
1412 labelobj->set = 0;
1413 labelobj->rescued = LABEL_RESCUE_NONE;
1414 labelobj->unremovable = 0;
1415 labelobj->position = -1;
1416 return labelobj;
1417}
1418
1419static ADJUST *
1420new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1421{
1422 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1423 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1424 adjust->link.next = 0;
1425 adjust->label = label;
1426 adjust->line_no = line;
1427 LABEL_UNREMOVABLE(label);
1428 return adjust;
1429}
1430
1431static void
1432iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE *, VALUE), VALUE data)
1433{
1434 const char *types = insn_op_types(insn->insn_id);
1435 for (int j = 0; types[j]; j++) {
1436 char type = types[j];
1437 switch (type) {
1438 case TS_CDHASH:
1439 case TS_ISEQ:
1440 case TS_VALUE:
1441 case TS_IC: // constant path array
1442 case TS_CALLDATA: // ci is stored.
1443 func(&OPERAND_AT(insn, j), data);
1444 break;
1445 default:
1446 break;
1447 }
1448 }
1449}
1450
1451static void
1452iseq_insn_each_object_write_barrier(VALUE * obj, VALUE iseq)
1453{
1454 RB_OBJ_WRITTEN(iseq, Qundef, *obj);
1456 RBASIC_CLASS(*obj) == 0 || // hidden
1457 RB_OBJ_SHAREABLE_P(*obj));
1458}
1459
1460static INSN *
1461new_insn_core(rb_iseq_t *iseq, int line_no, int node_id, int insn_id, int argc, VALUE *argv)
1462{
1463 INSN *iobj = compile_data_alloc_insn(iseq);
1464
1465 /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1466
1467 iobj->link.type = ISEQ_ELEMENT_INSN;
1468 iobj->link.next = 0;
1469 iobj->insn_id = insn_id;
1470 iobj->insn_info.line_no = line_no;
1471 iobj->insn_info.node_id = node_id;
1472 iobj->insn_info.events = 0;
1473 iobj->operands = argv;
1474 iobj->operand_size = argc;
1475 iobj->sc_state = 0;
1476
1477 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1478
1479 return iobj;
1480}
1481
1482static INSN *
1483new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...)
1484{
1485 VALUE *operands = 0;
1486 va_list argv;
1487 if (argc > 0) {
1488 int i;
1489 va_start(argv, argc);
1490 operands = compile_data_alloc2_type(iseq, VALUE, argc);
1491 for (i = 0; i < argc; i++) {
1492 VALUE v = va_arg(argv, VALUE);
1493 operands[i] = v;
1494 }
1495 va_end(argv);
1496 }
1497 return new_insn_core(iseq, line_no, node_id, insn_id, argc, operands);
1498}
1499
1500static INSN *
1501insn_replace_with_operands(rb_iseq_t *iseq, INSN *iobj, enum ruby_vminsn_type insn_id, int argc, ...)
1502{
1503 VALUE *operands = 0;
1504 va_list argv;
1505 if (argc > 0) {
1506 int i;
1507 va_start(argv, argc);
1508 operands = compile_data_alloc2_type(iseq, VALUE, argc);
1509 for (i = 0; i < argc; i++) {
1510 VALUE v = va_arg(argv, VALUE);
1511 operands[i] = v;
1512 }
1513 va_end(argv);
1514 }
1515
1516 iobj->insn_id = insn_id;
1517 iobj->operand_size = argc;
1518 iobj->operands = operands;
1519 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1520
1521 return iobj;
1522}
1523
1524static const struct rb_callinfo *
1525new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1526{
1527 VM_ASSERT(argc >= 0);
1528
1529 if (kw_arg) {
1530 flag |= VM_CALL_KWARG;
1531 argc += kw_arg->keyword_len;
1532 }
1533
1534 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING))
1535 && !has_blockiseq) {
1536 flag |= VM_CALL_ARGS_SIMPLE;
1537 }
1538
1539 ISEQ_BODY(iseq)->ci_size++;
1540 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1541 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1542 return ci;
1543}
1544
1545static INSN *
1546new_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)
1547{
1548 VALUE *operands = compile_data_calloc2_type(iseq, VALUE, 2);
1549 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1550 operands[0] = ci;
1551 operands[1] = (VALUE)blockiseq;
1552 if (blockiseq) {
1553 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1554 }
1555
1556 INSN *insn;
1557
1558 if (vm_ci_flag((struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
1559 insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
1560 }
1561 else {
1562 insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1563 }
1564
1565 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1566 RB_GC_GUARD(ci);
1567 return insn;
1568}
1569
1570static rb_iseq_t *
1571new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1572 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1573{
1574 rb_iseq_t *ret_iseq;
1575 VALUE ast_value = rb_ruby_ast_new(node);
1576
1577 // The child AST wrapper does not carry the source hash, so copy it from
1578 // the enclosing iseq before compiling, for grandchildren to inherit it.
1579 if (ISEQ_BODY(iseq)->source_hash) {
1580 rb_ast_t *child_ast = rb_ruby_ast_data_get(ast_value);
1581 child_ast->body.source_hash = ISEQ_BODY(iseq)->source_hash;
1582 child_ast->body.has_source_hash = 1;
1583 }
1584
1585 debugs("[new_child_iseq]> ---------------------------------------\n");
1586 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1587 ret_iseq = rb_iseq_new_with_opt(ast_value, name,
1588 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1589 line_no, parent,
1590 isolated_depth ? isolated_depth + 1 : 0,
1591 type, ISEQ_COMPILE_DATA(iseq)->option,
1592 ISEQ_SCRIPT_LINES(iseq));
1593 debugs("[new_child_iseq]< ---------------------------------------\n");
1594 return ret_iseq;
1595}
1596
1597static rb_iseq_t *
1598new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1599 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1600{
1601 rb_iseq_t *ret_iseq;
1602
1603 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1604 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1605 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1606 line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1607 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1608 return ret_iseq;
1609}
1610
1611static void
1612set_catch_except_p(rb_iseq_t *iseq)
1613{
1614 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1615 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1616 if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1617 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1618 set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1619 }
1620 }
1621}
1622
1623/* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1624 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1625 if catch table exists. But we want to optimize while loop, which always has catch
1626 table entries for break/next/redo.
1627
1628 So this function sets true for limited ISeqs with break/next/redo catch table entries
1629 whose child ISeq would really raise an exception. */
1630static void
1631update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
1632{
1633 unsigned int pos;
1634 size_t i;
1635 int insn;
1636 const struct iseq_catch_table *ct = body->catch_table;
1637
1638 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1639 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1640 pos = 0;
1641 while (pos < body->iseq_size) {
1642 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1643 if (insn == BIN(throw)) {
1644 set_catch_except_p(iseq);
1645 break;
1646 }
1647 pos += insn_len(insn);
1648 }
1649
1650 if (ct == NULL)
1651 return;
1652
1653 for (i = 0; i < ct->size; i++) {
1654 const struct iseq_catch_table_entry *entry =
1655 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1656 if (entry->type != CATCH_TYPE_BREAK
1657 && entry->type != CATCH_TYPE_NEXT
1658 && entry->type != CATCH_TYPE_REDO) {
1659 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1660 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1661 break;
1662 }
1663 }
1664}
1665
1666static void
1667iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1668{
1669 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1670 if (NIL_P(catch_table_ary)) return;
1671 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1672 const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
1673 for (i = 0; i < tlen; i++) {
1674 const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
1675 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1676 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1677 LINK_ELEMENT *e;
1678
1679 enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1680
1681 if (ct != CATCH_TYPE_BREAK
1682 && ct != CATCH_TYPE_NEXT
1683 && ct != CATCH_TYPE_REDO) {
1684
1685 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1686 if (e == cont) {
1687 INSN *nop = new_insn_core(iseq, 0, -1, BIN(nop), 0, 0);
1688 ELEM_INSERT_NEXT(end, &nop->link);
1689 break;
1690 }
1691 }
1692 }
1693 }
1694
1695 RB_GC_GUARD(catch_table_ary);
1696}
1697
1698static int
1699iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1700{
1701 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1702 return COMPILE_NG;
1703
1704 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1705
1706 if (compile_debug > 5)
1707 dump_disasm_list(FIRST_ELEMENT(anchor));
1708
1709 debugs("[compile step 3.1 (iseq_optimize)]\n");
1710 iseq_optimize(iseq, anchor);
1711
1712 if (compile_debug > 5)
1713 dump_disasm_list(FIRST_ELEMENT(anchor));
1714
1715 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1716 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1717 iseq_insns_unification(iseq, anchor);
1718 if (compile_debug > 5)
1719 dump_disasm_list(FIRST_ELEMENT(anchor));
1720 }
1721
1722 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1723 iseq_insert_nop_between_end_and_cont(iseq);
1724 if (compile_debug > 5)
1725 dump_disasm_list(FIRST_ELEMENT(anchor));
1726
1727 return COMPILE_OK;
1728}
1729
1730static int
1731iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1732{
1733 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1734 return COMPILE_NG;
1735
1736 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1737 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1738 if (compile_debug > 5)
1739 dump_disasm_list(FIRST_ELEMENT(anchor));
1740
1741 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1742 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1743
1744 debugs("[compile step 4.3 (set_optargs_table)] \n");
1745 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1746
1747 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1748 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1749
1750 debugs("[compile step 6 (update_catch_except_flags)] \n");
1751 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1752 update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1753
1754 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1755 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1756 if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1757 ruby_xfree_sized(ISEQ_BODY(iseq)->catch_table, iseq_catch_table_bytes(ISEQ_BODY(iseq)->catch_table->size));
1758 ISEQ_BODY(iseq)->catch_table = NULL;
1759 }
1760
1761#if VM_INSN_INFO_TABLE_IMPL == 2
1762 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1763 rb_iseq_insns_info_encode_positions(iseq);
1764#endif
1765
1766 if (compile_debug > 1) {
1767 VALUE str = rb_iseq_disasm(iseq);
1768 printf("%s\n", StringValueCStr(str));
1769 }
1770 verify_call_cache(iseq);
1771 debugs("[compile step: finish]\n");
1772
1773 return COMPILE_OK;
1774}
1775
1776static int
1777iseq_set_exception_local_table(rb_iseq_t *iseq)
1778{
1779 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1780 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1781 ISEQ_BODY(iseq)->lvar_states.list = NULL; // $! is read-only, so don't need lvar_states
1782 return COMPILE_OK;
1783}
1784
1785static int
1786get_lvar_level(const rb_iseq_t *iseq)
1787{
1788 int lev = 0;
1789 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1790 lev++;
1791 iseq = ISEQ_BODY(iseq)->parent_iseq;
1792 }
1793 return lev;
1794}
1795
1796static int
1797get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1798{
1799 unsigned int i;
1800
1801 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1802 if (ISEQ_BODY(iseq)->local_table[i] == id) {
1803 return (int)i;
1804 }
1805 }
1806 return -1;
1807}
1808
1809static int
1810get_local_var_idx(const rb_iseq_t *iseq, ID id)
1811{
1812 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1813
1814 if (idx < 0) {
1815 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1816 "get_local_var_idx: %d", idx);
1817 }
1818
1819 return idx;
1820}
1821
1822static int
1823get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1824{
1825 int lv = 0, idx = -1;
1826 const rb_iseq_t *const topmost_iseq = iseq;
1827
1828 while (iseq) {
1829 idx = get_dyna_var_idx_at_raw(iseq, id);
1830 if (idx >= 0) {
1831 break;
1832 }
1833 iseq = ISEQ_BODY(iseq)->parent_iseq;
1834 lv++;
1835 }
1836
1837 if (idx < 0) {
1838 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1839 "get_dyna_var_idx: -1");
1840 }
1841
1842 *level = lv;
1843 *ls = ISEQ_BODY(iseq)->local_table_size;
1844 return idx;
1845}
1846
1847static int
1848iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1849{
1850 const struct rb_iseq_constant_body *body;
1851 while (level > 0) {
1852 iseq = ISEQ_BODY(iseq)->parent_iseq;
1853 level--;
1854 }
1855 body = ISEQ_BODY(iseq);
1856 if (body->local_iseq == iseq && /* local variables */
1857 body->param.flags.has_block &&
1858 body->local_table_size - body->param.block_start == idx) {
1859 return TRUE;
1860 }
1861 else {
1862 return FALSE;
1863 }
1864}
1865
1866static int
1867iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1868{
1869 int level, ls;
1870 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1871 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1872 *pidx = ls - idx;
1873 *plevel = level;
1874 return TRUE;
1875 }
1876 else {
1877 return FALSE;
1878 }
1879}
1880
1881static void
1882access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1883{
1884 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1885
1886 if (isolated_depth && level >= isolated_depth) {
1887 if (id == rb_intern("yield")) {
1888 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1889 }
1890 else {
1891 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable '%s' from isolated Proc", rb_id2name(id));
1892 }
1893 }
1894
1895 for (int i=0; i<level; i++) {
1896 VALUE val;
1897 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1898
1899 if (!ovs) {
1900 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1901 }
1902
1903 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1904 if (write && !val) {
1905 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1906 }
1907 }
1908 else {
1909 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1910 }
1911
1912 iseq = ISEQ_BODY(iseq)->parent_iseq;
1913 }
1914}
1915
1916static ID
1917iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1918{
1919 for (int i=0; i<level; i++) {
1920 iseq = ISEQ_BODY(iseq)->parent_iseq;
1921 }
1922
1923 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1924 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1925 return id;
1926}
1927
1928static void
1929update_lvar_state(const rb_iseq_t *iseq, int level, int idx)
1930{
1931 for (int i=0; i<level; i++) {
1932 iseq = ISEQ_BODY(iseq)->parent_iseq;
1933 }
1934
1935 uint8_t *states = iseq_lvar_states(ISEQ_BODY(iseq));
1936 int table_idx = ISEQ_BODY(iseq)->local_table_size - idx;
1937 switch (iseq_lvar_state_get(states, table_idx)) {
1938 case lvar_uninitialized:
1939 iseq_lvar_state_set(states, table_idx, lvar_initialized);
1940 break;
1941 case lvar_initialized:
1942 iseq_lvar_state_set(states, table_idx, lvar_reassigned);
1943 break;
1944 case lvar_reassigned:
1945 /* nothing */
1946 break;
1947 default:
1948 rb_bug("unreachable");
1949 }
1950}
1951
1952static int
1953iseq_set_parameters_lvar_state(const rb_iseq_t *iseq)
1954{
1955 uint8_t *states = iseq_lvar_states(ISEQ_BODY(iseq));
1956
1957 for (unsigned int i=0; i<ISEQ_BODY(iseq)->param.size; i++) {
1958 iseq_lvar_state_set(states, i, lvar_initialized);
1959 }
1960
1961 int lead_num = ISEQ_BODY(iseq)->param.lead_num;
1962 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
1963 for (int i=0; i<opt_num; i++) {
1964 iseq_lvar_state_set(states, lead_num + i, lvar_uninitialized);
1965 }
1966
1967 return COMPILE_OK;
1968}
1969
1970static void
1971iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1972{
1973 if (iseq_local_block_param_p(iseq, idx, level)) {
1974 ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1975 }
1976 else {
1977 ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1978 }
1979 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1980}
1981
1982static void
1983iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1984{
1985 if (iseq_local_block_param_p(iseq, idx, level)) {
1986 ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1987 }
1988 else {
1989 ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1990 }
1991 update_lvar_state(iseq, level, idx);
1992 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1993}
1994
1995
1996
1997static void
1998iseq_calc_param_size(rb_iseq_t *iseq)
1999{
2000 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2001 if (body->param.flags.has_opt ||
2002 body->param.flags.has_post ||
2003 body->param.flags.has_rest ||
2004 body->param.flags.has_block ||
2005 body->param.flags.has_kw ||
2006 body->param.flags.has_kwrest) {
2007
2008 if (body->param.flags.has_block) {
2009 body->param.size = body->param.block_start + 1;
2010 }
2011 else if (body->param.flags.has_kwrest) {
2012 body->param.size = body->param.keyword->rest_start + 1;
2013 }
2014 else if (body->param.flags.has_kw) {
2015 body->param.size = body->param.keyword->bits_start + 1;
2016 }
2017 else if (body->param.flags.has_post) {
2018 body->param.size = body->param.post_start + body->param.post_num;
2019 }
2020 else if (body->param.flags.has_rest) {
2021 body->param.size = body->param.rest_start + 1;
2022 }
2023 else if (body->param.flags.has_opt) {
2024 body->param.size = body->param.lead_num + body->param.opt_num;
2025 }
2026 else {
2028 }
2029 }
2030 else {
2031 body->param.size = body->param.lead_num;
2032 }
2033}
2034
2035static int
2036iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
2037 const struct rb_args_info *args, int arg_size)
2038{
2039 const rb_node_kw_arg_t *node = args->kw_args;
2040 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2041 struct rb_iseq_param_keyword *keyword;
2042 const VALUE default_values = rb_ary_hidden_new(1);
2043 const VALUE complex_mark = rb_str_tmp_new(0);
2044 int kw = 0, rkw = 0, di = 0, i;
2045
2046 body->param.flags.has_kw = TRUE;
2047 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2048
2049 while (node) {
2050 kw++;
2051 node = node->nd_next;
2052 }
2053 if (kw > VM_CALL_KW_LEN_MAX) {
2054 COMPILE_ERROR(ERROR_ARGS_AT(RNODE(args->kw_args)) "too many keyword parameters (%d, maximum is %d)",
2055 kw, (int)VM_CALL_KW_LEN_MAX);
2056 }
2057 arg_size += kw;
2058 keyword->bits_start = arg_size++;
2059
2060 node = args->kw_args;
2061 while (node) {
2062 const NODE *val_node = get_nd_value(node->nd_body);
2063 VALUE dv;
2064
2065 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
2066 ++rkw;
2067 }
2068 else {
2069 switch (nd_type(val_node)) {
2070 case NODE_SYM:
2071 dv = rb_node_sym_string_val(val_node);
2072 break;
2073 case NODE_REGX:
2074 dv = rb_node_regx_string_val(val_node);
2075 break;
2076 case NODE_LINE:
2077 dv = rb_node_line_lineno_val(val_node);
2078 break;
2079 case NODE_INTEGER:
2080 dv = rb_node_integer_literal_val(val_node);
2081 break;
2082 case NODE_FLOAT:
2083 dv = rb_node_float_literal_val(val_node);
2084 break;
2085 case NODE_RATIONAL:
2086 dv = rb_node_rational_literal_val(val_node);
2087 break;
2088 case NODE_IMAGINARY:
2089 dv = rb_node_imaginary_literal_val(val_node);
2090 break;
2091 case NODE_ENCODING:
2092 dv = rb_node_encoding_val(val_node);
2093 break;
2094 case NODE_NIL:
2095 dv = Qnil;
2096 break;
2097 case NODE_TRUE:
2098 dv = Qtrue;
2099 break;
2100 case NODE_FALSE:
2101 dv = Qfalse;
2102 break;
2103 default:
2104 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
2105 dv = complex_mark;
2106 }
2107
2108 keyword->num = ++di;
2109 rb_ary_push(default_values, dv);
2110 }
2111
2112 node = node->nd_next;
2113 }
2114
2115 keyword->num = kw;
2116
2117 if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
2118 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2119 keyword->rest_start = arg_size++;
2120 body->param.flags.has_kwrest = TRUE;
2121
2122 if (kw_id == idPow) body->param.flags.anon_kwrest = TRUE;
2123 }
2124 keyword->required_num = rkw;
2125 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
2126
2127 if (RARRAY_LEN(default_values)) {
2128 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
2129
2130 for (i = 0; i < RARRAY_LEN(default_values); i++) {
2131 VALUE dv = RARRAY_AREF(default_values, i);
2132 if (dv == complex_mark) dv = Qundef;
2134 RB_OBJ_WRITE(iseq, &dvs[i], dv);
2135 }
2136
2137 keyword->default_values = dvs;
2138 }
2139 return arg_size;
2140}
2141
2142static void
2143iseq_set_use_block(rb_iseq_t *iseq)
2144{
2145 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2146 if (!body->param.flags.use_block) {
2147 body->param.flags.use_block = 1;
2148
2149 rb_vm_t *vm = GET_VM();
2150
2151 if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
2152 st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
2153 set_insert(&vm->unused_block_warning_table, key);
2154 }
2155 }
2156}
2157
2158static int
2159iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
2160{
2161 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
2162
2163 if (node_args) {
2164 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2165 const struct rb_args_info *const args = &RNODE_ARGS(node_args)->nd_ainfo;
2166 ID rest_id = 0;
2167 int last_comma = 0;
2168 ID block_id = 0;
2169 int arg_size;
2170
2171 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
2172
2173 body->param.lead_num = arg_size = (int)args->pre_args_num;
2174 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
2175 debugs(" - argc: %d\n", body->param.lead_num);
2176
2177 rest_id = args->rest_arg;
2178 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2179 last_comma = 1;
2180 rest_id = 0;
2181 }
2182 block_id = args->block_arg;
2183
2184 bool optimized_forward = (args->forwarding && args->pre_args_num == 0 && !args->opt_args);
2185
2186 if (optimized_forward) {
2187 rest_id = 0;
2188 block_id = 0;
2189 }
2190
2191 if (args->opt_args) {
2192 const rb_node_opt_arg_t *node = args->opt_args;
2193 LABEL *label;
2194 VALUE labels = rb_ary_hidden_new(1);
2195 VALUE *opt_table;
2196 int i = 0, j;
2197
2198 while (node) {
2199 label = NEW_LABEL(nd_line(RNODE(node)));
2200 rb_ary_push(labels, (VALUE)label | 1);
2201 ADD_LABEL(optargs, label);
2202 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
2203 node = node->nd_next;
2204 i += 1;
2205 }
2206
2207 /* last label */
2208 label = NEW_LABEL(nd_line(node_args));
2209 rb_ary_push(labels, (VALUE)label | 1);
2210 ADD_LABEL(optargs, label);
2211
2212 opt_table = ALLOC_N(VALUE, i+1);
2213
2214 MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
2215 for (j = 0; j < i+1; j++) {
2216 opt_table[j] &= ~1;
2217 }
2218 rb_ary_clear(labels);
2219
2220 body->param.flags.has_opt = TRUE;
2221 body->param.opt_num = i;
2222 body->param.opt_table = opt_table;
2223 arg_size += i;
2224 }
2225
2226 if (rest_id) {
2227 body->param.rest_start = arg_size++;
2228 body->param.flags.has_rest = TRUE;
2229 if (rest_id == '*') body->param.flags.anon_rest = TRUE;
2230 RUBY_ASSERT(body->param.rest_start != -1);
2231 }
2232
2233 if (args->first_post_arg) {
2234 body->param.post_start = arg_size;
2235 body->param.post_num = args->post_args_num;
2236 body->param.flags.has_post = TRUE;
2237 arg_size += args->post_args_num;
2238
2239 if (body->param.flags.has_rest) { /* TODO: why that? */
2240 body->param.post_start = body->param.rest_start + 1;
2241 }
2242 }
2243
2244 if (args->kw_args) {
2245 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2246 }
2247 else if (args->kw_rest_arg && !optimized_forward) {
2248 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2249 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2250 keyword->rest_start = arg_size++;
2251 body->param.keyword = keyword;
2252 body->param.flags.has_kwrest = TRUE;
2253
2254 static ID anon_kwrest = 0;
2255 if (!anon_kwrest) anon_kwrest = rb_intern("**");
2256 if (kw_id == anon_kwrest) body->param.flags.anon_kwrest = TRUE;
2257 }
2258 else if (args->no_kwarg) {
2259 body->param.flags.accepts_no_kwarg = TRUE;
2260 }
2261
2262 if (args->no_blockarg) {
2263 body->param.flags.accepts_no_block = TRUE;
2264 }
2265 else if (block_id) {
2266 body->param.block_start = arg_size++;
2267 body->param.flags.has_block = TRUE;
2268 iseq_set_use_block(iseq);
2269 }
2270
2271 // Only optimize specifically methods like this: `foo(...)`
2272 if (optimized_forward) {
2273 body->param.flags.use_block = 1;
2274 body->param.flags.forwardable = TRUE;
2275 arg_size = 1;
2276 }
2277
2278 iseq_calc_param_size(iseq);
2279 body->param.size = arg_size;
2280
2281 if (args->pre_init) { /* m_init */
2282 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
2283 }
2284 if (args->post_init) { /* p_init */
2285 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
2286 }
2287
2288 if (body->type == ISEQ_TYPE_BLOCK) {
2289 if (body->param.flags.has_opt == FALSE &&
2290 body->param.flags.has_post == FALSE &&
2291 body->param.flags.has_rest == FALSE &&
2292 body->param.flags.has_kw == FALSE &&
2293 body->param.flags.has_kwrest == FALSE) {
2294
2295 if (body->param.lead_num == 1 && last_comma == 0) {
2296 /* {|a|} */
2297 body->param.flags.ambiguous_param0 = TRUE;
2298 }
2299 }
2300 }
2301 }
2302
2303 return COMPILE_OK;
2304}
2305
2306static int
2307iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args)
2308{
2309 unsigned int size = tbl ? tbl->size : 0;
2310 unsigned int offset = 0;
2311
2312 if (node_args) {
2313 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2314
2315 // If we have a function that only has `...` as the parameter,
2316 // then its local table should only be `...`
2317 // FIXME: I think this should be fixed in the AST rather than special case here.
2318 if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
2319 CHECK(size >= 3);
2320 size -= 3;
2321 offset += 3;
2322 }
2323 }
2324
2325 if (size > 0) {
2326 ID *ids = ALLOC_N(ID, size);
2327 MEMCPY(ids, tbl->ids + offset, ID, size);
2328 ISEQ_BODY(iseq)->local_table = ids;
2329
2330 if (ISEQ_LVAR_STATES_EMBED_P(size)) {
2331 /* states are embedded in the body; zero them out */
2332 memset(ISEQ_BODY(iseq)->lvar_states.single, 0, sizeof(ISEQ_BODY(iseq)->lvar_states.single));
2333 }
2334 else {
2335 ISEQ_BODY(iseq)->lvar_states.list = ZALLOC_N(uint8_t, ISEQ_LVAR_STATES_BUFLEN(size));
2336 }
2337 }
2338 ISEQ_BODY(iseq)->local_table_size = size;
2339
2340 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2341 return COMPILE_OK;
2342}
2343
2344int
2345rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
2346{
2347 int tval, tlit;
2348
2349 if (val == lit) {
2350 return 0;
2351 }
2352 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2353 return val != lit;
2354 }
2355 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2356 return -1;
2357 }
2358 else if (tlit != tval) {
2359 return -1;
2360 }
2361 else if (tlit == T_SYMBOL) {
2362 return val != lit;
2363 }
2364 else if (tlit == T_STRING) {
2365 return rb_str_hash_cmp(lit, val);
2366 }
2367 else if (tlit == T_BIGNUM) {
2368 long x = FIX2LONG(rb_big_cmp(lit, val));
2369
2370 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2371 * There is no need to call rb_fix2int here. */
2372 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2373 return (int)x;
2374 }
2375 else if (tlit == T_FLOAT) {
2376 return rb_float_cmp(lit, val);
2377 }
2378 else if (tlit == T_RATIONAL) {
2379 const struct RRational *rat1 = RRATIONAL(val);
2380 const struct RRational *rat2 = RRATIONAL(lit);
2381 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2382 }
2383 else if (tlit == T_COMPLEX) {
2384 const struct RComplex *comp1 = RCOMPLEX(val);
2385 const struct RComplex *comp2 = RCOMPLEX(lit);
2386 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2387 }
2388 else if (tlit == T_REGEXP) {
2389 return rb_reg_equal(val, lit) ? 0 : -1;
2390 }
2391 else {
2393 }
2394}
2395
2396st_index_t
2397rb_iseq_cdhash_hash(VALUE a)
2398{
2399 switch (OBJ_BUILTIN_TYPE(a)) {
2400 case -1:
2401 case T_SYMBOL:
2402 return (st_index_t)a;
2403 case T_STRING:
2404 return rb_str_hash(a);
2405 case T_BIGNUM:
2406 return FIX2LONG(rb_big_hash(a));
2407 case T_FLOAT:
2408 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2409 case T_RATIONAL:
2410 return rb_rational_hash(a);
2411 case T_COMPLEX:
2412 return rb_complex_hash(a);
2413 case T_REGEXP:
2414 return NUM2LONG(rb_reg_hash(a));
2415 default:
2417 }
2418}
2419
2420static const struct st_hash_type cdhash_type = {
2421 rb_iseq_cdhash_cmp,
2422 rb_iseq_cdhash_hash,
2423};
2424
2425static VALUE
2426cdhash_new(size_t size)
2427{
2428 VALUE cdhash = rb_imemo_cdhash_new(size, &cdhash_type);
2429 RB_OBJ_SET_SHAREABLE(cdhash);
2430 return cdhash;
2431}
2432
2433static void
2434cdhash_aset(VALUE cdhash, VALUE key, VALUE val)
2435{
2436 st_table *tbl = rb_imemo_cdhash_tbl(cdhash);
2437 st_insert(tbl, key, val);
2438 RB_OBJ_WRITTEN(cdhash, Qundef, key);
2439}
2440
2441static void
2442cdhash_aset_if_missing(VALUE cdhash, VALUE key, VALUE val)
2443{
2444 st_table *tbl = rb_imemo_cdhash_tbl(cdhash);
2445 VALUE dontcare;
2446 if (!st_lookup(tbl, key, &dontcare)) {
2447 st_insert(tbl, key, val);
2448 RB_OBJ_WRITTEN(cdhash, Qundef, key);
2449 }
2450}
2451
2453 VALUE hash;
2454 int pos;
2455 int len;
2456};
2457
2458static int
2459cdhash_set_label_check_i(st_data_t key, st_data_t value, st_data_t argp, int error)
2460{
2461 return ST_REPLACE;
2462}
2463
2464static int
2465cdhash_set_label_replace_i(st_data_t *key, st_data_t *value, st_data_t ptr, int existing)
2466{
2467 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2468 LABEL *lobj = (LABEL *)(*value & ~1);
2469 *value = lobj->position - (data->pos+data->len);
2470 return ST_CONTINUE;
2471}
2472
2473static inline VALUE
2474get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2475{
2476 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2477}
2478
2479static inline VALUE
2480get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2481{
2482 VALUE val;
2483 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2484 if (tbl) {
2485 if (rb_id_table_lookup(tbl,id,&val)) {
2486 return val;
2487 }
2488 }
2489 else {
2490 tbl = rb_id_table_create(1);
2491 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2492 }
2493 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2494 rb_id_table_insert(tbl,id,val);
2495 return val;
2496}
2497
2498#define BADINSN_DUMP(anchor, list, dest) \
2499 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2500
2501#define BADINSN_ERROR \
2502 (SIZED_FREE_N(generated_iseq, generated_iseq_size), \
2503 SIZED_FREE_N(insns_info, insns_info_size), \
2504 BADINSN_DUMP(anchor, list, NULL), \
2505 COMPILE_ERROR)
2506
2507static int
2508fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2509{
2510 int stack_max = 0, sp = 0, line = 0;
2511 LINK_ELEMENT *list;
2512
2513 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2514 if (IS_LABEL(list)) {
2515 LABEL *lobj = (LABEL *)list;
2516 lobj->set = TRUE;
2517 }
2518 }
2519
2520 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2521 switch (list->type) {
2522 case ISEQ_ELEMENT_INSN:
2523 {
2524 int j, len, insn;
2525 const char *types;
2526 VALUE *operands;
2527 INSN *iobj = (INSN *)list;
2528
2529 /* update sp */
2530 sp = calc_sp_depth(sp, iobj);
2531 if (sp < 0) {
2532 BADINSN_DUMP(anchor, list, NULL);
2533 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2534 "argument stack underflow (%d)", sp);
2535 return -1;
2536 }
2537 if (sp > stack_max) {
2538 stack_max = sp;
2539 }
2540
2541 line = iobj->insn_info.line_no;
2542 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2543 operands = iobj->operands;
2544 insn = iobj->insn_id;
2545 types = insn_op_types(insn);
2546 len = insn_len(insn);
2547
2548 /* operand check */
2549 if (iobj->operand_size != len - 1) {
2550 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2551 BADINSN_DUMP(anchor, list, NULL);
2552 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2553 "operand size miss! (%d for %d)",
2554 iobj->operand_size, len - 1);
2555 return -1;
2556 }
2557
2558 for (j = 0; types[j]; j++) {
2559 if (types[j] == TS_OFFSET) {
2560 /* label(destination position) */
2561 LABEL *lobj = (LABEL *)operands[j];
2562 if (!lobj->set) {
2563 BADINSN_DUMP(anchor, list, NULL);
2564 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2565 "unknown label: "LABEL_FORMAT, lobj->label_no);
2566 return -1;
2567 }
2568 if (lobj->sp == -1) {
2569 lobj->sp = sp;
2570 }
2571 else if (lobj->sp != sp) {
2572 VALUE path = rb_iseq_path(iseq);
2573 debugs("%.*s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2574 RSTRING_LENINT(path), RSTRING_PTR(path), line,
2575 lobj->label_no, lobj->sp, sp);
2576 }
2577 }
2578 }
2579 break;
2580 }
2581 case ISEQ_ELEMENT_LABEL:
2582 {
2583 LABEL *lobj = (LABEL *)list;
2584 if (lobj->sp == -1) {
2585 lobj->sp = sp;
2586 }
2587 else {
2588 if (lobj->sp != sp) {
2589 VALUE path = rb_iseq_path(iseq);
2590 debugs("%.*s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2591 RSTRING_LENINT(path), RSTRING_PTR(path), line,
2592 lobj->label_no, lobj->sp, sp);
2593 }
2594 sp = lobj->sp;
2595 }
2596 break;
2597 }
2598 case ISEQ_ELEMENT_TRACE:
2599 {
2600 /* ignore */
2601 break;
2602 }
2603 case ISEQ_ELEMENT_ADJUST:
2604 {
2605 ADJUST *adjust = (ADJUST *)list;
2606 int orig_sp = sp;
2607
2608 sp = adjust->label ? adjust->label->sp : 0;
2609 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2610 BADINSN_DUMP(anchor, list, NULL);
2611 COMPILE_ERROR(iseq, adjust->line_no,
2612 "iseq_set_sequence: adjust bug %d < %d",
2613 orig_sp, sp);
2614 return -1;
2615 }
2616 break;
2617 }
2618 default:
2619 BADINSN_DUMP(anchor, list, NULL);
2620 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2621 return -1;
2622 }
2623 }
2624 return stack_max;
2625}
2626
2627#ifdef USE_ISEQ_NODE_ID
2628static void
2629add_node_id(uint8_t *node_ids, unsigned int *node_ids_size, int node_id, int *prev_node_id)
2630{
2631 int delta = node_id - *prev_node_id;
2632 uint32_t zz = ((uint32_t)delta << 1) ^ (uint32_t)(delta >> 31);
2633 *prev_node_id = node_id;
2634 do {
2635 uint8_t byte = zz & 0x7f;
2636 zz >>= 7;
2637 node_ids[(*node_ids_size)++] = zz ? (byte | 0x80) : byte;
2638 } while (zz);
2639}
2640#endif
2641
2642static int
2643add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2644 int insns_info_index, int code_index, const INSN *iobj)
2645{
2646 if (insns_info_index == 0 ||
2647 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2648 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2649 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2650 insns_info[insns_info_index].events = iobj->insn_info.events;
2651 positions[insns_info_index] = code_index;
2652 return TRUE;
2653 }
2654 return FALSE;
2655}
2656
2657static int
2658add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2659 int insns_info_index, int code_index, const ADJUST *adjust)
2660{
2661 insns_info[insns_info_index].line_no = adjust->line_no;
2662 insns_info[insns_info_index].events = 0;
2663 positions[insns_info_index] = code_index;
2664 return TRUE;
2665}
2666
2667static ID *
2668array_to_idlist(VALUE arr)
2669{
2671 rb_len_t size = RARRAY_LEN(arr);
2672 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2673 for (rb_len_t i = 0; i < size; i++) {
2674 VALUE sym = RARRAY_AREF(arr, i);
2675 ids[i] = SYM2ID(sym);
2676 }
2677 ids[size] = 0;
2678 return ids;
2679}
2680
2681static VALUE
2682idlist_to_array(const ID *ids)
2683{
2684 VALUE arr = rb_ary_new();
2685 while (*ids) {
2686 rb_ary_push(arr, ID2SYM(*ids++));
2687 }
2688 return arr;
2689}
2690
2694static int
2695iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2696{
2697 struct iseq_insn_info_entry *insns_info;
2698 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2699 unsigned int *positions;
2700 LINK_ELEMENT *list;
2701 VALUE *generated_iseq;
2702 rb_event_flag_t events = 0;
2703 long data = 0;
2704
2705 int insn_num, code_index, insns_info_index, sp = 0;
2706 int stack_max = fix_sp_depth(iseq, anchor);
2707
2708 if (stack_max < 0) return COMPILE_NG;
2709
2710 /* fix label position */
2711 insn_num = code_index = 0;
2712 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2713 switch (list->type) {
2714 case ISEQ_ELEMENT_INSN:
2715 {
2716 INSN *iobj = (INSN *)list;
2717 /* update sp */
2718 sp = calc_sp_depth(sp, iobj);
2719 insn_num++;
2720 events = iobj->insn_info.events |= events;
2721 if (ISEQ_COVERAGE(iseq)) {
2722 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2723 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2724 int line = iobj->insn_info.line_no - 1;
2725 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2726 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2727 }
2728 }
2729 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2730 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2731 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2732 }
2733 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2734 }
2735 }
2736 code_index += insn_data_length(iobj);
2737 events = 0;
2738 data = 0;
2739 break;
2740 }
2741 case ISEQ_ELEMENT_LABEL:
2742 {
2743 LABEL *lobj = (LABEL *)list;
2744 lobj->position = code_index;
2745 if (lobj->sp != sp) {
2746 VALUE path = rb_iseq_path(iseq);
2747 debugs("%.*s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2748 RSTRING_LENINT(path), RSTRING_PTR(path),
2749 lobj->label_no, lobj->sp, sp);
2750 }
2751 sp = lobj->sp;
2752 break;
2753 }
2754 case ISEQ_ELEMENT_TRACE:
2755 {
2756 TRACE *trace = (TRACE *)list;
2757 events |= trace->event;
2758 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2759 break;
2760 }
2761 case ISEQ_ELEMENT_ADJUST:
2762 {
2763 ADJUST *adjust = (ADJUST *)list;
2764 if (adjust->line_no != -1) {
2765 int orig_sp = sp;
2766 sp = adjust->label ? adjust->label->sp : 0;
2767 if (orig_sp - sp > 0) {
2768 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2769 code_index++; /* insn */
2770 insn_num++;
2771 }
2772 }
2773 break;
2774 }
2775 default: break;
2776 }
2777 }
2778
2779 /* make instruction sequence */
2780 const int generated_iseq_size = code_index;
2781 generated_iseq = ALLOC_N(VALUE, code_index);
2782
2783 const int insns_info_size = insn_num;
2784 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2785
2786 const int positions_size = insn_num;
2787 positions = ALLOC_N(unsigned int, insn_num);
2788#ifdef USE_ISEQ_NODE_ID
2789 uint8_t *node_ids = ALLOC_N(uint8_t, (size_t)insn_num * 5);
2790 unsigned int node_ids_size = 0;
2791 int prev_node_id = 0;
2792#endif
2793 if (ISEQ_IS_SIZE(body)) {
2794 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2795 }
2796 else {
2797 body->is_entries = NULL;
2798 }
2799
2800 if (body->ci_size) {
2801 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2802 }
2803 else {
2804 body->call_data = NULL;
2805 }
2806 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2807
2808 // Calculate the bitmask buffer size.
2809 // Round the generated_iseq size up to the nearest multiple
2810 // of the number of bits in an unsigned long.
2811
2812 // Allocate enough room for the bitmask list
2813 iseq_bits_t * mark_offset_bits;
2814 int code_size = code_index;
2815
2816 bool needs_bitmap = false;
2817
2818 const size_t mark_offset_bits_size = ISEQ_MBITS_BUFLEN(code_index);
2819 if (mark_offset_bits_size == 1) {
2820 mark_offset_bits = &ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2821 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = true;
2822 }
2823 else {
2824 mark_offset_bits = ZALLOC_N(iseq_bits_t, mark_offset_bits_size);
2825 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = mark_offset_bits;
2826 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = false;
2827 }
2828
2829 ISEQ_COMPILE_DATA(iseq)->iseq_encoded = (void *)generated_iseq;
2830 ISEQ_COMPILE_DATA(iseq)->iseq_size = code_index;
2831
2832 list = FIRST_ELEMENT(anchor);
2833 insns_info_index = code_index = sp = 0;
2834
2835 while (list) {
2836 switch (list->type) {
2837 case ISEQ_ELEMENT_INSN:
2838 {
2839 int j, len, insn;
2840 const char *types;
2841 VALUE *operands;
2842 INSN *iobj = (INSN *)list;
2843
2844 /* update sp */
2845 sp = calc_sp_depth(sp, iobj);
2846 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2847 operands = iobj->operands;
2848 insn = iobj->insn_id;
2849 generated_iseq[code_index] = insn;
2850 types = insn_op_types(insn);
2851 len = insn_len(insn);
2852
2853 for (j = 0; types[j]; j++) {
2854 char type = types[j];
2855
2856 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2857 switch (type) {
2858 case TS_OFFSET:
2859 {
2860 /* label(destination position) */
2861 LABEL *lobj = (LABEL *)operands[j];
2862 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2863 break;
2864 }
2865 case TS_CDHASH:
2866 {
2867 VALUE map = operands[j];
2868 struct cdhash_set_label_struct data;
2869 data.hash = map;
2870 data.pos = code_index;
2871 data.len = len;
2872 st_foreach_with_replace(rb_imemo_cdhash_tbl(map), cdhash_set_label_check_i, cdhash_set_label_replace_i, (VALUE)&data);
2873
2874 generated_iseq[code_index + 1 + j] = map;
2875 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2876 RB_OBJ_WRITTEN(iseq, Qundef, map);
2877 needs_bitmap = true;
2878 break;
2879 }
2880 case TS_LINDEX:
2881 case TS_NUM: /* ulong */
2882 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2883 break;
2884 case TS_ISEQ: /* iseq */
2885 case TS_VALUE: /* VALUE */
2886 {
2887 VALUE v = operands[j];
2888 generated_iseq[code_index + 1 + j] = v;
2889 /* to mark ruby object */
2890 if (!SPECIAL_CONST_P(v)) {
2891 RB_OBJ_WRITTEN(iseq, Qundef, v);
2892 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2893 needs_bitmap = true;
2894 }
2895 break;
2896 }
2897 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2898 case TS_IC: /* inline cache: constants */
2899 {
2900 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2901 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2902 if (UNLIKELY(ic_index >= body->ic_size)) {
2903 BADINSN_DUMP(anchor, &iobj->link, 0);
2904 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2905 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2906 ic_index, ISEQ_IS_SIZE(body));
2907 }
2908
2909 ic->segments = array_to_idlist(operands[j]);
2910
2911 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2912 }
2913 break;
2914 case TS_IVC: /* inline ivar cache */
2915 {
2916 unsigned int ic_index = FIX2UINT(operands[j]);
2917
2918 IVC cache = ((IVC)&body->is_entries[ic_index]);
2919
2920 if (insn == BIN(setinstancevariable)) {
2921 cache->iv_set_name = SYM2ID(operands[j - 1]);
2922 cache->value = IVAR_CACHE_INIT;
2923 }
2924 else {
2925 cache->iv_set_name = 0;
2926 cache->value = rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET);
2927 }
2928 }
2929 case TS_ISE: /* inline storage entry: `once` insn */
2930 case TS_ICVARC: /* inline cvar cache */
2931 {
2932 unsigned int ic_index = FIX2UINT(operands[j]);
2933 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2934 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2935 BADINSN_DUMP(anchor, &iobj->link, 0);
2936 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2937 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2938 ic_index, ISEQ_IS_SIZE(body));
2939 }
2940 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2941
2942 break;
2943 }
2944 case TS_CALLDATA:
2945 {
2946 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2947 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2948 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2949 cd->ci = source_ci;
2950 cd->cc = vm_cc_empty();
2951 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2952 break;
2953 }
2954 case TS_ID: /* ID */
2955 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2956 break;
2957 case TS_FUNCPTR:
2958 generated_iseq[code_index + 1 + j] = operands[j];
2959 break;
2960 case TS_BUILTIN:
2961 generated_iseq[code_index + 1 + j] = operands[j];
2962 break;
2963 default:
2964 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2965 "unknown operand type: %c", type);
2966 return COMPILE_NG;
2967 }
2968 }
2969 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2970#ifdef USE_ISEQ_NODE_ID
2971 add_node_id(node_ids, &node_ids_size, iobj->insn_info.node_id, &prev_node_id);
2972#endif
2973 code_index += len;
2974 break;
2975 }
2976 case ISEQ_ELEMENT_LABEL:
2977 {
2978 LABEL *lobj = (LABEL *)list;
2979 if (lobj->sp != sp) {
2980 VALUE path = rb_iseq_path(iseq);
2981 debugs("%.*s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2982 RSTRING_LENINT(path), RSTRING_PTR(path),
2983 lobj->label_no, lobj->sp, sp);
2984 }
2985 sp = lobj->sp;
2986 break;
2987 }
2988 case ISEQ_ELEMENT_ADJUST:
2989 {
2990 ADJUST *adjust = (ADJUST *)list;
2991 int orig_sp = sp;
2992
2993 if (adjust->label) {
2994 sp = adjust->label->sp;
2995 }
2996 else {
2997 sp = 0;
2998 }
2999
3000 if (adjust->line_no != -1) {
3001 const int diff = orig_sp - sp;
3002 if (diff > 0) {
3003 if (insns_info_index == 0) {
3004 COMPILE_ERROR(iseq, adjust->line_no,
3005 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
3006 }
3007 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
3008#ifdef USE_ISEQ_NODE_ID
3009 add_node_id(node_ids, &node_ids_size, -1, &prev_node_id);
3010#endif
3011 }
3012 if (diff > 1) {
3013 generated_iseq[code_index++] = BIN(adjuststack);
3014 generated_iseq[code_index++] = orig_sp - sp;
3015 }
3016 else if (diff == 1) {
3017 generated_iseq[code_index++] = BIN(pop);
3018 }
3019 else if (diff < 0) {
3020 int label_no = adjust->label ? adjust->label->label_no : -1;
3021 SIZED_FREE_N(generated_iseq, generated_iseq_size);
3022 SIZED_FREE_N(insns_info, insns_info_size);
3023 SIZED_FREE_N(positions, positions_size);
3024#ifdef USE_ISEQ_NODE_ID
3025 SIZED_FREE_N(node_ids, (size_t)insns_info_size * 5);
3026#endif
3027 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
3028 SIZED_FREE_N(mark_offset_bits, ISEQ_MBITS_BUFLEN(code_index));
3029 }
3030 debug_list(anchor, list);
3031 COMPILE_ERROR(iseq, adjust->line_no,
3032 "iseq_set_sequence: adjust bug to %d %d < %d",
3033 label_no, orig_sp, sp);
3034 return COMPILE_NG;
3035 }
3036 }
3037 break;
3038 }
3039 default:
3040 /* ignore */
3041 break;
3042 }
3043 list = list->next;
3044 }
3045
3046 body->iseq_encoded = (void *)generated_iseq;
3047 body->iseq_size = code_index;
3048 body->stack_max = stack_max;
3049
3050 if (ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit) {
3051 body->mark_bits.single = ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
3052 }
3053 else {
3054 if (needs_bitmap) {
3055 body->mark_bits.list = mark_offset_bits;
3056 }
3057 else {
3058 body->mark_bits.list = NULL;
3059 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = NULL;
3060 SIZED_FREE_N(mark_offset_bits, mark_offset_bits_size);
3061 }
3062 }
3063
3064 /* get rid of memory leak when REALLOC failed */
3065 body->insns_info.body = insns_info;
3066 body->insns_info.positions_or_succ_index_table.positions = positions;
3067#ifdef USE_ISEQ_NODE_ID
3068 body->insns_info.node_ids = node_ids;
3069#endif
3070
3071 SIZED_REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index, insns_info_size);
3072 body->insns_info.body = insns_info;
3073 SIZED_REALLOC_N(positions, unsigned int, insns_info_index, positions_size);
3074 body->insns_info.positions_or_succ_index_table.positions = positions;
3075 body->insns_info.size = insns_info_index;
3076#ifdef USE_ISEQ_NODE_ID
3077 SIZED_REALLOC_N(node_ids, uint8_t, node_ids_size, (size_t)insns_info_size * 5);
3078 body->insns_info.node_ids = node_ids;
3079 body->insns_info.node_ids_size = node_ids_size;
3080#endif
3081
3082 return COMPILE_OK;
3083}
3084
3085static int
3086label_get_position(LABEL *lobj)
3087{
3088 return lobj->position;
3089}
3090
3091static int
3092label_get_sp(LABEL *lobj)
3093{
3094 return lobj->sp;
3095}
3096
3097static int
3098iseq_set_exception_table(rb_iseq_t *iseq)
3099{
3100 const VALUE *tptr, *ptr;
3101 unsigned int tlen, i, table_size = 0;
3102 struct iseq_catch_table_entry *entry;
3103
3104 ISEQ_BODY(iseq)->catch_table = NULL;
3105
3106 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
3107 if (NIL_P(catch_table_ary)) return COMPILE_OK;
3108 tlen = (int)RARRAY_LEN(catch_table_ary);
3109 tptr = RARRAY_CONST_PTR(catch_table_ary);
3110
3111 if (tlen > 0) {
3112 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
3113 table->size = tlen;
3114
3115 for (i = 0; i < table->size; i++) {
3116 ptr = RARRAY_CONST_PTR(tptr[i]);
3117 int start = label_get_position((LABEL *)(ptr[1] & ~1));
3118 int end = label_get_position((LABEL *)(ptr[2] & ~1));
3119 int cont = 0;
3120 int sp = 0;
3121 if (start < 0 || end < 0) {
3122 if ((ptr[0] & 0xffff) != CATCH_TYPE_ENSURE) continue;
3123 if (start < 0) start = 0;
3124 if (end < 0) end = 0;
3125 }
3126 if (ptr[4]) {
3127 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
3128 cont = label_get_position(lobj);
3129 if (cont < 0) continue;
3130 sp = label_get_sp(lobj);
3131 }
3132
3133 entry = UNALIGNED_MEMBER_PTR(table, entries[table_size++]);
3134 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
3135 entry->start = (unsigned int)start;
3136 entry->end = (unsigned int)end;
3137 entry->iseq = (rb_iseq_t *)ptr[3];
3138 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
3139
3140 /* stack depth */
3141 if (ptr[4]) {
3142 entry->cont = (unsigned int)cont;
3143 entry->sp = sp;
3144
3145 /* TODO: Dirty Hack! Fix me */
3146 if (entry->type == CATCH_TYPE_RESCUE ||
3147 entry->type == CATCH_TYPE_BREAK ||
3148 entry->type == CATCH_TYPE_NEXT) {
3149 RUBY_ASSERT(entry->sp > 0);
3150 entry->sp--;
3151 }
3152 }
3153 else {
3154 entry->cont = 0;
3155 }
3156 }
3157 table->size = table_size;
3158 if (table_size == 0) {
3159 ruby_xfree_sized(table, iseq_catch_table_bytes(tlen));
3160 table = NULL;
3161 }
3162 else if (table_size < tlen) {
3163 table = ruby_xrealloc(table, iseq_catch_table_bytes(table_size));
3164 }
3165 ISEQ_BODY(iseq)->catch_table = table;
3166 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
3167 }
3168
3169 RB_GC_GUARD(catch_table_ary);
3170
3171 return COMPILE_OK;
3172}
3173
3174/*
3175 * set optional argument table
3176 * def foo(a, b=expr1, c=expr2)
3177 * =>
3178 * b:
3179 * expr1
3180 * c:
3181 * expr2
3182 */
3183static int
3184iseq_set_optargs_table(rb_iseq_t *iseq)
3185{
3186 int i;
3187 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
3188
3189 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
3190 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
3191 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
3192 }
3193 }
3194 return COMPILE_OK;
3195}
3196
3197static LINK_ELEMENT *
3198get_destination_insn(INSN *iobj)
3199{
3200 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
3201 LINK_ELEMENT *list;
3202 rb_event_flag_t events = 0;
3203
3204 list = lobj->link.next;
3205 while (list) {
3206 switch (list->type) {
3207 case ISEQ_ELEMENT_INSN:
3208 case ISEQ_ELEMENT_ADJUST:
3209 goto found;
3210 case ISEQ_ELEMENT_LABEL:
3211 /* ignore */
3212 break;
3213 case ISEQ_ELEMENT_TRACE:
3214 {
3215 TRACE *trace = (TRACE *)list;
3216 events |= trace->event;
3217 }
3218 break;
3219 default: break;
3220 }
3221 list = list->next;
3222 }
3223 found:
3224 if (list && IS_INSN(list)) {
3225 INSN *iobj = (INSN *)list;
3226 iobj->insn_info.events |= events;
3227 }
3228 return list;
3229}
3230
3231static LINK_ELEMENT *
3232get_next_insn(INSN *iobj)
3233{
3234 LINK_ELEMENT *list = iobj->link.next;
3235
3236 while (list) {
3237 if (IS_INSN(list) || IS_ADJUST(list)) {
3238 return list;
3239 }
3240 list = list->next;
3241 }
3242 return 0;
3243}
3244
3245static LINK_ELEMENT *
3246get_prev_insn(INSN *iobj)
3247{
3248 LINK_ELEMENT *list = iobj->link.prev;
3249
3250 while (list) {
3251 if (IS_INSN(list) || IS_ADJUST(list)) {
3252 return list;
3253 }
3254 list = list->prev;
3255 }
3256 return 0;
3257}
3258
3259static void
3260unref_destination(INSN *iobj, int pos)
3261{
3262 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3263 --lobj->refcnt;
3264 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3265}
3266
3267static bool
3268replace_destination(INSN *dobj, INSN *nobj)
3269{
3270 VALUE n = OPERAND_AT(nobj, 0);
3271 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3272 LABEL *nl = (LABEL *)n;
3273 if (dl == nl) return false;
3274 --dl->refcnt;
3275 ++nl->refcnt;
3276 OPERAND_AT(dobj, 0) = n;
3277 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3278 return true;
3279}
3280
3281static LABEL*
3282find_destination(INSN *i)
3283{
3284 int pos, len = insn_len(i->insn_id);
3285 for (pos = 0; pos < len; ++pos) {
3286 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3287 return (LABEL *)OPERAND_AT(i, pos);
3288 }
3289 }
3290 return 0;
3291}
3292
3294 const unsigned int capacity;
3295 unsigned int gen;
3296 int *counts;
3297 unsigned int *stamps;
3298};
3299
3300static int
3301unreachable_unref_count(const struct unreachable_unref *unref, const LABEL *lab)
3302{
3303 unsigned int no = (unsigned int)lab->label_no;
3304 return unref->stamps[no] == unref->gen ? unref->counts[no] : 0;
3305}
3306
3307static void
3308unreachable_unref_increment(const struct unreachable_unref *unref, const LABEL *lab)
3309{
3310 unsigned int no = (unsigned int)lab->label_no;
3311 if (unref->stamps[no] != unref->gen) {
3312 unref->stamps[no] = unref->gen;
3313 unref->counts[no] = 0;
3314 }
3315 unref->counts[no]++;
3316}
3317
3318static int
3319remove_unreachable_chunk(rb_iseq_t *iseq, struct unreachable_unref *unref, LINK_ELEMENT *i)
3320{
3321 LINK_ELEMENT *first = i, *end, *scan, *pending_end = 0;
3322 LABEL *pending = 0;
3323
3324 if (!i) return 0;
3325 if (++unref->gen == 0) {
3326 /* The stamp wrapped around, so every stale stamp became ambiguous. */
3327 MEMZERO(unref->stamps, unsigned int, unref->capacity);
3328 unref->gen = 1;
3329 }
3330
3331 end = i;
3332 scan = i;
3333 do {
3334 LABEL *lab;
3335 if (IS_INSN(scan)) {
3336 if (IS_INSN_ID(scan, leave)) {
3337 if (pending) break;
3338 end = scan;
3339 break;
3340 }
3341 else if ((lab = find_destination((INSN *)scan)) != 0) {
3342 unreachable_unref_increment(unref, lab);
3343 if (lab == pending && lab->refcnt <= unreachable_unref_count(unref, lab)) {
3344 pending = 0;
3345 }
3346 }
3347 }
3348 else if (IS_LABEL(scan)) {
3349 lab = (LABEL *)scan;
3350 if (lab->unremovable) {
3351 if (pending) break;
3352 return 0;
3353 }
3354 if (lab->refcnt > unreachable_unref_count(unref, lab)) {
3355 if (pending) break;
3356 pending = lab;
3357 pending_end = (scan == first) ? 0 : end;
3358 }
3359 continue;
3360 }
3361 else if (IS_ADJUST(scan)) {
3362 if (pending) break;
3363 return 0;
3364 }
3365 if (!pending) end = scan;
3366 } while ((scan = scan->next) != 0);
3367
3368 if (pending) {
3369 if (!pending_end) return 0;
3370 end = pending_end;
3371 }
3372 i = first;
3373 do {
3374 if (IS_INSN(i)) {
3375 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3376 VALUE insn = INSN_OF(i);
3377 int pos, len = insn_len(insn);
3378 for (pos = 0; pos < len; ++pos) {
3379 switch (insn_op_types(insn)[pos]) {
3380 case TS_OFFSET:
3381 unref_destination((INSN *)i, pos);
3382 break;
3383 case TS_CALLDATA:
3384 --(body->ci_size);
3385 break;
3386 }
3387 }
3388 }
3389 ELEM_REMOVE(i);
3390 } while ((i != end) && (i = i->next) != 0);
3391 return 1;
3392}
3393
3394static int
3395iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3396{
3397 switch (OPERAND_AT(iobj, 0)) {
3398 case INT2FIX(0): /* empty array */
3399 ELEM_REMOVE(&iobj->link);
3400 return TRUE;
3401 case INT2FIX(1): /* single element array */
3402 ELEM_REMOVE(&iobj->link);
3403 return FALSE;
3404 default:
3405 iobj->insn_id = BIN(adjuststack);
3406 return TRUE;
3407 }
3408}
3409
3410static int
3411is_frozen_putstring(INSN *insn, VALUE *op)
3412{
3413 if (IS_INSN_ID(insn, dupstring) || IS_INSN_ID(insn, dupchilledstring)) {
3414 *op = OPERAND_AT(insn, 0);
3415 return 1;
3416 }
3417 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3418 *op = OPERAND_AT(insn, 0);
3419 return RB_TYPE_P(*op, T_STRING);
3420 }
3421 return 0;
3422}
3423
3424static int
3425insn_has_label_before(LINK_ELEMENT *elem)
3426{
3427 LINK_ELEMENT *prev = elem->prev;
3428 while (prev) {
3429 if (prev->type == ISEQ_ELEMENT_LABEL) {
3430 LABEL *label = (LABEL *)prev;
3431 if (label->refcnt > 0) {
3432 return 1;
3433 }
3434 }
3435 else if (prev->type == ISEQ_ELEMENT_INSN) {
3436 break;
3437 }
3438 prev = prev->prev;
3439 }
3440 return 0;
3441}
3442
3443static int
3444optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3445{
3446 /*
3447 * putobject obj
3448 * dup
3449 * checktype T_XXX
3450 * branchif l1
3451 * l2:
3452 * ...
3453 * l1:
3454 *
3455 * => obj is a T_XXX
3456 *
3457 * putobject obj (T_XXX)
3458 * jump L1
3459 * L1:
3460 *
3461 * => obj is not a T_XXX
3462 *
3463 * putobject obj (T_XXX)
3464 * jump L2
3465 * L2:
3466 */
3467 int line, node_id;
3468 INSN *niobj, *ciobj, *dup = 0;
3469 LABEL *dest = 0;
3470 VALUE type;
3471
3472 switch (INSN_OF(iobj)) {
3473 case BIN(dupstring):
3474 case BIN(dupchilledstring):
3476 break;
3477 case BIN(putnil):
3478 type = INT2FIX(T_NIL);
3479 break;
3480 case BIN(putobject):
3481 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3482 break;
3483 default: return FALSE;
3484 }
3485
3486 ciobj = (INSN *)get_next_insn(iobj);
3487 if (IS_INSN_ID(ciobj, jump)) {
3488 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3489 }
3490 if (IS_INSN_ID(ciobj, dup)) {
3491 ciobj = (INSN *)get_next_insn(dup = ciobj);
3492 }
3493 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3494 niobj = (INSN *)get_next_insn(ciobj);
3495 if (!niobj) {
3496 /* TODO: putobject true/false */
3497 return FALSE;
3498 }
3499 switch (INSN_OF(niobj)) {
3500 case BIN(branchif):
3501 if (OPERAND_AT(ciobj, 0) == type) {
3502 dest = (LABEL *)OPERAND_AT(niobj, 0);
3503 }
3504 break;
3505 case BIN(branchunless):
3506 if (OPERAND_AT(ciobj, 0) != type) {
3507 dest = (LABEL *)OPERAND_AT(niobj, 0);
3508 }
3509 break;
3510 default:
3511 return FALSE;
3512 }
3513 line = ciobj->insn_info.line_no;
3514 node_id = ciobj->insn_info.node_id;
3515 if (!dest) {
3516 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3517 dest = (LABEL *)niobj->link.next; /* reuse label */
3518 }
3519 else {
3520 dest = NEW_LABEL(line);
3521 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3522 }
3523 }
3524 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3525 LABEL_REF(dest);
3526 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3527 return TRUE;
3528}
3529
3530static const struct rb_callinfo *
3531ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3532{
3533 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3534 vm_ci_flag(ci) | add,
3535 vm_ci_argc(ci),
3536 vm_ci_kwarg(ci));
3537 RB_OBJ_WRITTEN(iseq, ci, nci);
3538 return nci;
3539}
3540
3541static const struct rb_callinfo *
3542ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3543{
3544 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3545 vm_ci_flag(ci),
3546 argc,
3547 vm_ci_kwarg(ci));
3548 RB_OBJ_WRITTEN(iseq, ci, nci);
3549 return nci;
3550}
3551
3552#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3553
3554static VALUE
3555iseq_reg_compile(rb_iseq_t *iseq, VALUE str, int options, const char *sourcefile, int sourceline)
3556{
3557 VALUE errinfo = rb_errinfo();
3558 VALUE re = rb_reg_compile(str, options, sourcefile, sourceline);
3559 if (NIL_P(re)) {
3560 VALUE message = rb_attr_get(rb_errinfo(), idMesg);
3561 rb_set_errinfo(errinfo);
3562 COMPILE_ERROR(iseq, sourceline, "%" PRIsVALUE, message);
3563 }
3564 else {
3566 }
3567 return re;
3568}
3569
3570static int
3571iseq_peephole_optimize(rb_iseq_t *iseq, struct unreachable_unref *unref, LINK_ELEMENT *list, const int do_tailcallopt)
3572{
3573 INSN *const iobj = (INSN *)list;
3574
3575 again:
3576 optimize_checktype(iseq, iobj);
3577
3578 if (IS_INSN_ID(iobj, jump)) {
3579 INSN *niobj, *diobj, *piobj;
3580 diobj = (INSN *)get_destination_insn(iobj);
3581 niobj = (INSN *)get_next_insn(iobj);
3582
3583 if (diobj == niobj) {
3584 /*
3585 * jump LABEL
3586 * LABEL:
3587 * =>
3588 * LABEL:
3589 */
3590 unref_destination(iobj, 0);
3591 ELEM_REMOVE(&iobj->link);
3592 return COMPILE_OK;
3593 }
3594 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3595 IS_INSN_ID(diobj, jump) &&
3596 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3597 diobj->insn_info.events == 0) {
3598 /*
3599 * useless jump elimination:
3600 * jump LABEL1
3601 * ...
3602 * LABEL1:
3603 * jump LABEL2
3604 *
3605 * => in this case, first jump instruction should jump to
3606 * LABEL2 directly
3607 */
3608 if (replace_destination(iobj, diobj)) {
3609 remove_unreachable_chunk(iseq, unref, iobj->link.next);
3610 goto again;
3611 }
3612 }
3613 else if (IS_INSN_ID(diobj, leave)) {
3614 /*
3615 * jump LABEL
3616 * ...
3617 * LABEL:
3618 * leave
3619 * =>
3620 * leave
3621 * ...
3622 * LABEL:
3623 * leave
3624 */
3625 /* replace */
3626 unref_destination(iobj, 0);
3627 iobj->insn_id = BIN(leave);
3628 iobj->operand_size = 0;
3629 iobj->insn_info = diobj->insn_info;
3630 goto again;
3631 }
3632 else if (IS_INSN(iobj->link.prev) &&
3633 (piobj = (INSN *)iobj->link.prev) &&
3634 (IS_INSN_ID(piobj, branchif) ||
3635 IS_INSN_ID(piobj, branchunless))) {
3636 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3637 if (niobj == pdiobj) {
3638 int refcnt = IS_LABEL(piobj->link.next) ?
3639 ((LABEL *)piobj->link.next)->refcnt : 0;
3640 /*
3641 * useless jump elimination (if/unless destination):
3642 * if L1
3643 * jump L2
3644 * L1:
3645 * ...
3646 * L2:
3647 *
3648 * ==>
3649 * unless L2
3650 * L1:
3651 * ...
3652 * L2:
3653 */
3654 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3655 ? BIN(branchunless) : BIN(branchif);
3656 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3657 ELEM_REMOVE(&iobj->link);
3658 }
3659 else {
3660 /* TODO: replace other branch destinations too */
3661 }
3662 return COMPILE_OK;
3663 }
3664 else if (diobj == pdiobj) {
3665 /*
3666 * useless jump elimination (if/unless before jump):
3667 * L1:
3668 * ...
3669 * if L1
3670 * jump L1
3671 *
3672 * ==>
3673 * L1:
3674 * ...
3675 * pop
3676 * jump L1
3677 */
3678 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3679 ELEM_REPLACE(&piobj->link, &popiobj->link);
3680 }
3681 }
3682 if (remove_unreachable_chunk(iseq, unref, iobj->link.next)) {
3683 goto again;
3684 }
3685 }
3686
3687 /*
3688 * dupstring "beg"
3689 * dupstring "end"
3690 * newrange excl
3691 *
3692 * ==>
3693 *
3694 * putobject "beg".."end"
3695 */
3696 if (IS_INSN_ID(iobj, newrange)) {
3697 INSN *const range = iobj;
3698 INSN *beg, *end;
3699 VALUE str_beg, str_end;
3700
3701 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3702 is_frozen_putstring(end, &str_end) &&
3703 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3704 is_frozen_putstring(beg, &str_beg) &&
3705 !(insn_has_label_before(&beg->link) || insn_has_label_before(&end->link))) {
3706 int excl = FIX2INT(OPERAND_AT(range, 0));
3707 VALUE lit_range = RB_OBJ_SET_SHAREABLE(rb_range_new(str_beg, str_end, excl));
3708
3709 ELEM_REMOVE(&beg->link);
3710 ELEM_REMOVE(&end->link);
3711 range->insn_id = BIN(putobject);
3712 OPERAND_AT(range, 0) = lit_range;
3713 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3714 }
3715 }
3716
3717 if (IS_INSN_ID(iobj, leave)) {
3718 remove_unreachable_chunk(iseq, unref, iobj->link.next);
3719 }
3720
3721 /*
3722 * ...
3723 * duparray [...]
3724 * concatarray | concattoarray
3725 * =>
3726 * ...
3727 * putobject [...]
3728 * concatarray | concattoarray
3729 */
3730 if (IS_INSN_ID(iobj, duparray)) {
3731 LINK_ELEMENT *next = iobj->link.next;
3732 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3733 iobj->insn_id = BIN(putobject);
3734 }
3735 }
3736
3737 /*
3738 * duparray [...]
3739 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3740 * =>
3741 * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3742 */
3743 if (IS_INSN_ID(iobj, duparray)) {
3744 LINK_ELEMENT *next = iobj->link.next;
3745 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3746 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3747 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3748
3749 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3750 VALUE ary = iobj->operands[0];
3752
3753 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, ary, (VALUE)ci);
3754 ELEM_REMOVE(next);
3755 }
3756 }
3757 }
3758
3759 /*
3760 * duphash {...}
3761 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3762 * =>
3763 * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3764 */
3765 if (IS_INSN_ID(iobj, duphash)) {
3766 LINK_ELEMENT *next = iobj->link.next;
3767 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3768 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3769 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3770
3771 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3772 VALUE hash = iobj->operands[0];
3773 rb_obj_reveal(hash, rb_cHash);
3775
3776 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, hash, (VALUE)ci);
3777 ELEM_REMOVE(next);
3778 }
3779 }
3780 }
3781
3782 /*
3783 * newarray 0
3784 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3785 * =>
3786 * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3787 */
3788 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3789 LINK_ELEMENT *next = iobj->link.next;
3790 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3791 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3792 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3793
3794 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3795 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, rb_cArray_empty_frozen, (VALUE)ci);
3796 ELEM_REMOVE(next);
3797 }
3798 }
3799 }
3800
3801 /*
3802 * newhash 0
3803 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3804 * =>
3805 * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3806 */
3807 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3808 LINK_ELEMENT *next = iobj->link.next;
3809 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3810 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3811 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3812
3813 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3814 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, rb_cHash_empty_frozen, (VALUE)ci);
3815 ELEM_REMOVE(next);
3816 }
3817 }
3818 }
3819
3820 if (IS_INSN_ID(iobj, branchif) ||
3821 IS_INSN_ID(iobj, branchnil) ||
3822 IS_INSN_ID(iobj, branchunless)) {
3823 /*
3824 * if L1
3825 * ...
3826 * L1:
3827 * jump L2
3828 * =>
3829 * if L2
3830 */
3831 INSN *nobj = (INSN *)get_destination_insn(iobj);
3832
3833 /* This jump-jump optimization may ignore line events on the jump
3834 * instruction being skipped. For example, the Line 2 TracePoint
3835 * event would otherwise never fire in the following code:
3836 *
3837 * 1: raise if 1 == 2
3838 * 2: while true
3839 * 3: break
3840 * 4: end
3841 *
3842 * Do not skip a jump that carries a line event. This applies even
3843 * when coverage is disabled because TracePoint consumes the same
3844 * event. [Bug #15980]
3845 */
3846 int stop_optimization =
3847 nobj->link.type == ISEQ_ELEMENT_INSN &&
3848 (nobj->insn_info.events & (RUBY_EVENT_LINE | RUBY_EVENT_COVERAGE_LINE));
3849 if (!stop_optimization) {
3850 INSN *pobj = (INSN *)iobj->link.prev;
3851 int prev_dup = 0;
3852 if (pobj) {
3853 if (!IS_INSN(&pobj->link))
3854 pobj = 0;
3855 else if (IS_INSN_ID(pobj, dup))
3856 prev_dup = 1;
3857 }
3858
3859 for (;;) {
3860 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3861 if (!replace_destination(iobj, nobj)) break;
3862 }
3863 else if (prev_dup && IS_INSN(&nobj->link) && IS_INSN_ID(nobj, dup) &&
3864 !!(nobj = (INSN *)nobj->link.next) &&
3865 IS_INSN(&nobj->link) &&
3866 /* basic blocks, with no labels in the middle */
3867 nobj->insn_id == iobj->insn_id) {
3868 /*
3869 * dup
3870 * if L1
3871 * ...
3872 * L1:
3873 * dup
3874 * if L2
3875 * =>
3876 * dup
3877 * if L2
3878 * ...
3879 * L1:
3880 * dup
3881 * if L2
3882 */
3883 if (!replace_destination(iobj, nobj)) break;
3884 }
3885 else if (pobj) {
3886 /*
3887 * putnil
3888 * if L1
3889 * =>
3890 * # nothing
3891 *
3892 * putobject true
3893 * if L1
3894 * =>
3895 * jump L1
3896 *
3897 * dupstring ".."
3898 * if L1
3899 * =>
3900 * jump L1
3901 *
3902 * dupstring ".."
3903 * dup
3904 * if L1
3905 * =>
3906 * dupstring ".."
3907 * jump L1
3908 *
3909 */
3910 int cond;
3911 if (prev_dup && IS_INSN(pobj->link.prev)) {
3912 pobj = (INSN *)pobj->link.prev;
3913 }
3914 if (IS_INSN_ID(pobj, putobject)) {
3915 cond = (IS_INSN_ID(iobj, branchif) ?
3916 OPERAND_AT(pobj, 0) != Qfalse :
3917 IS_INSN_ID(iobj, branchunless) ?
3918 OPERAND_AT(pobj, 0) == Qfalse :
3919 FALSE);
3920 }
3921 else if (IS_INSN_ID(pobj, dupstring) ||
3922 IS_INSN_ID(pobj, duparray) ||
3923 IS_INSN_ID(pobj, newarray)) {
3924 cond = IS_INSN_ID(iobj, branchif);
3925 }
3926 else if (IS_INSN_ID(pobj, putnil)) {
3927 cond = !IS_INSN_ID(iobj, branchif);
3928 }
3929 else break;
3930 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3931 ELEM_REMOVE(iobj->link.prev);
3932 }
3933 else if (!iseq_pop_newarray(iseq, pobj)) {
3934 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3935 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3936 }
3937 if (cond) {
3938 if (prev_dup) {
3939 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3940 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3941 }
3942 iobj->insn_id = BIN(jump);
3943 goto again;
3944 }
3945 else {
3946 unref_destination(iobj, 0);
3947 ELEM_REMOVE(&iobj->link);
3948 }
3949 break;
3950 }
3951 else break;
3952 {
3953 LINK_ELEMENT *dest = get_destination_insn(nobj);
3954 if (!dest || !IS_INSN(dest)) break;
3955 nobj = (INSN *)dest;
3956 }
3957 }
3958 }
3959 }
3960
3961 if (IS_INSN_ID(iobj, pop)) {
3962 /*
3963 * putself / putnil / putobject obj / dupstring "..."
3964 * pop
3965 * =>
3966 * # do nothing
3967 */
3968 LINK_ELEMENT *prev = iobj->link.prev;
3969 if (IS_INSN(prev)) {
3970 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3971 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3972 previ == BIN(putself) || previ == BIN(dupstring) ||
3973 previ == BIN(dupchilledstring) ||
3974 previ == BIN(dup) ||
3975 previ == BIN(getlocal) ||
3976 previ == BIN(getblockparam) ||
3977 previ == BIN(getblockparamproxy) ||
3978 previ == BIN(getinstancevariable) ||
3979 previ == BIN(duparray)) {
3980 /* just push operand or static value and pop soon, no
3981 * side effects */
3982 ELEM_REMOVE(prev);
3983 ELEM_REMOVE(&iobj->link);
3984 }
3985 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3986 ELEM_REMOVE(&iobj->link);
3987 }
3988 else if (previ == BIN(concatarray)) {
3989 INSN *piobj = (INSN *)prev;
3990 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3991 INSN_OF(piobj) = BIN(pop);
3992 }
3993 else if (previ == BIN(concatstrings)) {
3994 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3995 ELEM_REMOVE(prev);
3996 }
3997 else {
3998 ELEM_REMOVE(&iobj->link);
3999 INSN_OF(prev) = BIN(adjuststack);
4000 }
4001 }
4002 }
4003 }
4004
4005 if (IS_INSN_ID(iobj, newarray) ||
4006 IS_INSN_ID(iobj, duparray) ||
4007 IS_INSN_ID(iobj, concatarray) ||
4008 IS_INSN_ID(iobj, splatarray) ||
4009 0) {
4010 /*
4011 * newarray N
4012 * splatarray
4013 * =>
4014 * newarray N
4015 * newarray always puts an array
4016 */
4017 LINK_ELEMENT *next = iobj->link.next;
4018 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
4019 /* remove splatarray following always-array insn */
4020 ELEM_REMOVE(next);
4021 }
4022 }
4023
4024 if (IS_INSN_ID(iobj, newarray)) {
4025 LINK_ELEMENT *next = iobj->link.next;
4026 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
4027 OPERAND_AT(next, 1) == INT2FIX(0)) {
4028 VALUE op1, op2;
4029 op1 = OPERAND_AT(iobj, 0);
4030 op2 = OPERAND_AT(next, 0);
4031 ELEM_REMOVE(next);
4032
4033 if (op1 == op2) {
4034 /*
4035 * newarray 2
4036 * expandarray 2, 0
4037 * =>
4038 * swap
4039 */
4040 if (op1 == INT2FIX(2)) {
4041 INSN_OF(iobj) = BIN(swap);
4042 iobj->operand_size = 0;
4043 }
4044 /*
4045 * newarray X
4046 * expandarray X, 0
4047 * =>
4048 * opt_reverse X
4049 */
4050 else {
4051 INSN_OF(iobj) = BIN(opt_reverse);
4052 }
4053 }
4054 else {
4055 long diff = FIX2LONG(op1) - FIX2LONG(op2);
4056 INSN_OF(iobj) = BIN(opt_reverse);
4057 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
4058
4059 if (op1 > op2) {
4060 /* X > Y
4061 * newarray X
4062 * expandarray Y, 0
4063 * =>
4064 * pop * (Y-X)
4065 * opt_reverse Y
4066 */
4067 for (; diff > 0; diff--) {
4068 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
4069 }
4070 }
4071 else { /* (op1 < op2) */
4072 /* X < Y
4073 * newarray X
4074 * expandarray Y, 0
4075 * =>
4076 * putnil * (Y-X)
4077 * opt_reverse Y
4078 */
4079 for (; diff < 0; diff++) {
4080 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
4081 }
4082 }
4083 }
4084 }
4085 }
4086
4087 if (IS_INSN_ID(iobj, duparray)) {
4088 LINK_ELEMENT *next = iobj->link.next;
4089 /*
4090 * duparray obj
4091 * expandarray X, 0
4092 * =>
4093 * putobject obj
4094 * expandarray X, 0
4095 */
4096 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
4097 INSN_OF(iobj) = BIN(putobject);
4098 }
4099 }
4100
4101 if (IS_INSN_ID(iobj, anytostring)) {
4102 LINK_ELEMENT *next = iobj->link.next;
4103 /*
4104 * anytostring
4105 * concatstrings 1
4106 * =>
4107 * anytostring
4108 */
4109 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
4110 OPERAND_AT(next, 0) == INT2FIX(1)) {
4111 ELEM_REMOVE(next);
4112 }
4113 }
4114
4115 if (IS_INSN_ID(iobj, dupstring) || IS_INSN_ID(iobj, dupchilledstring) ||
4116 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
4117 /*
4118 * dupstring ""
4119 * concatstrings N
4120 * =>
4121 * concatstrings N-1
4122 */
4123 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
4124 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
4125 INSN *next = (INSN *)iobj->link.next;
4126 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
4127 ELEM_REMOVE(&next->link);
4128 }
4129 ELEM_REMOVE(&iobj->link);
4130 }
4131 if (IS_NEXT_INSN_ID(&iobj->link, toregexp)) {
4132 INSN *next = (INSN *)iobj->link.next;
4133 if (OPERAND_AT(next, 1) == INT2FIX(1)) {
4134 VALUE src = OPERAND_AT(iobj, 0);
4135 int opt = (int)FIX2LONG(OPERAND_AT(next, 0));
4136 VALUE path = rb_iseq_path(iseq);
4137 int line = iobj->insn_info.line_no;
4138 VALUE re = iseq_reg_compile(iseq, src, opt, RSTRING_PTR(path), line);
4139 /* The folded operand is a Regexp, so the instruction must be
4140 * putobject: dupstring/dupchilledstring would resurrect the
4141 * Regexp as a String at run time (e.g. for a /o regexp whose
4142 * interpolation folds to a constant, such as /#{"a"}/o). */
4143 iobj->insn_id = BIN(putobject);
4144 RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
4145 ELEM_REMOVE(iobj->link.next);
4146 }
4147 }
4148 }
4149
4150 if (IS_INSN_ID(iobj, concatstrings)) {
4151 /*
4152 * concatstrings N
4153 * concatstrings M
4154 * =>
4155 * concatstrings N+M-1
4156 */
4157 LINK_ELEMENT *next = iobj->link.next;
4158 INSN *jump = 0;
4159 if (IS_INSN(next) && IS_INSN_ID(next, jump))
4160 next = get_destination_insn(jump = (INSN *)next);
4161 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
4162 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
4163 OPERAND_AT(iobj, 0) = INT2FIX(n);
4164 if (jump) {
4165 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
4166 if (!--label->refcnt) {
4167 ELEM_REMOVE(&label->link);
4168 }
4169 else {
4170 label = NEW_LABEL(0);
4171 OPERAND_AT(jump, 0) = (VALUE)label;
4172 }
4173 label->refcnt++;
4174 ELEM_INSERT_NEXT(next, &label->link);
4175 CHECK(iseq_peephole_optimize(iseq, unref, get_next_insn(jump), do_tailcallopt));
4176 }
4177 else {
4178 ELEM_REMOVE(next);
4179 }
4180 }
4181 }
4182
4183 if (do_tailcallopt &&
4184 (IS_INSN_ID(iobj, send) ||
4185 IS_INSN_ID(iobj, invokesuper))) {
4186 /*
4187 * send ...
4188 * leave
4189 * =>
4190 * send ..., ... | VM_CALL_TAILCALL, ...
4191 * leave # unreachable
4192 */
4193 INSN *piobj = NULL;
4194 if (iobj->link.next) {
4195 LINK_ELEMENT *next = iobj->link.next;
4196 do {
4197 if (!IS_INSN(next)) {
4198 next = next->next;
4199 continue;
4200 }
4201 switch (INSN_OF(next)) {
4202 case BIN(nop):
4203 next = next->next;
4204 break;
4205 case BIN(jump):
4206 /* if cond
4207 * return tailcall
4208 * end
4209 */
4210 next = get_destination_insn((INSN *)next);
4211 break;
4212 case BIN(leave):
4213 piobj = iobj;
4214 /* fall through */
4215 default:
4216 next = NULL;
4217 break;
4218 }
4219 } while (next);
4220 }
4221
4222 if (piobj) {
4223 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
4224 if (IS_INSN_ID(piobj, send) ||
4225 IS_INSN_ID(piobj, invokesuper)) {
4226 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
4227 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4228 OPERAND_AT(piobj, 0) = (VALUE)ci;
4229 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4230 }
4231 }
4232 else {
4233 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4234 OPERAND_AT(piobj, 0) = (VALUE)ci;
4235 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4236 }
4237 }
4238 }
4239
4240 if (IS_INSN_ID(iobj, dup)) {
4241 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
4242 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
4243
4244 /*
4245 * dup
4246 * setlocal x, y
4247 * setlocal x, y
4248 * =>
4249 * dup
4250 * setlocal x, y
4251 */
4252 if (IS_NEXT_INSN_ID(set1, setlocal)) {
4253 set2 = set1->next;
4254 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4255 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4256 ELEM_REMOVE(set1);
4257 ELEM_REMOVE(&iobj->link);
4258 }
4259 }
4260
4261 /*
4262 * dup
4263 * setlocal x, y
4264 * dup
4265 * setlocal x, y
4266 * =>
4267 * dup
4268 * setlocal x, y
4269 */
4270 else if (IS_NEXT_INSN_ID(set1, dup) &&
4271 IS_NEXT_INSN_ID(set1->next, setlocal)) {
4272 set2 = set1->next->next;
4273 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4274 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4275 ELEM_REMOVE(set1->next);
4276 ELEM_REMOVE(set2);
4277 }
4278 }
4279 }
4280 }
4281
4282 /*
4283 * getlocal x, y
4284 * dup
4285 * setlocal x, y
4286 * =>
4287 * dup
4288 */
4289 if (IS_INSN_ID(iobj, getlocal)) {
4290 LINK_ELEMENT *niobj = &iobj->link;
4291 if (IS_NEXT_INSN_ID(niobj, dup)) {
4292 niobj = niobj->next;
4293 }
4294 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
4295 LINK_ELEMENT *set1 = niobj->next;
4296 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
4297 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
4298 ELEM_REMOVE(set1);
4299 ELEM_REMOVE(niobj);
4300 }
4301 }
4302 }
4303
4304 /*
4305 * opt_invokebuiltin_delegate
4306 * trace
4307 * leave
4308 * =>
4309 * opt_invokebuiltin_delegate_leave
4310 * trace
4311 * leave
4312 */
4313 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4314 if (IS_TRACE(iobj->link.next)) {
4315 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4316 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4317 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
4318 if (iobj == (INSN *)list && bf->argc == 0 && (ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4319 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4320 }
4321 }
4322 }
4323 }
4324
4325 /*
4326 * getblockparam
4327 * branchif / branchunless
4328 * =>
4329 * getblockparamproxy
4330 * branchif / branchunless
4331 */
4332 if (IS_INSN_ID(iobj, getblockparam)) {
4333 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4334 iobj->insn_id = BIN(getblockparamproxy);
4335 }
4336 }
4337
4338 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4339 LINK_ELEMENT *niobj = &iobj->link;
4340 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4341 niobj = niobj->next;
4342 LINK_ELEMENT *siobj;
4343 unsigned int set_flags = 0, unset_flags = 0;
4344
4345 /*
4346 * Eliminate hash allocation for f(*a, kw: 1)
4347 *
4348 * splatarray false
4349 * duphash
4350 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4351 * =>
4352 * splatarray false
4353 * putobject
4354 * send ARGS_SPLAT|KW_SPLAT
4355 */
4356 if (IS_NEXT_INSN_ID(niobj, send)) {
4357 siobj = niobj->next;
4358 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4359 unset_flags = VM_CALL_ARGS_BLOCKARG;
4360 }
4361 /*
4362 * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4363 *
4364 * splatarray false
4365 * duphash
4366 * getlocal / getinstancevariable / getblockparamproxy
4367 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4368 * =>
4369 * splatarray false
4370 * putobject
4371 * getlocal / getinstancevariable / getblockparamproxy
4372 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4373 */
4374 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4375 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4376 siobj = niobj->next->next;
4377 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4378 }
4379
4380 if (set_flags) {
4381 const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4382 unsigned int flags = vm_ci_flag(ci);
4383 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4384 ((INSN*)niobj)->insn_id = BIN(putobject);
4385 RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), RB_OBJ_SET_SHAREABLE(rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)))));
4386
4387 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4388 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4389 RB_OBJ_WRITTEN(iseq, ci, nci);
4390 OPERAND_AT(siobj, 0) = (VALUE)nci;
4391 }
4392 }
4393 }
4394 }
4395
4396 /*
4397 * putself / (or any other independent instruction)
4398 * putnil / (or any other independent instruction)
4399 * swap
4400 * =>
4401 * putnil / (or any other independent instruction)
4402 * putself / (or any other independent instruction)
4403 */
4404 if (IS_NEXT_INSN_ID(&iobj->link, swap)) {
4405 LINK_ELEMENT *second = &iobj->link;
4406 LINK_ELEMENT *first = second->prev;
4407 LINK_ELEMENT *swap = second->next;
4408
4409 if (IS_INDEPENDENT_INSN(first) && IS_INDEPENDENT_INSN(second)) {
4410 ELEM_REMOVE(swap);
4411 ELEM_SWAP(first, second);
4412 }
4413 }
4414
4415 return COMPILE_OK;
4416}
4417
4418static int
4419insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4420{
4421 if (insn_id == BIN(opt_neq)) {
4422 VALUE original_ci = iobj->operands[0];
4423 VALUE new_ci = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4424 insn_replace_with_operands(iseq, iobj, insn_id, 2, new_ci, original_ci);
4425 }
4426 else {
4427 iobj->insn_id = insn_id;
4428 iobj->operand_size = insn_len(insn_id) - 1;
4429 }
4430 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4431
4432 return COMPILE_OK;
4433}
4434
4435static int
4436iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4437{
4438 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4439 IS_INSN(iobj->link.next)) {
4440 /*
4441 * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4442 */
4443 INSN *niobj = (INSN *)iobj->link.next;
4444 if (IS_INSN_ID(niobj, send)) {
4445 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4446 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4447 VALUE method = INT2FIX(0);
4448 switch (vm_ci_mid(ci)) {
4449 case idMax:
4450 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4451 break;
4452 case idMin:
4453 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4454 break;
4455 case idHash:
4456 method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4457 break;
4458 }
4459
4460 if (method != INT2FIX(0)) {
4461 VALUE num = iobj->operands[0];
4462 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, num, method);
4463 ELEM_REMOVE(&niobj->link);
4464 return COMPILE_OK;
4465 }
4466 }
4467 }
4468 else if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
4469 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4470 IS_NEXT_INSN_ID(&niobj->link, send)) {
4471 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4472 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4473 VALUE num = iobj->operands[0];
4474 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK));
4475 ELEM_REMOVE(&iobj->link);
4476 ELEM_REMOVE(niobj->link.next);
4477 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4478 return COMPILE_OK;
4479 }
4480 }
4481 // newarray n, dupchilledstring "E", getlocal b, send :pack with {buffer: b}
4482 // -> dupchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
4483 else if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
4484 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4485 IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4486 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4487 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4488 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4489 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4490 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4491 VALUE num = iobj->operands[0];
4492 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 2), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER));
4493 // Remove the "send" insn.
4494 ELEM_REMOVE((niobj->link.next)->next);
4495 // Remove the modified insn from its original "newarray" position...
4496 ELEM_REMOVE(&iobj->link);
4497 // and insert it after the buffer insn.
4498 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4499 return COMPILE_OK;
4500 }
4501 }
4502
4503 // Break the "else if" chain since some prior checks abort after sub-ifs.
4504 // We already found "newarray". To match `[...].include?(arg)` we look for
4505 // the instruction(s) representing the argument followed by a "send".
4506 if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
4507 IS_INSN_ID(niobj, putobject) ||
4508 IS_INSN_ID(niobj, putself) ||
4509 IS_INSN_ID(niobj, getlocal) ||
4510 IS_INSN_ID(niobj, getinstancevariable)) &&
4511 IS_NEXT_INSN_ID(&niobj->link, send)) {
4512
4513 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4514 const struct rb_callinfo *ci;
4515 // Allow any number (0 or more) of simple method calls on the argument
4516 // (as in `[...].include?(arg.method1.method2)`.
4517 do {
4518 sendobj = sendobj->next;
4519 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4520 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4521
4522 // If this send is for .include? with one arg we can do our opt.
4523 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4524 VALUE num = iobj->operands[0];
4525 INSN *sendins = (INSN *)sendobj;
4526 insn_replace_with_operands(iseq, sendins, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P));
4527 // Remove the original "newarray" insn.
4528 ELEM_REMOVE(&iobj->link);
4529 return COMPILE_OK;
4530 }
4531 }
4532 }
4533
4534 /*
4535 * duparray [...]
4536 * some insn for the arg...
4537 * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4538 * =>
4539 * arg insn...
4540 * opt_duparray_send [...], :include?, 1
4541 */
4542 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4543 INSN *niobj = (INSN *)iobj->link.next;
4544 if ((IS_INSN_ID(niobj, getlocal) ||
4545 IS_INSN_ID(niobj, getinstancevariable) ||
4546 IS_INSN_ID(niobj, putself) ||
4547 IS_INSN_ID(niobj, putobject) ||
4548 IS_INSN_ID(niobj, putnil)) &&
4549 IS_NEXT_INSN_ID(&niobj->link, send)) {
4550
4551 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4552 const struct rb_callinfo *ci;
4553 // Allow any number (0 or more) of simple method calls on the argument
4554 // (as in `[...].include?(arg.method1.method2)`.
4555 do {
4556 sendobj = sendobj->next;
4557 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4558 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4559
4560 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4561 // Move the array arg from duparray to opt_duparray_send.
4562 VALUE ary = iobj->operands[0];
4564
4565 INSN *sendins = (INSN *)sendobj;
4566 insn_replace_with_operands(iseq, sendins, BIN(opt_duparray_send), 3, ary, rb_id2sym(idIncludeP), INT2FIX(1));
4567
4568 // Remove the duparray insn.
4569 ELEM_REMOVE(&iobj->link);
4570 return COMPILE_OK;
4571 }
4572 }
4573 }
4574
4575
4576 if (IS_INSN_ID(iobj, send)) {
4577 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4578 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4579
4580#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4581 if (vm_ci_simple(ci)) {
4582 switch (vm_ci_argc(ci)) {
4583 case 0:
4584 switch (vm_ci_mid(ci)) {
4585 case idLength: SP_INSN(length); return COMPILE_OK;
4586 case idSize: SP_INSN(size); return COMPILE_OK;
4587 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4588 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4589 case idSucc: SP_INSN(succ); return COMPILE_OK;
4590 case idNot: SP_INSN(not); return COMPILE_OK;
4591 }
4592 break;
4593 case 1:
4594 switch (vm_ci_mid(ci)) {
4595 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4596 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4597 case idMULT: SP_INSN(mult); return COMPILE_OK;
4598 case idDIV: SP_INSN(div); return COMPILE_OK;
4599 case idMOD: SP_INSN(mod); return COMPILE_OK;
4600 case idEq: SP_INSN(eq); return COMPILE_OK;
4601 case idNeq: SP_INSN(neq); return COMPILE_OK;
4602 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4603 case idLT: SP_INSN(lt); return COMPILE_OK;
4604 case idLE: SP_INSN(le); return COMPILE_OK;
4605 case idGT: SP_INSN(gt); return COMPILE_OK;
4606 case idGE: SP_INSN(ge); return COMPILE_OK;
4607 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4608 case idAREF: SP_INSN(aref); return COMPILE_OK;
4609 case idAnd: SP_INSN(and); return COMPILE_OK;
4610 case idOr: SP_INSN(or); return COMPILE_OK;
4611 }
4612 break;
4613 case 2:
4614 switch (vm_ci_mid(ci)) {
4615 case idASET: SP_INSN(aset); return COMPILE_OK;
4616 }
4617 break;
4618 }
4619 }
4620
4621 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4622 iobj->insn_id = BIN(opt_send_without_block);
4623 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4624 }
4625 }
4626#undef SP_INSN
4627
4628 return COMPILE_OK;
4629}
4630
4631static inline int
4632tailcallable_p(rb_iseq_t *iseq)
4633{
4634 switch (ISEQ_BODY(iseq)->type) {
4635 case ISEQ_TYPE_TOP:
4636 case ISEQ_TYPE_EVAL:
4637 case ISEQ_TYPE_MAIN:
4638 /* not tail callable because cfp will be over popped */
4639 case ISEQ_TYPE_RESCUE:
4640 case ISEQ_TYPE_ENSURE:
4641 /* rescue block can't tail call because of errinfo */
4642 return FALSE;
4643 default:
4644 return TRUE;
4645 }
4646}
4647
4648static int
4649iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4650{
4651 LINK_ELEMENT *list;
4652 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4653 const int do_tailcallopt = tailcallable_p(iseq) &&
4654 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4655 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4656 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4657 const int do_without_ints = ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_WITHOUT_INTERRUPTS;
4658 int rescue_level = 0;
4659 int tailcallopt = do_tailcallopt;
4660
4661 list = FIRST_ELEMENT(anchor);
4662
4663 int do_block_optimization = 0;
4664 LABEL * block_loop_label = NULL;
4665
4666 int nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
4667 VALUE unref_counts_buf = 0, unref_stamps_buf = 0;
4669 .capacity = nlabels,
4670 .gen = 0,
4671 .counts = ALLOCV_N(int, unref_counts_buf, nlabels),
4672 .stamps = ALLOCV_N(unsigned int, unref_stamps_buf, nlabels),
4673 };
4674 MEMZERO(unreachable_unref.counts, int, nlabels);
4675 MEMZERO(unreachable_unref.stamps, unsigned int, nlabels);
4676
4677 // If we're optimizing a block
4678 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
4679 do_block_optimization = 1;
4680
4681 // If the block starts with a nop and a label,
4682 // record the label so we can detect if it's a jump target
4683 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4684 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop) && IS_LABEL(le->next)) {
4685 block_loop_label = (LABEL *)le->next;
4686 }
4687 }
4688
4689 while (list) {
4690 if (IS_INSN(list)) {
4691 if (do_peepholeopt) {
4692 iseq_peephole_optimize(iseq, &unreachable_unref, list, tailcallopt);
4693 }
4694 if (do_si) {
4695 iseq_specialized_instruction(iseq, (INSN *)list);
4696 }
4697 if (do_ou) {
4698 insn_operands_unification((INSN *)list);
4699 }
4700
4701 if (do_without_ints) {
4702 INSN *item = (INSN *)list;
4703 if (IS_INSN_ID(item, jump)) {
4704 item->insn_id = BIN(jump_without_ints);
4705 }
4706 else if (IS_INSN_ID(item, branchif)) {
4707 item->insn_id = BIN(branchif_without_ints);
4708 }
4709 else if (IS_INSN_ID(item, branchunless)) {
4710 item->insn_id = BIN(branchunless_without_ints);
4711 }
4712 else if (IS_INSN_ID(item, branchnil)) {
4713 item->insn_id = BIN(branchnil_without_ints);
4714 }
4715 }
4716
4717 if (do_block_optimization) {
4718 INSN * item = (INSN *)list;
4719 // Give up if there is a throw
4720 if (IS_INSN_ID(item, throw)) {
4721 do_block_optimization = 0;
4722 }
4723 else {
4724 // If the instruction has a jump target, check if the
4725 // jump target is the block loop label
4726 const char *types = insn_op_types(item->insn_id);
4727 for (int j = 0; types[j]; j++) {
4728 if (types[j] == TS_OFFSET) {
4729 // If the jump target is equal to the block loop
4730 // label, then we can't do the optimization because
4731 // the leading `nop` instruction fires the block
4732 // entry tracepoint
4733 LABEL * target = (LABEL *)OPERAND_AT(item, j);
4734 if (target == block_loop_label) {
4735 do_block_optimization = 0;
4736 }
4737 }
4738 }
4739 }
4740 }
4741 }
4742 if (IS_LABEL(list)) {
4743 switch (((LABEL *)list)->rescued) {
4744 case LABEL_RESCUE_BEG:
4745 rescue_level++;
4746 tailcallopt = FALSE;
4747 break;
4748 case LABEL_RESCUE_END:
4749 if (!--rescue_level) tailcallopt = do_tailcallopt;
4750 break;
4751 }
4752 }
4753 list = list->next;
4754 }
4755
4756 if (do_block_optimization) {
4757 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4758 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4759 ELEM_REMOVE(le);
4760 }
4761 }
4762
4763 ALLOCV_END(unref_counts_buf);
4764 ALLOCV_END(unref_stamps_buf);
4765 return COMPILE_OK;
4766}
4767
4768#if OPT_INSTRUCTIONS_UNIFICATION
4769static INSN *
4770new_unified_insn(rb_iseq_t *iseq,
4771 int insn_id, int size, LINK_ELEMENT *seq_list)
4772{
4773 INSN *iobj = 0;
4774 LINK_ELEMENT *list = seq_list;
4775 int i, argc = 0;
4776 VALUE *operands = 0, *ptr = 0;
4777
4778
4779 /* count argc */
4780 for (i = 0; i < size; i++) {
4781 iobj = (INSN *)list;
4782 argc += iobj->operand_size;
4783 list = list->next;
4784 }
4785
4786 if (argc > 0) {
4787 ptr = operands = compile_data_alloc2_type(iseq, VALUE, argc);
4788 }
4789
4790 /* copy operands */
4791 list = seq_list;
4792 for (i = 0; i < size; i++) {
4793 iobj = (INSN *)list;
4794 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4795 ptr += iobj->operand_size;
4796 list = list->next;
4797 }
4798
4799 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4800}
4801#endif
4802
4803/*
4804 * This scheme can get more performance if do this optimize with
4805 * label address resolving.
4806 * It's future work (if compile time was bottle neck).
4807 */
4808static int
4809iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4810{
4811#if OPT_INSTRUCTIONS_UNIFICATION
4812 LINK_ELEMENT *list;
4813 INSN *iobj, *niobj;
4814 int id, k;
4815 intptr_t j;
4816
4817 list = FIRST_ELEMENT(anchor);
4818 while (list) {
4819 if (IS_INSN(list)) {
4820 iobj = (INSN *)list;
4821 id = iobj->insn_id;
4822 if (unified_insns_data[id] != 0) {
4823 const int *const *entry = unified_insns_data[id];
4824 for (j = 1; j < (intptr_t)entry[0]; j++) {
4825 const int *unified = entry[j];
4826 LINK_ELEMENT *li = list->next;
4827 for (k = 2; k < unified[1]; k++) {
4828 if (!IS_INSN(li) ||
4829 ((INSN *)li)->insn_id != unified[k]) {
4830 goto miss;
4831 }
4832 li = li->next;
4833 }
4834 /* matched */
4835 niobj =
4836 new_unified_insn(iseq, unified[0], unified[1] - 1,
4837 list);
4838
4839 /* insert to list */
4840 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4841 niobj->link.next = li;
4842 if (li) {
4843 li->prev = (LINK_ELEMENT *)niobj;
4844 }
4845
4846 list->prev->next = (LINK_ELEMENT *)niobj;
4847 list = (LINK_ELEMENT *)niobj;
4848 break;
4849 miss:;
4850 }
4851 }
4852 }
4853 list = list->next;
4854 }
4855#endif
4856 return COMPILE_OK;
4857}
4858
4859static int
4860all_string_result_p(const NODE *node)
4861{
4862 if (!node) return FALSE;
4863 switch (nd_type(node)) {
4864 case NODE_STR: case NODE_DSTR: case NODE_FILE:
4865 return TRUE;
4866 case NODE_IF: case NODE_UNLESS:
4867 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4868 if (all_string_result_p(RNODE_IF(node)->nd_body))
4869 return all_string_result_p(RNODE_IF(node)->nd_else);
4870 return FALSE;
4871 case NODE_AND: case NODE_OR:
4872 if (!RNODE_AND(node)->nd_2nd)
4873 return all_string_result_p(RNODE_AND(node)->nd_1st);
4874 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4875 return FALSE;
4876 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4877 default:
4878 return FALSE;
4879 }
4880}
4881
4883 rb_iseq_t *const iseq;
4884 LINK_ANCHOR *const ret;
4885 VALUE lit;
4886 const NODE *lit_node;
4887 int cnt;
4888 int dregx;
4889};
4890
4891static int
4892append_dstr_fragment(struct dstr_ctxt *args, const NODE *const node, rb_parser_string_t *str)
4893{
4894 VALUE s = rb_str_new_mutable_parser_string(str);
4895 if (args->dregx) {
4896 VALUE error = rb_reg_check_preprocess(s);
4897 if (!NIL_P(error)) {
4898 COMPILE_ERROR(args->iseq, nd_line(node), "%" PRIsVALUE, error);
4899 return COMPILE_NG;
4900 }
4901 }
4902 if (NIL_P(args->lit)) {
4903 args->lit = s;
4904 args->lit_node = node;
4905 }
4906 else {
4907 rb_str_buf_append(args->lit, s);
4908 }
4909 return COMPILE_OK;
4910}
4911
4912static void
4913flush_dstr_fragment(struct dstr_ctxt *args)
4914{
4915 if (!NIL_P(args->lit)) {
4916 rb_iseq_t *iseq = args->iseq;
4917 VALUE lit = args->lit;
4918 args->lit = Qnil;
4919 lit = rb_fstring(lit);
4920 ADD_INSN1(args->ret, args->lit_node, putobject, lit);
4921 RB_OBJ_WRITTEN(args->iseq, Qundef, lit);
4922 args->cnt++;
4923 }
4924}
4925
4926static int
4927compile_dstr_fragments_0(struct dstr_ctxt *args, const NODE *const node)
4928{
4929 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4930 rb_parser_string_t *str = RNODE_DSTR(node)->string;
4931
4932 if (str) {
4933 CHECK(append_dstr_fragment(args, node, str));
4934 }
4935
4936 while (list) {
4937 const NODE *const head = list->nd_head;
4938 if (nd_type_p(head, NODE_STR)) {
4939 CHECK(append_dstr_fragment(args, node, RNODE_STR(head)->string));
4940 }
4941 else if (nd_type_p(head, NODE_DSTR)) {
4942 CHECK(compile_dstr_fragments_0(args, head));
4943 }
4944 else {
4945 flush_dstr_fragment(args);
4946 rb_iseq_t *iseq = args->iseq;
4947 CHECK(COMPILE(args->ret, "each string", head));
4948 args->cnt++;
4949 }
4950 list = (struct RNode_LIST *)list->nd_next;
4951 }
4952 return COMPILE_OK;
4953}
4954
4955static int
4956compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp, int dregx)
4957{
4958 struct dstr_ctxt args = {
4959 .iseq = iseq, .ret = ret,
4960 .lit = Qnil, .lit_node = NULL,
4961 .cnt = 0, .dregx = dregx,
4962 };
4963 CHECK(compile_dstr_fragments_0(&args, node));
4964 flush_dstr_fragment(&args);
4965
4966 *cntp = args.cnt;
4967
4968 return COMPILE_OK;
4969}
4970
4971static int
4972compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4973{
4974 while (node && nd_type_p(node, NODE_BLOCK)) {
4975 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4976 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4977 node = RNODE_BLOCK(node)->nd_next;
4978 }
4979 if (node) {
4980 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4981 }
4982 return COMPILE_OK;
4983}
4984
4985static int
4986compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4987{
4988 int cnt;
4989 if (!RNODE_DSTR(node)->nd_next) {
4990 VALUE lit = rb_node_dstr_string_val(node);
4991 ADD_INSN1(ret, node, dupstring, lit);
4993 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4994 }
4995 else {
4996 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, FALSE));
4997 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4998 }
4999 return COMPILE_OK;
5000}
5001
5002static int
5003compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
5004{
5005 int cnt;
5006 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
5007
5008 if (!RNODE_DREGX(node)->nd_next) {
5009 if (!popped) {
5010 VALUE src = rb_node_dregx_string_val(node);
5011 VALUE match = iseq_reg_compile(iseq, src, cflag, NULL, 0);
5012 ADD_INSN1(ret, node, putobject, match);
5013 RB_OBJ_WRITTEN(iseq, Qundef, match);
5014 }
5015 return COMPILE_OK;
5016 }
5017
5018 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, TRUE));
5019 ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
5020
5021 if (popped) {
5022 ADD_INSN(ret, node, pop);
5023 }
5024
5025 return COMPILE_OK;
5026}
5027
5028static int
5029compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
5030 LABEL *then_label, LABEL *else_label)
5031{
5032 const int line = nd_line(node);
5033 LABEL *lend = NEW_LABEL(line);
5034 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
5035 + VM_SVAR_FLIPFLOP_START;
5036 VALUE key = INT2FIX(cnt);
5037
5038 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
5039 ADD_INSNL(ret, node, branchif, lend);
5040
5041 /* *flip == 0 */
5042 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
5043 ADD_INSNL(ret, node, branchunless, else_label);
5044 ADD_INSN1(ret, node, putobject, Qtrue);
5045 ADD_INSN1(ret, node, setspecial, key);
5046 if (!again) {
5047 ADD_INSNL(ret, node, jump, then_label);
5048 }
5049
5050 /* *flip == 1 */
5051 ADD_LABEL(ret, lend);
5052 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
5053 ADD_INSNL(ret, node, branchunless, then_label);
5054 ADD_INSN1(ret, node, putobject, Qfalse);
5055 ADD_INSN1(ret, node, setspecial, key);
5056 ADD_INSNL(ret, node, jump, then_label);
5057
5058 return COMPILE_OK;
5059}
5060
5061static int
5062compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
5063 LABEL *then_label, LABEL *else_label);
5064
5065#define COMPILE_SINGLE 2
5066static int
5067compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
5068 LABEL *then_label, LABEL *else_label)
5069{
5070 DECL_ANCHOR(seq);
5071 INIT_ANCHOR(seq);
5072 LABEL *label = NEW_LABEL(nd_line(cond));
5073 if (!then_label) then_label = label;
5074 else if (!else_label) else_label = label;
5075
5076 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
5077
5078 if (LIST_INSN_SIZE_ONE(seq)) {
5079 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
5080 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
5081 return COMPILE_OK;
5082 }
5083 if (!label->refcnt) {
5084 return COMPILE_SINGLE;
5085 }
5086 ADD_LABEL(seq, label);
5087 ADD_SEQ(ret, seq);
5088 return COMPILE_OK;
5089}
5090
5091static int
5092compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
5093 LABEL *then_label, LABEL *else_label)
5094{
5095 int ok;
5096 DECL_ANCHOR(ignore);
5097
5098 again:
5099 switch (nd_type(cond)) {
5100 case NODE_AND:
5101 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
5102 cond = RNODE_AND(cond)->nd_2nd;
5103 if (ok == COMPILE_SINGLE) {
5104 ADD_INSNL(ret, cond, jump, else_label);
5105 INIT_ANCHOR(ignore);
5106 ret = ignore;
5107 then_label = NEW_LABEL(nd_line(cond));
5108 }
5109 goto again;
5110 case NODE_OR:
5111 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
5112 cond = RNODE_OR(cond)->nd_2nd;
5113 if (ok == COMPILE_SINGLE) {
5114 ADD_INSNL(ret, cond, jump, then_label);
5115 INIT_ANCHOR(ignore);
5116 ret = ignore;
5117 else_label = NEW_LABEL(nd_line(cond));
5118 }
5119 goto again;
5120 case NODE_SYM:
5121 case NODE_LINE:
5122 case NODE_FILE:
5123 case NODE_ENCODING:
5124 case NODE_INTEGER: /* NODE_INTEGER is always true */
5125 case NODE_FLOAT: /* NODE_FLOAT is always true */
5126 case NODE_RATIONAL: /* NODE_RATIONAL is always true */
5127 case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
5128 case NODE_TRUE:
5129 case NODE_STR:
5130 case NODE_REGX:
5131 case NODE_ZLIST:
5132 case NODE_LAMBDA:
5133 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
5134 ADD_INSNL(ret, cond, jump, then_label);
5135 return COMPILE_OK;
5136 case NODE_FALSE:
5137 case NODE_NIL:
5138 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
5139 ADD_INSNL(ret, cond, jump, else_label);
5140 return COMPILE_OK;
5141 case NODE_LIST:
5142 case NODE_ARGSCAT:
5143 case NODE_DREGX:
5144 case NODE_DSTR:
5145 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
5146 ADD_INSNL(ret, cond, jump, then_label);
5147 return COMPILE_OK;
5148 case NODE_FLIP2:
5149 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
5150 return COMPILE_OK;
5151 case NODE_FLIP3:
5152 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
5153 return COMPILE_OK;
5154 case NODE_DEFINED:
5155 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
5156 break;
5157 default:
5158 {
5159 DECL_ANCHOR(cond_seq);
5160 INIT_ANCHOR(cond_seq);
5161
5162 CHECK(COMPILE(cond_seq, "branch condition", cond));
5163
5164 if (LIST_INSN_SIZE_ONE(cond_seq)) {
5165 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
5166 if (insn->insn_id == BIN(putobject)) {
5167 if (RTEST(insn->operands[0])) {
5168 ADD_INSNL(ret, cond, jump, then_label);
5169 // maybe unreachable
5170 return COMPILE_OK;
5171 }
5172 else {
5173 ADD_INSNL(ret, cond, jump, else_label);
5174 return COMPILE_OK;
5175 }
5176 }
5177 }
5178 ADD_SEQ(ret, cond_seq);
5179 }
5180 break;
5181 }
5182
5183 ADD_INSNL(ret, cond, branchunless, else_label);
5184 ADD_INSNL(ret, cond, jump, then_label);
5185 return COMPILE_OK;
5186}
5187
5188#define HASH_BRACE 1
5189
5190static int
5191keyword_node_p(const NODE *const node)
5192{
5193 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
5194}
5195
5196static VALUE
5197get_symbol_value(rb_iseq_t *iseq, const NODE *node)
5198{
5199 switch (nd_type(node)) {
5200 case NODE_SYM:
5201 return rb_node_sym_string_val(node);
5202 default:
5203 UNKNOWN_NODE("get_symbol_value", node, Qnil);
5204 }
5205}
5206
5207static VALUE
5208node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
5209{
5210 NODE *node = node_hash->nd_head;
5211 VALUE hash = rb_hash_new();
5212 VALUE ary = rb_ary_new();
5213
5214 for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5215 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
5216 VALUE idx = rb_hash_aref(hash, key);
5217 if (!NIL_P(idx)) {
5218 rb_ary_store(ary, FIX2INT(idx), Qfalse);
5219 (*count_ptr)--;
5220 }
5221 rb_hash_aset(hash, key, INT2FIX(i));
5222 rb_ary_store(ary, i, Qtrue);
5223 (*count_ptr)++;
5224 }
5225
5226 return ary;
5227}
5228
5229static int
5230compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5231 const NODE *const root_node,
5232 struct rb_callinfo_kwarg **const kw_arg_ptr,
5233 unsigned int *flag)
5234{
5235 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
5236 RUBY_ASSERT(kw_arg_ptr != NULL);
5237 RUBY_ASSERT(flag != NULL);
5238
5239 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
5240 const NODE *node = RNODE_HASH(root_node)->nd_head;
5241 int seen_nodes = 0;
5242
5243 while (node) {
5244 const NODE *key_node = RNODE_LIST(node)->nd_head;
5245 seen_nodes++;
5246
5247 RUBY_ASSERT(nd_type_p(node, NODE_LIST));
5248 if (key_node && nd_type_p(key_node, NODE_SYM)) {
5249 /* can be keywords */
5250 }
5251 else {
5252 if (flag) {
5253 *flag |= VM_CALL_KW_SPLAT;
5254 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5255 /* A new hash will be created for the keyword arguments
5256 * in this case, so mark the method as passing mutable
5257 * keyword splat.
5258 */
5259 *flag |= VM_CALL_KW_SPLAT_MUT;
5260 }
5261 }
5262 return FALSE;
5263 }
5264 node = RNODE_LIST(node)->nd_next; /* skip value node */
5265 node = RNODE_LIST(node)->nd_next;
5266 }
5267
5268 /* may be keywords */
5269 node = RNODE_HASH(root_node)->nd_head;
5270 {
5271 int len = 0;
5272 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
5273
5274 if (len > VM_CALL_KW_LEN_MAX) {
5275 COMPILE_ERROR(ERROR_ARGS_AT(root_node) "too many keyword arguments (%d, maximum is %d)",
5276 len, (int)VM_CALL_KW_LEN_MAX);
5277 }
5278
5279 struct rb_callinfo_kwarg *kw_arg =
5280 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
5281 VALUE *keywords = kw_arg->keywords;
5282 int i = 0;
5283 int j = 0;
5284 kw_arg->references = 0;
5285 kw_arg->keyword_len = len;
5286
5287 *kw_arg_ptr = kw_arg;
5288
5289 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5290 const NODE *key_node = RNODE_LIST(node)->nd_head;
5291 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5292 int popped = TRUE;
5293 if (rb_ary_entry(key_index, i)) {
5294 keywords[j] = get_symbol_value(iseq, key_node);
5295 j++;
5296 popped = FALSE;
5297 }
5298 NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
5299 }
5300 RUBY_ASSERT(j == len);
5301 return TRUE;
5302 }
5303 }
5304 return FALSE;
5305}
5306
5307static int
5308compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
5309{
5310 int len = 0;
5311
5312 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
5313 if (CPDEBUG > 0) {
5314 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
5315 }
5316
5317 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
5318 *kwnode_ptr = RNODE_LIST(node)->nd_head;
5319 }
5320 else {
5321 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
5322 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
5323 }
5324 }
5325
5326 return len;
5327}
5328
5329static inline bool
5330frozen_string_literal_p(const rb_iseq_t *iseq)
5331{
5332 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
5333}
5334
5335static inline bool
5336static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
5337{
5338 switch (nd_type(node)) {
5339 case NODE_SYM:
5340 case NODE_REGX:
5341 case NODE_LINE:
5342 case NODE_ENCODING:
5343 case NODE_INTEGER:
5344 case NODE_FLOAT:
5345 case NODE_RATIONAL:
5346 case NODE_IMAGINARY:
5347 case NODE_NIL:
5348 case NODE_TRUE:
5349 case NODE_FALSE:
5350 return TRUE;
5351 case NODE_STR:
5352 case NODE_FILE:
5353 return hash_key || frozen_string_literal_p(iseq);
5354 default:
5355 return FALSE;
5356 }
5357}
5358
5359static inline VALUE
5360static_literal_value(const NODE *node, rb_iseq_t *iseq)
5361{
5362 switch (nd_type(node)) {
5363 case NODE_INTEGER:
5364 {
5365 VALUE lit = rb_node_integer_literal_val(node);
5366 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5367 return lit;
5368 }
5369 case NODE_FLOAT:
5370 {
5371 VALUE lit = rb_node_float_literal_val(node);
5372 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5373 return lit;
5374 }
5375 case NODE_RATIONAL:
5376 return rb_ractor_make_shareable(rb_node_rational_literal_val(node));
5377 case NODE_IMAGINARY:
5378 return rb_ractor_make_shareable(rb_node_imaginary_literal_val(node));
5379 case NODE_NIL:
5380 return Qnil;
5381 case NODE_TRUE:
5382 return Qtrue;
5383 case NODE_FALSE:
5384 return Qfalse;
5385 case NODE_SYM:
5386 return rb_node_sym_string_val(node);
5387 case NODE_REGX:
5388 return RB_OBJ_SET_SHAREABLE(rb_node_regx_string_val(node));
5389 case NODE_LINE:
5390 return rb_node_line_lineno_val(node);
5391 case NODE_ENCODING:
5392 return rb_node_encoding_val(node);
5393 case NODE_FILE:
5394 case NODE_STR:
5395 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
5396 VALUE lit = get_string_value(node);
5397 VALUE str = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
5399 return str;
5400 }
5401 else {
5402 return get_string_value(node);
5403 }
5404 default:
5405 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
5406 }
5407}
5408
5409static int
5410compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
5411{
5412 const NODE *line_node = node;
5413
5414 if (nd_type_p(node, NODE_ZLIST)) {
5415 if (!popped) {
5416 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5417 }
5418 return 0;
5419 }
5420
5421 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5422
5423 if (popped) {
5424 for (; node; node = RNODE_LIST(node)->nd_next) {
5425 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
5426 }
5427 return 1;
5428 }
5429
5430 /* Compilation of an array literal.
5431 * The following code is essentially the same as:
5432 *
5433 * for (int count = 0; node; count++; node->nd_next) {
5434 * compile(node->nd_head);
5435 * }
5436 * ADD_INSN(newarray, count);
5437 *
5438 * However, there are three points.
5439 *
5440 * - The code above causes stack overflow for a big string literal.
5441 * The following limits the stack length up to max_stack_len.
5442 *
5443 * [x1,x2,...,x10000] =>
5444 * push x1 ; push x2 ; ...; push x256; newarray 256;
5445 * push x257; push x258; ...; push x512; pushtoarray 256;
5446 * push x513; push x514; ...; push x768; pushtoarray 256;
5447 * ...
5448 *
5449 * - Long subarray can be optimized by pre-allocating a hidden array.
5450 *
5451 * [1,2,3,...,100] =>
5452 * duparray [1,2,3,...,100]
5453 *
5454 * [x, 1,2,3,...,100, z] =>
5455 * push x; newarray 1;
5456 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5457 * push z; pushtoarray 1;
5458 *
5459 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5460 * to only push it onto the array if it is not empty
5461 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5462 *
5463 * [1,2,3,**kw] =>
5464 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5465 */
5466
5467 const int max_stack_len = 0x100;
5468 const int min_tmp_ary_len = 0x40;
5469 int stack_len = 0;
5470
5471 /* Either create a new array, or push to the existing array */
5472#define FLUSH_CHUNK \
5473 if (stack_len) { \
5474 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5475 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5476 first_chunk = FALSE; \
5477 stack_len = 0; \
5478 }
5479
5480 while (node) {
5481 int count = 1;
5482
5483 /* pre-allocation check (this branch can be omittable) */
5484 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5485 /* count the elements that are optimizable */
5486 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5487 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5488 count++;
5489
5490 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5491 /* The literal contains only optimizable elements, or the subarray is long enough */
5492 VALUE ary = rb_ary_hidden_new(count);
5493
5494 /* Create a hidden array */
5495 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5496 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5498
5499 /* Emit optimized code */
5500 FLUSH_CHUNK;
5501 if (first_chunk) {
5502 ADD_INSN1(ret, line_node, duparray, ary);
5503 first_chunk = FALSE;
5504 }
5505 else {
5506 ADD_INSN1(ret, line_node, putobject, ary);
5507 ADD_INSN(ret, line_node, concattoarray);
5508 }
5510 RB_OBJ_WRITTEN(iseq, Qundef, ary);
5511 }
5512 }
5513
5514 /* Base case: Compile "count" elements */
5515 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5516 if (CPDEBUG > 0) {
5517 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5518 }
5519
5520 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5521 /* Create array or push existing non-keyword elements onto array */
5522 if (stack_len == 0 && first_chunk) {
5523 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5524 }
5525 else {
5526 FLUSH_CHUNK;
5527 }
5528 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5529 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5530 return 1;
5531 }
5532 else {
5533 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5534 stack_len++;
5535 }
5536
5537 /* If there are many pushed elements, flush them to avoid stack overflow */
5538 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5539 }
5540 }
5541
5542 FLUSH_CHUNK;
5543#undef FLUSH_CHUNK
5544 return 1;
5545}
5546
5547static inline int
5548static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5549{
5550 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);
5551}
5552
5553static int
5554compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5555{
5556 const NODE *line_node = node;
5557
5558 node = RNODE_HASH(node)->nd_head;
5559
5560 if (!node || nd_type_p(node, NODE_ZLIST)) {
5561 if (!popped) {
5562 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5563 }
5564 return 0;
5565 }
5566
5567 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5568
5569 if (popped) {
5570 for (; node; node = RNODE_LIST(node)->nd_next) {
5571 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5572 }
5573 return 1;
5574 }
5575
5576 /* Compilation of a hash literal (or keyword arguments).
5577 * This is very similar to compile_array, but there are some differences:
5578 *
5579 * - It contains key-value pairs. So we need to take every two elements.
5580 * We can assume that the length is always even.
5581 *
5582 * - Merging is done by a method call (id_core_hash_merge_bang_ptr).
5583 * Sometimes we need to insert the receiver, so "anchor" is needed.
5584 * In addition, a method call is much slower than concatarray.
5585 * So it pays only when the subsequence is really long.
5586 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5587 *
5588 * - We need to handle keyword splat: **kw.
5589 * For **kw, the key part (node->nd_head) is NULL, and the value part
5590 * (node->nd_next->nd_head) is "kw".
5591 * The code is a bit difficult to avoid hash allocation for **{}.
5592 */
5593
5594 const int max_stack_len = 0x100;
5595 const int min_tmp_hash_len = 0x800;
5596 int stack_len = 0;
5597 int first_chunk = 1;
5598 DECL_ANCHOR(anchor);
5599 INIT_ANCHOR(anchor);
5600
5601 /* Convert pushed elements to a hash, and merge if needed */
5602#define FLUSH_CHUNK() \
5603 if (stack_len) { \
5604 if (first_chunk) { \
5605 APPEND_LIST(ret, anchor); \
5606 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5607 } \
5608 else { \
5609 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5610 ADD_INSN(ret, line_node, swap); \
5611 APPEND_LIST(ret, anchor); \
5612 ADD_SEND(ret, line_node, id_core_hash_merge_bang_ptr, INT2FIX(stack_len + 1)); \
5613 } \
5614 INIT_ANCHOR(anchor); \
5615 first_chunk = stack_len = 0; \
5616 }
5617
5618 while (node) {
5619 int count = 1;
5620
5621 /* pre-allocation check (this branch can be omittable) */
5622 if (static_literal_node_pair_p(node, iseq)) {
5623 /* count the elements that are optimizable */
5624 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5625 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5626 count++;
5627
5628 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5629 /* The literal contains only optimizable elements, or the subsequence is long enough */
5630 VALUE ary = rb_ary_hidden_new(count);
5631
5632 /* Create a hidden hash */
5633 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5634 VALUE elem[2];
5635 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5636 if (!RB_SPECIAL_CONST_P(elem[0])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[0]);
5637 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5638 if (!RB_SPECIAL_CONST_P(elem[1])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[1]);
5639 rb_ary_cat(ary, elem, 2);
5640 }
5641 VALUE hash = rb_hash_alloc_fixed_size(Qfalse, RARRAY_LEN(ary) / 2);
5642 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
5643 RB_GC_GUARD(ary);
5644 hash = RB_OBJ_SET_FROZEN_SHAREABLE(hash);
5645
5646 /* Emit optimized code */
5647 FLUSH_CHUNK();
5648 if (first_chunk) {
5649 ADD_INSN1(ret, line_node, duphash, hash);
5650 first_chunk = 0;
5651 }
5652 else {
5653 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5654 ADD_INSN(ret, line_node, swap);
5655
5656 ADD_INSN1(ret, line_node, putobject, hash);
5657
5658 ADD_SEND(ret, line_node, id_core_hash_merge_bang_kwd, INT2FIX(2));
5659 }
5660 RB_OBJ_WRITTEN(iseq, Qundef, hash);
5661 }
5662 }
5663
5664 /* Base case: Compile "count" elements */
5665 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5666
5667 if (CPDEBUG > 0) {
5668 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5669 }
5670
5671 if (RNODE_LIST(node)->nd_head) {
5672 /* Normal key-value pair */
5673 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5674 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5675 stack_len += 2;
5676
5677 /* If there are many pushed elements, flush them to avoid stack overflow */
5678 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5679 }
5680 else {
5681 /* kwsplat case: foo(..., **kw, ...) */
5682 FLUSH_CHUNK();
5683
5684 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5685 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5686 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5687 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5688 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5689
5690 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5691 if (empty_kw) {
5692 if (only_kw && method_call_keywords) {
5693 /* **{} appears at the only keyword argument in method call,
5694 * so it won't be modified.
5695 * kw is a special NODE_LIT that contains a special empty hash,
5696 * so this emits: putobject {}.
5697 * This is only done for method calls and not for literal hashes,
5698 * because literal hashes should always result in a new hash.
5699 */
5700 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5701 }
5702 else if (first_kw) {
5703 /* **{} appears as the first keyword argument, so it may be modified.
5704 * We need to create a fresh hash object.
5705 */
5706 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5707 }
5708 /* Any empty keyword splats that are not the first can be ignored.
5709 * since merging an empty hash into the existing hash is the same
5710 * as not merging it. */
5711 }
5712 else {
5713 if (only_kw && method_call_keywords) {
5714 /* **kw is only keyword argument in method call.
5715 * Use directly. This will be not be flagged as mutable.
5716 * This is only done for method calls and not for literal hashes,
5717 * because literal hashes should always result in a new hash.
5718 */
5719 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5720 }
5721 else {
5722 /* There is more than one keyword argument, or this is not a method
5723 * call. In that case, we need to add an empty hash (if first keyword),
5724 * or merge the hash to the accumulated hash (if not the first keyword).
5725 */
5726 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5727 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5728 else ADD_INSN(ret, line_node, swap);
5729
5730 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5731
5732 ADD_SEND(ret, line_node, id_core_hash_merge_bang_kwd, INT2FIX(2));
5733 }
5734 }
5735
5736 first_chunk = 0;
5737 }
5738 }
5739 }
5740
5741 FLUSH_CHUNK();
5742#undef FLUSH_CHUNK
5743 return 1;
5744}
5745
5746static VALUE
5747rb_node_case_when_optimizable_literal(const NODE *const node)
5748{
5749 switch (nd_type(node)) {
5750 case NODE_INTEGER:
5751 return rb_node_integer_literal_val(node);
5752 case NODE_FLOAT: {
5753 VALUE v = rb_node_float_literal_val(node);
5754 double ival;
5755
5756 if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5757 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5758 }
5759 return v;
5760 }
5761 case NODE_RATIONAL:
5762 case NODE_IMAGINARY:
5763 return Qundef;
5764 case NODE_NIL:
5765 return Qnil;
5766 case NODE_TRUE:
5767 return Qtrue;
5768 case NODE_FALSE:
5769 return Qfalse;
5770 case NODE_SYM:
5771 return rb_node_sym_string_val(node);
5772 case NODE_LINE:
5773 return rb_node_line_lineno_val(node);
5774 case NODE_STR:
5775 return rb_node_str_string_val(node);
5776 case NODE_FILE:
5777 return rb_node_file_path_val(node);
5778 }
5779 return Qundef;
5780}
5781
5782static int
5783when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5784 LABEL *l1, int only_special_literals, VALUE literals)
5785{
5786 while (vals) {
5787 const NODE *val = RNODE_LIST(vals)->nd_head;
5788 VALUE lit = rb_node_case_when_optimizable_literal(val);
5789
5790 if (UNDEF_P(lit)) {
5791 only_special_literals = 0;
5792 }
5793 else {
5794 cdhash_aset_if_missing(literals, lit, (VALUE)(l1));
5795 }
5796
5797 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5798 debugp_param("nd_lit", get_string_value(val));
5799 lit = get_string_value(val);
5800 ADD_INSN1(cond_seq, val, putobject, lit);
5801 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5802 }
5803 else {
5804 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5805 }
5806
5807 // Emit pattern === target
5808 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5809 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5810 ADD_INSNL(cond_seq, val, branchif, l1);
5811 vals = RNODE_LIST(vals)->nd_next;
5812 }
5813 return only_special_literals;
5814}
5815
5816static int
5817when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5818 LABEL *l1, int only_special_literals, VALUE literals)
5819{
5820 const NODE *line_node = vals;
5821
5822 switch (nd_type(vals)) {
5823 case NODE_LIST:
5824 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5825 return COMPILE_NG;
5826 break;
5827 case NODE_SPLAT:
5828 ADD_INSN (cond_seq, line_node, dup);
5829 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5830 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5831 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5832 ADD_INSNL(cond_seq, line_node, branchif, l1);
5833 break;
5834 case NODE_ARGSCAT:
5835 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5836 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5837 break;
5838 case NODE_ARGSPUSH:
5839 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5840 ADD_INSN (cond_seq, line_node, dup);
5841 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5842 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5843 ADD_INSNL(cond_seq, line_node, branchif, l1);
5844 break;
5845 default:
5846 ADD_INSN (cond_seq, line_node, dup);
5847 CHECK(COMPILE(cond_seq, "when val", vals));
5848 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5849 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5850 ADD_INSNL(cond_seq, line_node, branchif, l1);
5851 break;
5852 }
5853 return COMPILE_OK;
5854}
5855
5856/* Multiple Assignment Handling
5857 *
5858 * In order to handle evaluation of multiple assignment such that the left hand side
5859 * is evaluated before the right hand side, we need to process the left hand side
5860 * and see if there are any attributes that need to be assigned, or constants set
5861 * on explicit objects. If so, we add instructions to evaluate the receiver of
5862 * any assigned attributes or constants before we process the right hand side.
5863 *
5864 * For a multiple assignment such as:
5865 *
5866 * l1.m1, l2[0] = r3, r4
5867 *
5868 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5869 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5870 * On the VM stack, this looks like:
5871 *
5872 * self # putself
5873 * l1 # send
5874 * l1, self # putself
5875 * l1, l2 # send
5876 * l1, l2, 0 # putobject 0
5877 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5878 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5879 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5880 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5881 * l1, l2, 0, [r3, r4], r4, m1= # send
5882 * l1, l2, 0, [r3, r4], r4 # pop
5883 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5884 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5885 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5886 * l1, l2, 0, [r3, r4], r4, []= # send
5887 * l1, l2, 0, [r3, r4], r4 # pop
5888 * l1, l2, 0, [r3, r4] # pop
5889 * [r3, r4], l2, 0, [r3, r4] # setn 3
5890 * [r3, r4], l2, 0 # pop
5891 * [r3, r4], l2 # pop
5892 * [r3, r4] # pop
5893 *
5894 * This is made more complex when you have to handle splats, post args,
5895 * and arbitrary levels of nesting. You need to keep track of the total
5896 * number of attributes to set, and for each attribute, how many entries
5897 * are on the stack before the final attribute, in order to correctly
5898 * calculate the topn value to use to get the receiver of the attribute
5899 * setter method.
5900 *
5901 * A brief description of the VM stack for simple multiple assignment
5902 * with no splat (rhs_array will not be present if the return value of
5903 * the multiple assignment is not needed):
5904 *
5905 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5906 *
5907 * For multiple assignment with splats, while processing the part before
5908 * the splat (splat+post here is an array of the splat and the post arguments):
5909 *
5910 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5911 *
5912 * When processing the splat and post arguments:
5913 *
5914 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5915 *
5916 * When processing nested multiple assignment, existing values on the stack
5917 * are kept. So for:
5918 *
5919 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5920 *
5921 * The stack layout would be the following before processing the nested
5922 * multiple assignment:
5923 *
5924 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5925 *
5926 * In order to handle this correctly, we need to keep track of the nesting
5927 * level for each attribute assignment, as well as the attribute number
5928 * (left hand side attributes are processed left to right) and number of
5929 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5930 * this information.
5931 *
5932 * We also need to track information for the entire multiple assignment, such
5933 * as the total number of arguments, and the current nesting level, to
5934 * handle both nested multiple assignment as well as cases where the
5935 * rhs is not needed. We also need to keep track of all attribute
5936 * assignments in this, which we do using a linked listed. struct masgn_state
5937 * tracks this information.
5938 */
5939
5941 INSN *before_insn;
5942 struct masgn_lhs_node *next;
5943 const NODE *line_node;
5944 int argn;
5945 int num_args;
5946 int lhs_pos;
5947};
5948
5950 struct masgn_lhs_node *first_memo;
5951 struct masgn_lhs_node *last_memo;
5952 int lhs_level;
5953 int num_args;
5954 bool nested;
5955};
5956
5957static int
5958add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5959{
5960 if (!state) {
5961 rb_bug("no masgn_state");
5962 }
5963
5964 struct masgn_lhs_node *memo;
5965 memo = malloc(sizeof(struct masgn_lhs_node));
5966 if (!memo) {
5967 return COMPILE_NG;
5968 }
5969
5970 memo->before_insn = before_insn;
5971 memo->line_node = line_node;
5972 memo->argn = state->num_args + 1;
5973 memo->num_args = argc;
5974 state->num_args += argc;
5975 memo->lhs_pos = lhs_pos;
5976 memo->next = NULL;
5977 if (!state->first_memo) {
5978 state->first_memo = memo;
5979 }
5980 else {
5981 state->last_memo->next = memo;
5982 }
5983 state->last_memo = memo;
5984
5985 return COMPILE_OK;
5986}
5987
5988static 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);
5989
5990static int
5991compile_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)
5992{
5993 switch (nd_type(node)) {
5994 case NODE_ATTRASGN: {
5995 INSN *iobj;
5996 const NODE *line_node = node;
5997
5998 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5999
6000 bool safenav_call = false;
6001 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
6002 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
6003 ASSUME(iobj);
6004 ELEM_REMOVE(insn_element);
6005 if (!IS_INSN_ID(iobj, send)) {
6006 safenav_call = true;
6007 iobj = (INSN *)get_prev_insn(iobj);
6008 ELEM_INSERT_NEXT(&iobj->link, insn_element);
6009 }
6010 (pre->last = iobj->link.prev)->next = 0;
6011
6012 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
6013 int argc = vm_ci_argc(ci) + 1;
6014 ci = ci_argc_set(iseq, ci, argc);
6015 OPERAND_AT(iobj, 0) = (VALUE)ci;
6016 RB_OBJ_WRITTEN(iseq, Qundef, ci);
6017
6018 if (argc == 1) {
6019 ADD_INSN(lhs, line_node, swap);
6020 }
6021 else {
6022 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
6023 }
6024
6025 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
6026 return COMPILE_NG;
6027 }
6028
6029 iobj->link.prev = lhs->last;
6030 lhs->last->next = &iobj->link;
6031 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
6032 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
6033 int argc = vm_ci_argc(ci);
6034 bool dupsplat = false;
6035 ci = ci_argc_set(iseq, ci, argc - 1);
6036 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
6037 /* Given h[*a], _ = ary
6038 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
6039 * `a` must be dupped, because it will be appended with ary[0]
6040 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
6041 */
6042 dupsplat = true;
6043 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
6044 }
6045 OPERAND_AT(iobj, 0) = (VALUE)ci;
6046 RB_OBJ_WRITTEN(iseq, Qundef, ci);
6047
6048 /* Given: h[*a], h[*b, 1] = ary
6049 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
6050 * so this uses splatarray true on a to dup it before using pushtoarray
6051 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
6052 * so you can use pushtoarray directly
6053 */
6054 int line_no = nd_line(line_node);
6055 int node_id = nd_node_id(line_node);
6056
6057 if (dupsplat) {
6058 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
6059 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
6060 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
6061 }
6062 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
6063 }
6064 if (!safenav_call) {
6065 ADD_INSN(lhs, line_node, pop);
6066 if (argc != 1) {
6067 ADD_INSN(lhs, line_node, pop);
6068 }
6069 }
6070 for (int i=0; i < argc; i++) {
6071 ADD_INSN(post, line_node, pop);
6072 }
6073 break;
6074 }
6075 case NODE_MASGN: {
6076 DECL_ANCHOR(nest_rhs);
6077 INIT_ANCHOR(nest_rhs);
6078 DECL_ANCHOR(nest_lhs);
6079 INIT_ANCHOR(nest_lhs);
6080
6081 int prev_level = state->lhs_level;
6082 bool prev_nested = state->nested;
6083 state->nested = 1;
6084 state->lhs_level = lhs_pos - 1;
6085 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
6086 state->lhs_level = prev_level;
6087 state->nested = prev_nested;
6088
6089 ADD_SEQ(lhs, nest_rhs);
6090 ADD_SEQ(lhs, nest_lhs);
6091 break;
6092 }
6093 case NODE_CDECL:
6094 if (!RNODE_CDECL(node)->nd_vid) {
6095 /* Special handling only needed for expr::C, not for C */
6096 INSN *iobj;
6097
6098 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
6099
6100 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
6101 iobj = (INSN *)insn_element; /* setconstant insn */
6102 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
6103 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
6104 ELEM_REMOVE(insn_element);
6105 pre->last = iobj->link.prev;
6106 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
6107
6108 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
6109 return COMPILE_NG;
6110 }
6111
6112 ADD_INSN(post, node, pop);
6113 break;
6114 }
6115 /* Fallthrough */
6116 default: {
6117 DECL_ANCHOR(anchor);
6118 INIT_ANCHOR(anchor);
6119 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
6120 ELEM_REMOVE(FIRST_ELEMENT(anchor));
6121 ADD_SEQ(lhs, anchor);
6122 }
6123 }
6124
6125 return COMPILE_OK;
6126}
6127
6128static int
6129compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
6130{
6131 if (lhsn) {
6132 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
6133 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
6134 }
6135 return COMPILE_OK;
6136}
6137
6138static int
6139compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6140 const NODE *rhsn, const NODE *orig_lhsn)
6141{
6142 VALUE mem[64];
6143 const int memsize = numberof(mem);
6144 int memindex = 0;
6145 int llen = 0, rlen = 0;
6146 int i;
6147 const NODE *lhsn = orig_lhsn;
6148
6149#define MEMORY(v) { \
6150 int i; \
6151 if (memindex == memsize) return 0; \
6152 for (i=0; i<memindex; i++) { \
6153 if (mem[i] == (v)) return 0; \
6154 } \
6155 mem[memindex++] = (v); \
6156}
6157
6158 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
6159 return 0;
6160 }
6161
6162 while (lhsn) {
6163 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
6164 switch (nd_type(ln)) {
6165 case NODE_LASGN:
6166 case NODE_DASGN:
6167 case NODE_IASGN:
6168 case NODE_CVASGN:
6169 MEMORY(get_nd_vid(ln));
6170 break;
6171 default:
6172 return 0;
6173 }
6174 lhsn = RNODE_LIST(lhsn)->nd_next;
6175 llen++;
6176 }
6177
6178 while (rhsn) {
6179 if (llen <= rlen) {
6180 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
6181 }
6182 else {
6183 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
6184 }
6185 rhsn = RNODE_LIST(rhsn)->nd_next;
6186 rlen++;
6187 }
6188
6189 if (llen > rlen) {
6190 for (i=0; i<llen-rlen; i++) {
6191 ADD_INSN(ret, orig_lhsn, putnil);
6192 }
6193 }
6194
6195 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
6196 return 1;
6197}
6198
6199static int
6200compile_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)
6201{
6202 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
6203 const NODE *splatn = RNODE_MASGN(node)->nd_args;
6204 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
6205 const NODE *lhsn_count = lhsn;
6206 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
6207
6208 int llen = 0;
6209 int lpos = 0;
6210
6211 while (lhsn_count) {
6212 llen++;
6213 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
6214 }
6215 while (lhsn) {
6216 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
6217 lpos++;
6218 lhsn = RNODE_LIST(lhsn)->nd_next;
6219 }
6220
6221 if (lhs_splat) {
6222 if (nd_type_p(splatn, NODE_POSTARG)) {
6223 /*a, b, *r, p1, p2 */
6224 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
6225 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
6226 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
6227 int ppos = 0;
6228 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
6229
6230 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
6231
6232 if (NODE_NAMED_REST_P(restn)) {
6233 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
6234 }
6235 while (postn) {
6236 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
6237 ppos++;
6238 postn = RNODE_LIST(postn)->nd_next;
6239 }
6240 }
6241 else {
6242 /* a, b, *r */
6243 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
6244 }
6245 }
6246
6247 if (!state->nested) {
6248 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
6249 }
6250
6251 if (!popped) {
6252 ADD_INSN(rhs, node, dup);
6253 }
6254 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
6255 return COMPILE_OK;
6256}
6257
6258static int
6259compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6260{
6261 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
6262 struct masgn_state state;
6263 state.lhs_level = popped ? 0 : 1;
6264 state.nested = 0;
6265 state.num_args = 0;
6266 state.first_memo = NULL;
6267 state.last_memo = NULL;
6268
6269 DECL_ANCHOR(pre);
6270 INIT_ANCHOR(pre);
6271 DECL_ANCHOR(rhs);
6272 INIT_ANCHOR(rhs);
6273 DECL_ANCHOR(lhs);
6274 INIT_ANCHOR(lhs);
6275 DECL_ANCHOR(post);
6276 INIT_ANCHOR(post);
6277 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
6278
6279 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
6280 while (memo) {
6281 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
6282 for (int i = 0; i < memo->num_args; i++) {
6283 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
6284 }
6285 tmp_memo = memo->next;
6286 free(memo);
6287 memo = tmp_memo;
6288 }
6289 CHECK(ok);
6290
6291 ADD_SEQ(ret, pre);
6292 ADD_SEQ(ret, rhs);
6293 ADD_SEQ(ret, lhs);
6294 if (!popped && state.num_args >= 1) {
6295 /* make sure rhs array is returned before popping */
6296 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
6297 }
6298 ADD_SEQ(ret, post);
6299 }
6300 return COMPILE_OK;
6301}
6302
6303static VALUE
6304collect_const_segments(rb_iseq_t *iseq, const NODE *node)
6305{
6306 VALUE arr = rb_ary_new();
6307 for (;;) {
6308 switch (nd_type(node)) {
6309 case NODE_CONST:
6310 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
6312 return arr;
6313 case NODE_COLON3:
6314 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
6315 rb_ary_unshift(arr, ID2SYM(idNULL));
6317 return arr;
6318 case NODE_COLON2:
6319 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
6320 node = RNODE_COLON2(node)->nd_head;
6321 break;
6322 default:
6323 return Qfalse;
6324 }
6325 }
6326}
6327
6328static int
6329compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
6330 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
6331{
6332 switch (nd_type(node)) {
6333 case NODE_CONST:
6334 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
6335 ADD_INSN1(body, node, putobject, Qtrue);
6336 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
6337 break;
6338 case NODE_COLON3:
6339 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
6340 ADD_INSN(body, node, pop);
6341 ADD_INSN1(body, node, putobject, rb_cObject);
6342 ADD_INSN1(body, node, putobject, Qtrue);
6343 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
6344 break;
6345 case NODE_COLON2:
6346 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
6347 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
6348 ADD_INSN1(body, node, putobject, Qfalse);
6349 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
6350 break;
6351 default:
6352 CHECK(COMPILE(pref, "const colon2 prefix", node));
6353 break;
6354 }
6355 return COMPILE_OK;
6356}
6357
6358static int
6359cpath_const_p(const NODE *node)
6360{
6361 switch (nd_type(node)) {
6362 case NODE_CONST:
6363 case NODE_COLON3:
6364 return TRUE;
6365 case NODE_COLON2:
6366 if (RNODE_COLON2(node)->nd_head) {
6367 return cpath_const_p(RNODE_COLON2(node)->nd_head);
6368 }
6369 return TRUE;
6370 default:
6371 return FALSE;
6372 }
6373}
6374
6375static int
6376compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
6377{
6378 if (nd_type_p(cpath, NODE_COLON3)) {
6379 /* toplevel class ::Foo */
6380 ADD_INSN1(ret, cpath, putobject, rb_cObject);
6381 return VM_DEFINECLASS_FLAG_SCOPED;
6382 }
6383 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
6384 /* Bar::Foo or expr::Foo */
6385 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
6386 int flags = VM_DEFINECLASS_FLAG_SCOPED;
6387 if (!cpath_const_p(RNODE_COLON2(cpath)->nd_head)) {
6388 flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF;
6389 }
6390 return flags;
6391 }
6392 else {
6393 /* class at cbase Foo */
6394 ADD_INSN1(ret, cpath, putspecialobject,
6395 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
6396 return 0;
6397 }
6398}
6399
6400static inline int
6401private_recv_p(const NODE *node)
6402{
6403 NODE *recv = get_nd_recv(node);
6404 if (recv && nd_type_p(recv, NODE_SELF)) {
6405 return RNODE_SELF(recv)->nd_state != 0;
6406 }
6407 return 0;
6408}
6409
6410static void
6411defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6412 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
6413
6414static int
6415compile_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);
6416
6417static void
6418defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6419 const NODE *const node, LABEL **lfinish, VALUE needstr,
6420 bool keep_result)
6421{
6422 enum defined_type expr_type = DEFINED_NOT_DEFINED;
6423 enum node_type type;
6424 const int line = nd_line(node);
6425 const NODE *line_node = node;
6426
6427 switch (type = nd_type(node)) {
6428
6429 /* easy literals */
6430 case NODE_NIL:
6431 expr_type = DEFINED_NIL;
6432 break;
6433 case NODE_SELF:
6434 expr_type = DEFINED_SELF;
6435 break;
6436 case NODE_TRUE:
6437 expr_type = DEFINED_TRUE;
6438 break;
6439 case NODE_FALSE:
6440 expr_type = DEFINED_FALSE;
6441 break;
6442
6443 case NODE_HASH:
6444 case NODE_LIST:{
6445 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6446
6447 if (vals) {
6448 do {
6449 if (RNODE_LIST(vals)->nd_head) {
6450 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
6451
6452 if (!lfinish[1]) {
6453 lfinish[1] = NEW_LABEL(line);
6454 }
6455 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6456 }
6457 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6458 }
6459 }
6460 /* fall through */
6461 case NODE_STR:
6462 case NODE_SYM:
6463 case NODE_REGX:
6464 case NODE_LINE:
6465 case NODE_FILE:
6466 case NODE_ENCODING:
6467 case NODE_INTEGER:
6468 case NODE_FLOAT:
6469 case NODE_RATIONAL:
6470 case NODE_IMAGINARY:
6471 case NODE_ZLIST:
6472 case NODE_AND:
6473 case NODE_OR:
6474 default:
6475 expr_type = DEFINED_EXPR;
6476 break;
6477
6478 case NODE_SPLAT:
6479 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6480 if (!lfinish[1]) {
6481 lfinish[1] = NEW_LABEL(line);
6482 }
6483 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6484 expr_type = DEFINED_EXPR;
6485 break;
6486
6487 /* variables */
6488 case NODE_LVAR:
6489 case NODE_DVAR:
6490 expr_type = DEFINED_LVAR;
6491 break;
6492
6493#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6494 case NODE_IVAR:
6495 ADD_INSN3(ret, line_node, definedivar,
6496 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6497 return;
6498
6499 case NODE_GVAR:
6500 ADD_INSN(ret, line_node, putnil);
6501 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6502 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6503 return;
6504
6505 case NODE_CVAR:
6506 ADD_INSN(ret, line_node, putnil);
6507 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6508 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6509 return;
6510
6511 case NODE_CONST:
6512 ADD_INSN(ret, line_node, putnil);
6513 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6514 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6515 return;
6516 case NODE_COLON2:
6517 if (!lfinish[1]) {
6518 lfinish[1] = NEW_LABEL(line);
6519 }
6520 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6521 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6522 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6523
6524 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6525 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6526 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6527 }
6528 else {
6529 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6530 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6531 }
6532 return;
6533 case NODE_COLON3:
6534 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6535 ADD_INSN3(ret, line_node, defined,
6536 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6537 return;
6538
6539 /* method dispatch */
6540 case NODE_CALL:
6541 case NODE_OPCALL:
6542 case NODE_VCALL:
6543 case NODE_FCALL:
6544 case NODE_ATTRASGN:{
6545 const int explicit_receiver =
6546 (type == NODE_CALL || type == NODE_OPCALL ||
6547 (type == NODE_ATTRASGN && !private_recv_p(node)));
6548
6549 if (get_nd_args(node) || explicit_receiver) {
6550 if (!lfinish[1]) {
6551 lfinish[1] = NEW_LABEL(line);
6552 }
6553 if (!lfinish[2]) {
6554 lfinish[2] = NEW_LABEL(line);
6555 }
6556 }
6557 if (get_nd_args(node)) {
6558 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6559 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6560 }
6561 if (explicit_receiver) {
6562 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6563 switch (nd_type(get_nd_recv(node))) {
6564 case NODE_CALL:
6565 case NODE_OPCALL:
6566 case NODE_VCALL:
6567 case NODE_FCALL:
6568 case NODE_ATTRASGN:
6569 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6570 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6571 break;
6572 default:
6573 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6574 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6575 break;
6576 }
6577 if (keep_result) {
6578 ADD_INSN(ret, line_node, dup);
6579 }
6580 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6581 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6582 }
6583 else {
6584 ADD_INSN(ret, line_node, putself);
6585 if (keep_result) {
6586 ADD_INSN(ret, line_node, dup);
6587 }
6588 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6589 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6590 }
6591 return;
6592 }
6593
6594 case NODE_YIELD:
6595 ADD_INSN(ret, line_node, putnil);
6596 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6597 PUSH_VAL(DEFINED_YIELD));
6598 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6599 return;
6600
6601 case NODE_BACK_REF:
6602 case NODE_NTH_REF:
6603 ADD_INSN(ret, line_node, putnil);
6604 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6605 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6606 PUSH_VAL(DEFINED_GVAR));
6607 return;
6608
6609 case NODE_SUPER:
6610 case NODE_ZSUPER:
6611 ADD_INSN(ret, line_node, putnil);
6612 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6613 PUSH_VAL(DEFINED_ZSUPER));
6614 return;
6615
6616#undef PUSH_VAL
6617 case NODE_OP_ASGN1:
6618 case NODE_OP_ASGN2:
6619 case NODE_OP_ASGN_OR:
6620 case NODE_OP_ASGN_AND:
6621 case NODE_MASGN:
6622 case NODE_LASGN:
6623 case NODE_DASGN:
6624 case NODE_GASGN:
6625 case NODE_IASGN:
6626 case NODE_CDECL:
6627 case NODE_CVASGN:
6628 case NODE_OP_CDECL:
6629 expr_type = DEFINED_ASGN;
6630 break;
6631 }
6632
6633 RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6634
6635 if (needstr != Qfalse) {
6636 VALUE str = rb_iseq_defined_string(expr_type);
6637 ADD_INSN1(ret, line_node, putobject, str);
6638 }
6639 else {
6640 ADD_INSN1(ret, line_node, putobject, Qtrue);
6641 }
6642}
6643
6644static void
6645build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6646{
6647 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6648 iseq_set_exception_local_table(iseq);
6649}
6650
6651static void
6652defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6653 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6654{
6655 LINK_ELEMENT *lcur = ret->last;
6656 defined_expr0(iseq, ret, node, lfinish, needstr, false);
6657 if (lfinish[1]) {
6658 int line = nd_line(node);
6659 LABEL *lstart = NEW_LABEL(line);
6660 LABEL *lend = NEW_LABEL(line);
6661 const rb_iseq_t *rescue;
6663 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6664 rescue = NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc,
6665 rb_str_concat(rb_str_new2("defined guard in "),
6666 ISEQ_BODY(iseq)->location.label),
6667 ISEQ_TYPE_RESCUE, 0);
6668 lstart->rescued = LABEL_RESCUE_BEG;
6669 lend->rescued = LABEL_RESCUE_END;
6670 APPEND_LABEL(ret, lcur, lstart);
6671 ADD_LABEL(ret, lend);
6672 if (!ignore) {
6673 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6674 }
6675 }
6676}
6677
6678static int
6679compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6680{
6681 const int line = nd_line(node);
6682 const NODE *line_node = node;
6683 if (!RNODE_DEFINED(node)->nd_head) {
6684 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6685 ADD_INSN1(ret, line_node, putobject, str);
6686 }
6687 else {
6688 LABEL *lfinish[3];
6689 LINK_ELEMENT *last = ret->last;
6690 lfinish[0] = NEW_LABEL(line);
6691 lfinish[1] = 0;
6692 lfinish[2] = 0;
6693 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6694 if (lfinish[1]) {
6695 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6696 ADD_INSN(ret, line_node, swap);
6697 if (lfinish[2]) {
6698 ADD_LABEL(ret, lfinish[2]);
6699 }
6700 ADD_INSN(ret, line_node, pop);
6701 ADD_LABEL(ret, lfinish[1]);
6702 }
6703 ADD_LABEL(ret, lfinish[0]);
6704 }
6705 return COMPILE_OK;
6706}
6707
6708static VALUE
6709make_name_for_block(const rb_iseq_t *orig_iseq)
6710{
6711 int level = 1;
6712 const rb_iseq_t *iseq = orig_iseq;
6713
6714 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6715 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6716 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6717 level++;
6718 }
6719 iseq = ISEQ_BODY(iseq)->parent_iseq;
6720 }
6721 }
6722
6723 if (level == 1) {
6724 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6725 }
6726 else {
6727 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6728 }
6729}
6730
6731static void
6732push_ensure_entry(rb_iseq_t *iseq,
6734 struct ensure_range *er, const void *const node)
6735{
6736 enl->ensure_node = node;
6737 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6738 enl->erange = er;
6739 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6740}
6741
6742static void
6743add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6744 LABEL *lstart, LABEL *lend)
6745{
6746 struct ensure_range *ne =
6747 compile_data_alloc_type(iseq, struct ensure_range);
6748
6749 while (erange->next != 0) {
6750 erange = erange->next;
6751 }
6752 ne->next = 0;
6753 ne->begin = lend;
6754 ne->end = erange->end;
6755 erange->end = lstart;
6756
6757 erange->next = ne;
6758}
6759
6760static bool
6761can_add_ensure_iseq(const rb_iseq_t *iseq)
6762{
6764 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6765 while (e) {
6766 if (e->ensure_node) return false;
6767 e = e->prev;
6768 }
6769 }
6770 return true;
6771}
6772
6773static void
6774add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6775{
6776 RUBY_ASSERT(can_add_ensure_iseq(iseq));
6777
6779 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6780 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6781 DECL_ANCHOR(ensure);
6782
6783 INIT_ANCHOR(ensure);
6784 while (enlp) {
6785 if (enlp->erange != NULL) {
6786 DECL_ANCHOR(ensure_part);
6787 LABEL *lstart = NEW_LABEL(0);
6788 LABEL *lend = NEW_LABEL(0);
6789 INIT_ANCHOR(ensure_part);
6790
6791 add_ensure_range(iseq, enlp->erange, lstart, lend);
6792
6793 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6794 ADD_LABEL(ensure_part, lstart);
6795 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6796 ADD_LABEL(ensure_part, lend);
6797 ADD_SEQ(ensure, ensure_part);
6798 }
6799 else {
6800 if (!is_return) {
6801 break;
6802 }
6803 }
6804 enlp = enlp->prev;
6805 }
6806 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6807 ADD_SEQ(ret, ensure);
6808}
6809
6810#if RUBY_DEBUG
6811static int
6812check_keyword(const NODE *node)
6813{
6814 /* This check is essentially a code clone of compile_keyword_arg. */
6815
6816 if (nd_type_p(node, NODE_LIST)) {
6817 while (RNODE_LIST(node)->nd_next) {
6818 node = RNODE_LIST(node)->nd_next;
6819 }
6820 node = RNODE_LIST(node)->nd_head;
6821 }
6822
6823 return keyword_node_p(node);
6824}
6825#endif
6826
6827static bool
6828keyword_node_single_splat_p(NODE *kwnode)
6829{
6830 RUBY_ASSERT(keyword_node_p(kwnode));
6831
6832 NODE *node = RNODE_HASH(kwnode)->nd_head;
6833 return RNODE_LIST(node)->nd_head == NULL &&
6834 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6835}
6836
6837static void
6838compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6839 NODE *kwnode, unsigned int *flag_ptr)
6840{
6841 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6842 ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6843 ADD_INSN1(args, argn, newhash, INT2FIX(0));
6844 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6845 ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6846}
6847
6848#define SPLATARRAY_FALSE 0
6849#define SPLATARRAY_TRUE 1
6850#define DUP_SINGLE_KW_SPLAT 2
6851
6852static int
6853setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6854 unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6855{
6856 if (!argn) return 0;
6857
6858 NODE *kwnode = NULL;
6859
6860 switch (nd_type(argn)) {
6861 case NODE_LIST: {
6862 // f(x, y, z)
6863 int len = compile_args(iseq, args, argn, &kwnode);
6864 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6865
6866 if (kwnode) {
6867 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6868 len -= 1;
6869 }
6870 else {
6871 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6872 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6873 }
6874 else {
6875 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6876 }
6877 }
6878 }
6879
6880 return len;
6881 }
6882 case NODE_SPLAT: {
6883 // f(*a)
6884 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6885 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6886 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6887 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6888 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6889 return 1;
6890 }
6891 case NODE_ARGSCAT: {
6892 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6893 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6894 bool args_pushed = false;
6895
6896 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6897 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6898 if (kwnode) rest_len--;
6899 ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6900 args_pushed = true;
6901 }
6902 else {
6903 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6904 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6905 }
6906
6907 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6908 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6909 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6910 argc += 1;
6911 }
6912 else if (!args_pushed) {
6913 ADD_INSN(args, argn, concattoarray);
6914 }
6915
6916 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6917 if (kwnode) {
6918 // kwsplat
6919 *flag_ptr |= VM_CALL_KW_SPLAT;
6920 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6921 argc += 1;
6922 }
6923
6924 return argc;
6925 }
6926 case NODE_ARGSPUSH: {
6927 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6928 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6929
6930 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6931 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6932 if (kwnode) rest_len--;
6933 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6934 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6935 }
6936 else {
6937 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6938 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6939 }
6940 else {
6941 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6942 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6943 }
6944 }
6945
6946 if (kwnode) {
6947 // f(*a, k:1)
6948 *flag_ptr |= VM_CALL_KW_SPLAT;
6949 if (!keyword_node_single_splat_p(kwnode)) {
6950 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6951 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6952 }
6953 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6954 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6955 }
6956 else {
6957 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6958 }
6959 argc += 1;
6960 }
6961
6962 return argc;
6963 }
6964 default: {
6965 UNKNOWN_NODE("setup_arg", argn, Qnil);
6966 }
6967 }
6968}
6969
6970static void
6971setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6972{
6973 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6974 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6975 }
6976}
6977
6978static bool
6979setup_args_dup_rest_p(const NODE *argn)
6980{
6981 switch(nd_type(argn)) {
6982 case NODE_LVAR:
6983 case NODE_DVAR:
6984 case NODE_GVAR:
6985 case NODE_IVAR:
6986 case NODE_CVAR:
6987 case NODE_CONST:
6988 case NODE_COLON3:
6989 case NODE_INTEGER:
6990 case NODE_FLOAT:
6991 case NODE_RATIONAL:
6992 case NODE_IMAGINARY:
6993 case NODE_STR:
6994 case NODE_SYM:
6995 case NODE_REGX:
6996 case NODE_SELF:
6997 case NODE_NIL:
6998 case NODE_TRUE:
6999 case NODE_FALSE:
7000 case NODE_LAMBDA:
7001 case NODE_NTH_REF:
7002 case NODE_BACK_REF:
7003 return false;
7004 case NODE_COLON2:
7005 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
7006 case NODE_LIST:
7007 while (argn) {
7008 if (setup_args_dup_rest_p(RNODE_LIST(argn)->nd_head)) {
7009 return true;
7010 }
7011 argn = RNODE_LIST(argn)->nd_next;
7012 }
7013 return false;
7014 default:
7015 return true;
7016 }
7017}
7018
7019static VALUE
7020setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
7021 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
7022{
7023 VALUE ret;
7024 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
7025
7026 if (argn) {
7027 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
7028 RNODE_BLOCK_PASS(argn)->nd_head : argn;
7029
7030 if (check_arg) {
7031 switch(nd_type(check_arg)) {
7032 case(NODE_SPLAT):
7033 // avoid caller side array allocation for f(*arg)
7034 dup_rest = SPLATARRAY_FALSE;
7035 break;
7036 case(NODE_ARGSCAT):
7037 // avoid caller side array allocation for f(1, *arg)
7038 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
7039 break;
7040 case(NODE_ARGSPUSH):
7041 // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
7042 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
7043 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
7044 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
7045 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
7046 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
7047
7048 if (dup_rest == SPLATARRAY_FALSE) {
7049 // require allocation for keyword key/value/splat that may modify splatted argument
7050 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
7051 while (node) {
7052 NODE *key_node = RNODE_LIST(node)->nd_head;
7053 if (key_node && setup_args_dup_rest_p(key_node)) {
7054 dup_rest = SPLATARRAY_TRUE;
7055 break;
7056 }
7057
7058 node = RNODE_LIST(node)->nd_next;
7059 NODE *value_node = RNODE_LIST(node)->nd_head;
7060 if (setup_args_dup_rest_p(value_node)) {
7061 dup_rest = SPLATARRAY_TRUE;
7062 break;
7063 }
7064
7065 node = RNODE_LIST(node)->nd_next;
7066 }
7067 }
7068 break;
7069 default:
7070 break;
7071 }
7072 }
7073
7074 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
7075 // for block pass that may modify splatted argument, dup rest and kwrest if given
7076 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
7077 }
7078 }
7079 initial_dup_rest = dup_rest;
7080
7081 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
7082 DECL_ANCHOR(arg_block);
7083 INIT_ANCHOR(arg_block);
7084
7085 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
7086 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
7087
7088 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
7089 const NODE * arg_node =
7090 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
7091
7092 int argc = 0;
7093
7094 // Only compile leading args:
7095 // foo(x, y, ...)
7096 // ^^^^
7097 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
7098 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
7099 }
7100
7101 *flag |= VM_CALL_FORWARDING;
7102
7103 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
7104 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
7105 return INT2FIX(argc);
7106 }
7107 else {
7108 *flag |= VM_CALL_ARGS_BLOCKARG;
7109
7110 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
7111 }
7112
7113 if (LIST_INSN_SIZE_ONE(arg_block)) {
7114 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
7115 if (IS_INSN(elem)) {
7116 INSN *iobj = (INSN *)elem;
7117 if (iobj->insn_id == BIN(getblockparam)) {
7118 iobj->insn_id = BIN(getblockparamproxy);
7119 }
7120 }
7121 }
7122 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
7123 ADD_SEQ(args, arg_block);
7124 }
7125 else {
7126 ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
7127 }
7128 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
7129 return ret;
7130}
7131
7132static void
7133build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
7134{
7135 const NODE *body = ptr;
7136 int line = nd_line(body);
7137 VALUE argc = INT2FIX(0);
7138 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
7139
7140 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7141 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
7142 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
7143 iseq_set_local_table(iseq, 0, 0);
7144}
7145
7146static void
7147compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
7148{
7149 const NODE *vars;
7150 LINK_ELEMENT *last;
7151 int line = nd_line(node);
7152 const NODE *line_node = node;
7153 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
7154
7155#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
7156 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
7157#else
7158 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
7159#endif
7160 ADD_INSN(ret, line_node, dup);
7161 ADD_INSNL(ret, line_node, branchunless, fail_label);
7162
7163 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
7164 INSN *cap;
7165 if (RNODE_BLOCK(vars)->nd_next) {
7166 ADD_INSN(ret, line_node, dup);
7167 }
7168 last = ret->last;
7169 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
7170 last = last->next; /* putobject :var */
7171 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
7172 NULL, INT2FIX(0), NULL);
7173 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
7174#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
7175 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
7176 /* only one name */
7177 DECL_ANCHOR(nom);
7178
7179 INIT_ANCHOR(nom);
7180 ADD_INSNL(nom, line_node, jump, end_label);
7181 ADD_LABEL(nom, fail_label);
7182# if 0 /* $~ must be MatchData or nil */
7183 ADD_INSN(nom, line_node, pop);
7184 ADD_INSN(nom, line_node, putnil);
7185# endif
7186 ADD_LABEL(nom, end_label);
7187 (nom->last->next = cap->link.next)->prev = nom->last;
7188 (cap->link.next = nom->anchor.next)->prev = &cap->link;
7189 return;
7190 }
7191#endif
7192 }
7193 ADD_INSNL(ret, line_node, jump, end_label);
7194 ADD_LABEL(ret, fail_label);
7195 ADD_INSN(ret, line_node, pop);
7196 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
7197 last = ret->last;
7198 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
7199 last = last->next; /* putobject :var */
7200 ((INSN*)last)->insn_id = BIN(putnil);
7201 ((INSN*)last)->operand_size = 0;
7202 }
7203 ADD_LABEL(ret, end_label);
7204}
7205
7206static int
7207optimizable_range_item_p(const NODE *n)
7208{
7209 if (!n) return FALSE;
7210 switch (nd_type(n)) {
7211 case NODE_LINE:
7212 return TRUE;
7213 case NODE_INTEGER:
7214 return TRUE;
7215 case NODE_NIL:
7216 return TRUE;
7217 default:
7218 return FALSE;
7219 }
7220}
7221
7222static VALUE
7223optimized_range_item(const NODE *n)
7224{
7225 switch (nd_type(n)) {
7226 case NODE_LINE:
7227 return rb_node_line_lineno_val(n);
7228 case NODE_INTEGER:
7229 return rb_node_integer_literal_val(n);
7230 case NODE_FLOAT:
7231 return rb_node_float_literal_val(n);
7232 case NODE_RATIONAL:
7233 return rb_node_rational_literal_val(n);
7234 case NODE_IMAGINARY:
7235 return rb_node_imaginary_literal_val(n);
7236 case NODE_NIL:
7237 return Qnil;
7238 default:
7239 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
7240 }
7241}
7242
7243static int
7244compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
7245{
7246 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
7247 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
7248
7249 const int line = nd_line(node);
7250 const NODE *line_node = node;
7251 DECL_ANCHOR(cond_seq);
7252 LABEL *then_label, *else_label, *end_label;
7253 VALUE branches = Qfalse;
7254
7255 INIT_ANCHOR(cond_seq);
7256 then_label = NEW_LABEL(line);
7257 else_label = NEW_LABEL(line);
7258 end_label = 0;
7259
7260 NODE *cond = RNODE_IF(node)->nd_cond;
7261 if (nd_type(cond) == NODE_BLOCK) {
7262 cond = RNODE_BLOCK(cond)->nd_head;
7263 }
7264
7265 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
7266 ADD_SEQ(ret, cond_seq);
7267
7268 if (then_label->refcnt && else_label->refcnt) {
7269 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
7270 }
7271
7272 if (then_label->refcnt) {
7273 ADD_LABEL(ret, then_label);
7274
7275 DECL_ANCHOR(then_seq);
7276 INIT_ANCHOR(then_seq);
7277 CHECK(COMPILE_(then_seq, "then", node_body, popped));
7278
7279 if (else_label->refcnt) {
7280 const NODE *const coverage_node = node_body ? node_body : node;
7281 add_trace_branch_coverage(
7282 iseq,
7283 ret,
7284 nd_code_loc(coverage_node),
7285 nd_node_id(coverage_node),
7286 0,
7287 type == NODE_IF ? "then" : "else",
7288 branches);
7289 end_label = NEW_LABEL(line);
7290 ADD_INSNL(then_seq, line_node, jump, end_label);
7291 if (!popped) {
7292 ADD_INSN(then_seq, line_node, pop);
7293 }
7294 }
7295 ADD_SEQ(ret, then_seq);
7296 }
7297
7298 if (else_label->refcnt) {
7299 ADD_LABEL(ret, else_label);
7300
7301 DECL_ANCHOR(else_seq);
7302 INIT_ANCHOR(else_seq);
7303 CHECK(COMPILE_(else_seq, "else", node_else, popped));
7304
7305 if (then_label->refcnt) {
7306 const NODE *const coverage_node = node_else ? node_else : node;
7307 add_trace_branch_coverage(
7308 iseq,
7309 ret,
7310 nd_code_loc(coverage_node),
7311 nd_node_id(coverage_node),
7312 1,
7313 type == NODE_IF ? "else" : "then",
7314 branches);
7315 }
7316 ADD_SEQ(ret, else_seq);
7317 }
7318
7319 if (end_label) {
7320 ADD_LABEL(ret, end_label);
7321 }
7322
7323 return COMPILE_OK;
7324}
7325
7326static int
7327compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7328{
7329 const NODE *vals;
7330 const NODE *node = orig_node;
7331 LABEL *endlabel, *elselabel;
7332 DECL_ANCHOR(head);
7333 DECL_ANCHOR(body_seq);
7334 DECL_ANCHOR(cond_seq);
7335 int only_special_literals = 1;
7336 VALUE literals = cdhash_new(0);
7337 int line;
7338 enum node_type type;
7339 const NODE *line_node;
7340 VALUE branches = Qfalse;
7341 int branch_id = 0;
7342
7343 INIT_ANCHOR(head);
7344 INIT_ANCHOR(body_seq);
7345 INIT_ANCHOR(cond_seq);
7346
7347 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
7348
7349 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), "case");
7350
7351 node = RNODE_CASE(node)->nd_body;
7352 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
7353 type = nd_type(node);
7354 line = nd_line(node);
7355 line_node = node;
7356
7357 endlabel = NEW_LABEL(line);
7358 elselabel = NEW_LABEL(line);
7359
7360 ADD_SEQ(ret, head); /* case VAL */
7361
7362 while (type == NODE_WHEN) {
7363 LABEL *l1;
7364
7365 l1 = NEW_LABEL(line);
7366 ADD_LABEL(body_seq, l1);
7367 ADD_INSN(body_seq, line_node, pop);
7368
7369 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7370 add_trace_branch_coverage(
7371 iseq,
7372 body_seq,
7373 nd_code_loc(coverage_node),
7374 nd_node_id(coverage_node),
7375 branch_id++,
7376 "when",
7377 branches);
7378
7379 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
7380 ADD_INSNL(body_seq, line_node, jump, endlabel);
7381
7382 vals = RNODE_WHEN(node)->nd_head;
7383 if (vals) {
7384 switch (nd_type(vals)) {
7385 case NODE_LIST:
7386 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
7387 if (only_special_literals < 0) return COMPILE_NG;
7388 break;
7389 case NODE_SPLAT:
7390 case NODE_ARGSCAT:
7391 case NODE_ARGSPUSH:
7392 only_special_literals = 0;
7393 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
7394 break;
7395 default:
7396 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
7397 }
7398 }
7399 else {
7400 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
7401 }
7402
7403 node = RNODE_WHEN(node)->nd_next;
7404 if (!node) {
7405 break;
7406 }
7407 type = nd_type(node);
7408 line = nd_line(node);
7409 line_node = node;
7410 }
7411 /* else */
7412 if (node) {
7413 ADD_LABEL(cond_seq, elselabel);
7414 ADD_INSN(cond_seq, line_node, pop);
7415 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
7416 CHECK(COMPILE_(cond_seq, "else", node, popped));
7417 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7418 }
7419 else {
7420 debugs("== else (implicit)\n");
7421 ADD_LABEL(cond_seq, elselabel);
7422 ADD_INSN(cond_seq, orig_node, pop);
7423 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
7424 if (!popped) {
7425 ADD_INSN(cond_seq, orig_node, putnil);
7426 }
7427 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7428 }
7429
7430 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7431 ADD_INSN(ret, orig_node, dup);
7432 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
7433 RB_OBJ_WRITTEN(iseq, Qundef, literals);
7434 LABEL_REF(elselabel);
7435 }
7436
7437 ADD_SEQ(ret, cond_seq);
7438 ADD_SEQ(ret, body_seq);
7439 ADD_LABEL(ret, endlabel);
7440 return COMPILE_OK;
7441}
7442
7443static int
7444compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7445{
7446 const NODE *vals;
7447 const NODE *val;
7448 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
7449 LABEL *endlabel;
7450 DECL_ANCHOR(body_seq);
7451 VALUE branches = Qfalse;
7452 int branch_id = 0;
7453
7454 branches = decl_branch_base(iseq, nd_node_id(orig_node), nd_code_loc(orig_node), "case");
7455
7456 INIT_ANCHOR(body_seq);
7457 endlabel = NEW_LABEL(nd_line(node));
7458
7459 while (node && nd_type_p(node, NODE_WHEN)) {
7460 const int line = nd_line(node);
7461 LABEL *l1 = NEW_LABEL(line);
7462 ADD_LABEL(body_seq, l1);
7463
7464 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7465 add_trace_branch_coverage(
7466 iseq,
7467 body_seq,
7468 nd_code_loc(coverage_node),
7469 nd_node_id(coverage_node),
7470 branch_id++,
7471 "when",
7472 branches);
7473
7474 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7475 ADD_INSNL(body_seq, node, jump, endlabel);
7476
7477 vals = RNODE_WHEN(node)->nd_head;
7478 if (!vals) {
7479 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7480 }
7481 switch (nd_type(vals)) {
7482 case NODE_LIST:
7483 while (vals) {
7484 LABEL *lnext;
7485 val = RNODE_LIST(vals)->nd_head;
7486 lnext = NEW_LABEL(nd_line(val));
7487 debug_compile("== when2\n", (void)0);
7488 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7489 ADD_LABEL(ret, lnext);
7490 vals = RNODE_LIST(vals)->nd_next;
7491 }
7492 break;
7493 case NODE_SPLAT:
7494 case NODE_ARGSCAT:
7495 case NODE_ARGSPUSH:
7496 ADD_INSN(ret, vals, putnil);
7497 CHECK(COMPILE(ret, "when2/cond splat", vals));
7498 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7499 ADD_INSNL(ret, vals, branchif, l1);
7500 break;
7501 default:
7502 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7503 }
7504 node = RNODE_WHEN(node)->nd_next;
7505 }
7506 /* else */
7507 const NODE *const coverage_node = node ? node : orig_node;
7508 add_trace_branch_coverage(
7509 iseq,
7510 ret,
7511 nd_code_loc(coverage_node),
7512 nd_node_id(coverage_node),
7513 branch_id,
7514 "else",
7515 branches);
7516 CHECK(COMPILE_(ret, "else", node, popped));
7517 ADD_INSNL(ret, orig_node, jump, endlabel);
7518
7519 ADD_SEQ(ret, body_seq);
7520 ADD_LABEL(ret, endlabel);
7521 return COMPILE_OK;
7522}
7523
7524static 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);
7525
7526static 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);
7527static 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);
7528static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7529static 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);
7530static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7531
7532#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7533#define CASE3_BI_OFFSET_ERROR_STRING 1
7534#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7535#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7536#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7537
7538static int
7539iseq_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)
7540{
7541 const int line = nd_line(node);
7542 const NODE *line_node = node;
7543
7544 switch (nd_type(node)) {
7545 case NODE_ARYPTN: {
7546 /*
7547 * if pattern.use_rest_num?
7548 * rest_num = 0
7549 * end
7550 * if pattern.has_constant_node?
7551 * unless pattern.constant === obj
7552 * goto match_failed
7553 * end
7554 * end
7555 * unless obj.respond_to?(:deconstruct)
7556 * goto match_failed
7557 * end
7558 * d = obj.deconstruct
7559 * unless Array === d
7560 * goto type_error
7561 * end
7562 * min_argc = pattern.pre_args_num + pattern.post_args_num
7563 * if pattern.has_rest_arg?
7564 * unless d.length >= min_argc
7565 * goto match_failed
7566 * end
7567 * else
7568 * unless d.length == min_argc
7569 * goto match_failed
7570 * end
7571 * end
7572 * pattern.pre_args_num.each do |i|
7573 * unless pattern.pre_args[i].match?(d[i])
7574 * goto match_failed
7575 * end
7576 * end
7577 * if pattern.use_rest_num?
7578 * rest_num = d.length - min_argc
7579 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7580 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7581 * goto match_failed
7582 * end
7583 * end
7584 * end
7585 * pattern.post_args_num.each do |i|
7586 * j = pattern.pre_args_num + i
7587 * j += rest_num
7588 * unless pattern.post_args[i].match?(d[j])
7589 * goto match_failed
7590 * end
7591 * end
7592 * goto matched
7593 * type_error:
7594 * FrozenCore.raise TypeError
7595 * match_failed:
7596 * goto unmatched
7597 */
7598 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7599 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7600 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7601
7602 const int min_argc = pre_args_num + post_args_num;
7603 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7604 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7605
7606 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7607 int i;
7608 match_failed = NEW_LABEL(line);
7609 type_error = NEW_LABEL(line);
7610 deconstruct = NEW_LABEL(line);
7611 deconstructed = NEW_LABEL(line);
7612
7613 if (use_rest_num) {
7614 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7615 ADD_INSN(ret, line_node, swap);
7616 if (base_index) {
7617 base_index++;
7618 }
7619 }
7620
7621 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7622
7623 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7624
7625 ADD_INSN(ret, line_node, dup);
7626 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7627 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7628 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7629 if (in_single_pattern) {
7630 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7631 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7632 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7633 INT2FIX(min_argc), base_index + 1 /* (1) */));
7634 }
7635 ADD_INSNL(ret, line_node, branchunless, match_failed);
7636
7637 for (i = 0; i < pre_args_num; i++) {
7638 ADD_INSN(ret, line_node, dup);
7639 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7640 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7641 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));
7642 args = RNODE_LIST(args)->nd_next;
7643 }
7644
7645 if (RNODE_ARYPTN(node)->rest_arg) {
7646 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7647 ADD_INSN(ret, line_node, dup);
7648 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7649 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7650 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7651 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7652 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7653 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
7654 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7655
7656 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));
7657 }
7658 else {
7659 if (post_args_num > 0) {
7660 ADD_INSN(ret, line_node, dup);
7661 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7662 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7663 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7664 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7665 ADD_INSN(ret, line_node, pop);
7666 }
7667 }
7668 }
7669
7670 args = RNODE_ARYPTN(node)->post_args;
7671 for (i = 0; i < post_args_num; i++) {
7672 ADD_INSN(ret, line_node, dup);
7673
7674 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7675 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7676 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7677
7678 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7679 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));
7680 args = RNODE_LIST(args)->nd_next;
7681 }
7682
7683 ADD_INSN(ret, line_node, pop);
7684 if (use_rest_num) {
7685 ADD_INSN(ret, line_node, pop);
7686 }
7687 ADD_INSNL(ret, line_node, jump, matched);
7688 ADD_INSN(ret, line_node, putnil);
7689 if (use_rest_num) {
7690 ADD_INSN(ret, line_node, putnil);
7691 }
7692
7693 ADD_LABEL(ret, type_error);
7694 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7695 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7696 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7697 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7698 ADD_INSN(ret, line_node, pop);
7699
7700 ADD_LABEL(ret, match_failed);
7701 ADD_INSN(ret, line_node, pop);
7702 if (use_rest_num) {
7703 ADD_INSN(ret, line_node, pop);
7704 }
7705 ADD_INSNL(ret, line_node, jump, unmatched);
7706
7707 break;
7708 }
7709 case NODE_FNDPTN: {
7710 /*
7711 * if pattern.has_constant_node?
7712 * unless pattern.constant === obj
7713 * goto match_failed
7714 * end
7715 * end
7716 * unless obj.respond_to?(:deconstruct)
7717 * goto match_failed
7718 * end
7719 * d = obj.deconstruct
7720 * unless Array === d
7721 * goto type_error
7722 * end
7723 * unless d.length >= pattern.args_num
7724 * goto match_failed
7725 * end
7726 *
7727 * begin
7728 * len = d.length
7729 * limit = d.length - pattern.args_num
7730 * i = 0
7731 * while i <= limit
7732 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7733 * if pattern.has_pre_rest_arg_id
7734 * unless pattern.pre_rest_arg.match?(d[0, i])
7735 * goto find_failed
7736 * end
7737 * end
7738 * if pattern.has_post_rest_arg_id
7739 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7740 * goto find_failed
7741 * end
7742 * end
7743 * goto find_succeeded
7744 * end
7745 * i+=1
7746 * end
7747 * find_failed:
7748 * goto match_failed
7749 * find_succeeded:
7750 * end
7751 *
7752 * goto matched
7753 * type_error:
7754 * FrozenCore.raise TypeError
7755 * match_failed:
7756 * goto unmatched
7757 */
7758 const NODE *args = RNODE_FNDPTN(node)->args;
7759 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7760
7761 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7762 match_failed = NEW_LABEL(line);
7763 type_error = NEW_LABEL(line);
7764 deconstruct = NEW_LABEL(line);
7765 deconstructed = NEW_LABEL(line);
7766
7767 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7768
7769 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7770
7771 ADD_INSN(ret, line_node, dup);
7772 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7773 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7774 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7775 if (in_single_pattern) {
7776 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) */));
7777 }
7778 ADD_INSNL(ret, line_node, branchunless, match_failed);
7779
7780 {
7781 LABEL *while_begin = NEW_LABEL(nd_line(node));
7782 LABEL *next_loop = NEW_LABEL(nd_line(node));
7783 LABEL *find_succeeded = NEW_LABEL(line);
7784 LABEL *find_failed = NEW_LABEL(nd_line(node));
7785 int j;
7786
7787 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7788 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7789
7790 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7791 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7792 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7793
7794 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7795
7796 ADD_LABEL(ret, while_begin);
7797
7798 ADD_INSN(ret, line_node, dup);
7799 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7800 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7801 ADD_INSNL(ret, line_node, branchunless, find_failed);
7802
7803 for (j = 0; j < args_num; j++) {
7804 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7805 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7806 if (j != 0) {
7807 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7808 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7809 }
7810 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7811
7812 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));
7813 args = RNODE_LIST(args)->nd_next;
7814 }
7815
7816 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7817 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7818 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7819 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7820 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7821 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));
7822 }
7823 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7824 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7825 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7826 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7827 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7828 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7829 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7830 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));
7831 }
7832 ADD_INSNL(ret, line_node, jump, find_succeeded);
7833
7834 ADD_LABEL(ret, next_loop);
7835 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7836 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7837 ADD_INSNL(ret, line_node, jump, while_begin);
7838
7839 ADD_LABEL(ret, find_failed);
7840 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7841 if (in_single_pattern) {
7842 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7843 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7844 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7845 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7846 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7847
7848 ADD_INSN1(ret, line_node, putobject, Qfalse);
7849 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7850
7851 ADD_INSN(ret, line_node, pop);
7852 ADD_INSN(ret, line_node, pop);
7853 }
7854 ADD_INSNL(ret, line_node, jump, match_failed);
7855 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7856
7857 ADD_LABEL(ret, find_succeeded);
7858 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7859 }
7860
7861 ADD_INSN(ret, line_node, pop);
7862 ADD_INSNL(ret, line_node, jump, matched);
7863 ADD_INSN(ret, line_node, putnil);
7864
7865 ADD_LABEL(ret, type_error);
7866 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7867 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7868 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7869 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7870 ADD_INSN(ret, line_node, pop);
7871
7872 ADD_LABEL(ret, match_failed);
7873 ADD_INSN(ret, line_node, pop);
7874 ADD_INSNL(ret, line_node, jump, unmatched);
7875
7876 break;
7877 }
7878 case NODE_HSHPTN: {
7879 /*
7880 * keys = nil
7881 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7882 * keys = pattern.kw_args_node.keys
7883 * end
7884 * if pattern.has_constant_node?
7885 * unless pattern.constant === obj
7886 * goto match_failed
7887 * end
7888 * end
7889 * unless obj.respond_to?(:deconstruct_keys)
7890 * goto match_failed
7891 * end
7892 * d = obj.deconstruct_keys(keys)
7893 * unless Hash === d
7894 * goto type_error
7895 * end
7896 * if pattern.has_kw_rest_arg_node?
7897 * d = d.dup
7898 * end
7899 * if pattern.has_kw_args_node?
7900 * pattern.kw_args_node.each |k,|
7901 * unless d.key?(k)
7902 * goto match_failed
7903 * end
7904 * end
7905 * pattern.kw_args_node.each |k, pat|
7906 * if pattern.has_kw_rest_arg_node?
7907 * unless pat.match?(d.delete(k))
7908 * goto match_failed
7909 * end
7910 * else
7911 * unless pat.match?(d[k])
7912 * goto match_failed
7913 * end
7914 * end
7915 * end
7916 * else
7917 * unless d.empty?
7918 * goto match_failed
7919 * end
7920 * end
7921 * if pattern.has_kw_rest_arg_node?
7922 * if pattern.no_rest_keyword?
7923 * unless d.empty?
7924 * goto match_failed
7925 * end
7926 * else
7927 * unless pattern.kw_rest_arg_node.match?(d)
7928 * goto match_failed
7929 * end
7930 * end
7931 * end
7932 * goto matched
7933 * type_error:
7934 * FrozenCore.raise TypeError
7935 * match_failed:
7936 * goto unmatched
7937 */
7938 LABEL *match_failed, *type_error;
7939 VALUE keys = Qnil;
7940
7941 match_failed = NEW_LABEL(line);
7942 type_error = NEW_LABEL(line);
7943
7944 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7945 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7946 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7947 while (kw_args) {
7948 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7949 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7950 }
7951 }
7952
7953 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7954
7955 ADD_INSN(ret, line_node, dup);
7956 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7957 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7958 if (in_single_pattern) {
7959 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7960 }
7961 ADD_INSNL(ret, line_node, branchunless, match_failed);
7962
7963 if (NIL_P(keys)) {
7964 ADD_INSN(ret, line_node, putnil);
7965 }
7966 else {
7968 ADD_INSN1(ret, line_node, duparray, keys);
7969 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7970 }
7971 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7972
7973 ADD_INSN(ret, line_node, dup);
7974 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7975 ADD_INSNL(ret, line_node, branchunless, type_error);
7976
7977 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7978 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7979 }
7980
7981 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7982 int i;
7983 int keys_num;
7984 const NODE *args;
7985 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7986 if (args) {
7987 DECL_ANCHOR(match_values);
7988 INIT_ANCHOR(match_values);
7989 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7990 for (i = 0; i < keys_num; i++) {
7991 NODE *key_node = RNODE_LIST(args)->nd_head;
7992 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7993 VALUE key = get_symbol_value(iseq, key_node);
7994
7995 ADD_INSN(ret, line_node, dup);
7996 ADD_INSN1(ret, line_node, putobject, key);
7997 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7998 if (in_single_pattern) {
7999 LABEL *match_succeeded;
8000 match_succeeded = NEW_LABEL(line);
8001
8002 ADD_INSN(ret, line_node, dup);
8003 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8004
8005 VALUE str = rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key));
8006 ADD_INSN1(ret, line_node, putobject, RB_OBJ_SET_SHAREABLE(str)); // (4)
8007 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
8008 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
8009 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
8010 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
8011 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
8012 ADD_INSN1(ret, line_node, putobject, key); // (7)
8013 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
8014
8015 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
8016
8017 ADD_LABEL(ret, match_succeeded);
8018 }
8019 ADD_INSNL(ret, line_node, branchunless, match_failed);
8020
8021 ADD_INSN(match_values, line_node, dup);
8022 ADD_INSN1(match_values, line_node, putobject, key);
8023 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
8024 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
8025 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
8026 }
8027 ADD_SEQ(ret, match_values);
8028 }
8029 }
8030 else {
8031 ADD_INSN(ret, line_node, dup);
8032 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
8033 if (in_single_pattern) {
8034 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
8035 }
8036 ADD_INSNL(ret, line_node, branchunless, match_failed);
8037 }
8038
8039 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
8040 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
8041 ADD_INSN(ret, line_node, dup);
8042 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
8043 if (in_single_pattern) {
8044 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
8045 }
8046 ADD_INSNL(ret, line_node, branchunless, match_failed);
8047 }
8048 else {
8049 ADD_INSN(ret, line_node, dup); // (11)
8050 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));
8051 }
8052 }
8053
8054 ADD_INSN(ret, line_node, pop);
8055 ADD_INSNL(ret, line_node, jump, matched);
8056 ADD_INSN(ret, line_node, putnil);
8057
8058 ADD_LABEL(ret, type_error);
8059 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8060 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
8061 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
8062 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
8063 ADD_INSN(ret, line_node, pop);
8064
8065 ADD_LABEL(ret, match_failed);
8066 ADD_INSN(ret, line_node, pop);
8067 ADD_INSNL(ret, line_node, jump, unmatched);
8068 break;
8069 }
8070 case NODE_SYM:
8071 case NODE_REGX:
8072 case NODE_LINE:
8073 case NODE_INTEGER:
8074 case NODE_FLOAT:
8075 case NODE_RATIONAL:
8076 case NODE_IMAGINARY:
8077 case NODE_FILE:
8078 case NODE_ENCODING:
8079 case NODE_STR:
8080 case NODE_XSTR:
8081 case NODE_DSTR:
8082 case NODE_DSYM:
8083 case NODE_DREGX:
8084 case NODE_LIST:
8085 case NODE_ZLIST:
8086 case NODE_LAMBDA:
8087 case NODE_DOT2:
8088 case NODE_DOT3:
8089 case NODE_CONST:
8090 case NODE_LVAR:
8091 case NODE_DVAR:
8092 case NODE_IVAR:
8093 case NODE_CVAR:
8094 case NODE_GVAR:
8095 case NODE_TRUE:
8096 case NODE_FALSE:
8097 case NODE_SELF:
8098 case NODE_NIL:
8099 case NODE_COLON2:
8100 case NODE_COLON3:
8101 case NODE_BEGIN:
8102 case NODE_BLOCK:
8103 case NODE_ONCE:
8104 CHECK(COMPILE(ret, "case in literal", node)); // (1)
8105 if (in_single_pattern) {
8106 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
8107 }
8108 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
8109 if (in_single_pattern) {
8110 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
8111 }
8112 ADD_INSNL(ret, line_node, branchif, matched);
8113 ADD_INSNL(ret, line_node, jump, unmatched);
8114 break;
8115 case NODE_LASGN: {
8116 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
8117 ID id = RNODE_LASGN(node)->nd_vid;
8118 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8119
8120 if (in_alt_pattern) {
8121 const char *name = rb_id2name(id);
8122 if (name && strlen(name) > 0 && name[0] != '_') {
8123 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
8124 rb_id2str(id));
8125 return COMPILE_NG;
8126 }
8127 }
8128
8129 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8130 ADD_INSNL(ret, line_node, jump, matched);
8131 break;
8132 }
8133 case NODE_DASGN: {
8134 int idx, lv, ls;
8135 ID id = RNODE_DASGN(node)->nd_vid;
8136
8137 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
8138
8139 if (in_alt_pattern) {
8140 const char *name = rb_id2name(id);
8141 if (name && strlen(name) > 0 && name[0] != '_') {
8142 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
8143 rb_id2str(id));
8144 return COMPILE_NG;
8145 }
8146 }
8147
8148 if (idx < 0) {
8149 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
8150 rb_id2str(id));
8151 return COMPILE_NG;
8152 }
8153 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
8154 ADD_INSNL(ret, line_node, jump, matched);
8155 break;
8156 }
8157 case NODE_IF:
8158 case NODE_UNLESS: {
8159 LABEL *match_failed;
8160 match_failed = unmatched;
8161 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
8162 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
8163 if (in_single_pattern) {
8164 LABEL *match_succeeded;
8165 match_succeeded = NEW_LABEL(line);
8166
8167 ADD_INSN(ret, line_node, dup);
8168 if (nd_type_p(node, NODE_IF)) {
8169 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8170 }
8171 else {
8172 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
8173 }
8174
8175 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
8176 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8177 ADD_INSN1(ret, line_node, putobject, Qfalse);
8178 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8179
8180 ADD_INSN(ret, line_node, pop);
8181 ADD_INSN(ret, line_node, pop);
8182
8183 ADD_LABEL(ret, match_succeeded);
8184 }
8185 if (nd_type_p(node, NODE_IF)) {
8186 ADD_INSNL(ret, line_node, branchunless, match_failed);
8187 }
8188 else {
8189 ADD_INSNL(ret, line_node, branchif, match_failed);
8190 }
8191 ADD_INSNL(ret, line_node, jump, matched);
8192 break;
8193 }
8194 case NODE_HASH: {
8195 NODE *n;
8196 LABEL *match_failed;
8197 match_failed = NEW_LABEL(line);
8198
8199 n = RNODE_HASH(node)->nd_head;
8200 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
8201 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8202 return COMPILE_NG;
8203 }
8204
8205 ADD_INSN(ret, line_node, dup); // (1)
8206 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));
8207 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));
8208 ADD_INSN(ret, line_node, putnil);
8209
8210 ADD_LABEL(ret, match_failed);
8211 ADD_INSN(ret, line_node, pop);
8212 ADD_INSNL(ret, line_node, jump, unmatched);
8213 break;
8214 }
8215 case NODE_OR: {
8216 LABEL *match_succeeded, *fin;
8217 match_succeeded = NEW_LABEL(line);
8218 fin = NEW_LABEL(line);
8219
8220 ADD_INSN(ret, line_node, dup); // (1)
8221 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));
8222 ADD_LABEL(ret, match_succeeded);
8223 ADD_INSN(ret, line_node, pop);
8224 ADD_INSNL(ret, line_node, jump, matched);
8225 ADD_INSN(ret, line_node, putnil);
8226 ADD_LABEL(ret, fin);
8227 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
8228 break;
8229 }
8230 default:
8231 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
8232 }
8233 return COMPILE_OK;
8234}
8235
8236static int
8237iseq_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)
8238{
8239 LABEL *fin = NEW_LABEL(nd_line(node));
8240 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
8241 ADD_LABEL(ret, fin);
8242 return COMPILE_OK;
8243}
8244
8245static int
8246iseq_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)
8247{
8248 const NODE *line_node = node;
8249
8250 if (RNODE_ARYPTN(node)->nd_pconst) {
8251 ADD_INSN(ret, line_node, dup); // (1)
8252 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
8253 if (in_single_pattern) {
8254 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
8255 }
8256 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
8257 if (in_single_pattern) {
8258 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
8259 }
8260 ADD_INSNL(ret, line_node, branchunless, match_failed);
8261 }
8262 return COMPILE_OK;
8263}
8264
8265
8266static int
8267iseq_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)
8268{
8269 const NODE *line_node = node;
8270
8271 // NOTE: this optimization allows us to re-use the #deconstruct value
8272 // (or its absence).
8273 if (use_deconstructed_cache) {
8274 // If value is nil then we haven't tried to deconstruct
8275 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8276 ADD_INSNL(ret, line_node, branchnil, deconstruct);
8277
8278 // If false then the value is not deconstructable
8279 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8280 ADD_INSNL(ret, line_node, branchunless, match_failed);
8281
8282 // Drop value, add deconstructed to the stack and jump
8283 ADD_INSN(ret, line_node, pop); // (1)
8284 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
8285 ADD_INSNL(ret, line_node, jump, deconstructed);
8286 }
8287 else {
8288 ADD_INSNL(ret, line_node, jump, deconstruct);
8289 }
8290
8291 ADD_LABEL(ret, deconstruct);
8292 ADD_INSN(ret, line_node, dup);
8293 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
8294 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
8295
8296 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
8297 if (use_deconstructed_cache) {
8298 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
8299 }
8300
8301 if (in_single_pattern) {
8302 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
8303 }
8304
8305 ADD_INSNL(ret, line_node, branchunless, match_failed);
8306
8307 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
8308
8309 // Cache the result (if it's cacheable - currently, only top-level array patterns)
8310 if (use_deconstructed_cache) {
8311 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8312 }
8313
8314 ADD_INSN(ret, line_node, dup);
8315 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
8316 ADD_INSNL(ret, line_node, branchunless, type_error);
8317
8318 ADD_LABEL(ret, deconstructed);
8319
8320 return COMPILE_OK;
8321}
8322
8323static int
8324iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
8325{
8326 /*
8327 * if match_succeeded?
8328 * goto match_succeeded
8329 * end
8330 * error_string = FrozenCore.sprintf(errmsg, matchee)
8331 * key_error_p = false
8332 * match_succeeded:
8333 */
8334 const int line = nd_line(node);
8335 const NODE *line_node = node;
8336 LABEL *match_succeeded = NEW_LABEL(line);
8337
8338 ADD_INSN(ret, line_node, dup);
8339 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8340
8341 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8342 ADD_INSN1(ret, line_node, putobject, errmsg);
8343 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8344 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
8345 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8346
8347 ADD_INSN1(ret, line_node, putobject, Qfalse);
8348 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8349
8350 ADD_INSN(ret, line_node, pop);
8351 ADD_INSN(ret, line_node, pop);
8352 ADD_LABEL(ret, match_succeeded);
8353
8354 return COMPILE_OK;
8355}
8356
8357static int
8358iseq_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)
8359{
8360 /*
8361 * if match_succeeded?
8362 * goto match_succeeded
8363 * end
8364 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
8365 * key_error_p = false
8366 * match_succeeded:
8367 */
8368 const int line = nd_line(node);
8369 const NODE *line_node = node;
8370 LABEL *match_succeeded = NEW_LABEL(line);
8371
8372 ADD_INSN(ret, line_node, dup);
8373 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8374
8375 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8376 ADD_INSN1(ret, line_node, putobject, errmsg);
8377 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8378 ADD_INSN(ret, line_node, dup);
8379 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
8380 ADD_INSN1(ret, line_node, putobject, pattern_length);
8381 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
8382 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8383
8384 ADD_INSN1(ret, line_node, putobject, Qfalse);
8385 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
8386
8387 ADD_INSN(ret, line_node, pop);
8388 ADD_INSN(ret, line_node, pop);
8389 ADD_LABEL(ret, match_succeeded);
8390
8391 return COMPILE_OK;
8392}
8393
8394static int
8395iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
8396{
8397 /*
8398 * if match_succeeded?
8399 * goto match_succeeded
8400 * end
8401 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
8402 * key_error_p = false
8403 * match_succeeded:
8404 */
8405 const int line = nd_line(node);
8406 const NODE *line_node = node;
8407 LABEL *match_succeeded = NEW_LABEL(line);
8408
8409 ADD_INSN(ret, line_node, dup);
8410 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8411
8412 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8413 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
8414 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8415 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
8416 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
8417 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8418
8419 ADD_INSN1(ret, line_node, putobject, Qfalse);
8420 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8421
8422 ADD_INSN(ret, line_node, pop);
8423 ADD_INSN(ret, line_node, pop);
8424
8425 ADD_LABEL(ret, match_succeeded);
8426 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
8427 ADD_INSN(ret, line_node, pop);
8428 ADD_INSN(ret, line_node, pop);
8429
8430 return COMPILE_OK;
8431}
8432
8433static int
8434compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
8435{
8436 const NODE *pattern;
8437 const NODE *node = orig_node;
8438 LABEL *endlabel, *elselabel;
8439 DECL_ANCHOR(head);
8440 DECL_ANCHOR(body_seq);
8441 DECL_ANCHOR(cond_seq);
8442 int line;
8443 enum node_type type;
8444 const NODE *line_node;
8445 VALUE branches = 0;
8446 int branch_id = 0;
8447 bool single_pattern;
8448
8449 INIT_ANCHOR(head);
8450 INIT_ANCHOR(body_seq);
8451 INIT_ANCHOR(cond_seq);
8452
8453 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), "case");
8454
8455 node = RNODE_CASE3(node)->nd_body;
8456 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
8457 type = nd_type(node);
8458 line = nd_line(node);
8459 line_node = node;
8460 single_pattern = !RNODE_IN(node)->nd_next;
8461
8462 endlabel = NEW_LABEL(line);
8463 elselabel = NEW_LABEL(line);
8464
8465 if (single_pattern) {
8466 /* allocate stack for ... */
8467 ADD_INSN(head, line_node, putnil); /* key_error_key */
8468 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
8469 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
8470 ADD_INSN(head, line_node, putnil); /* error_string */
8471 }
8472 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
8473
8474 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8475
8476 ADD_SEQ(ret, head); /* case VAL */
8477
8478 while (type == NODE_IN) {
8479 LABEL *l1;
8480
8481 if (branch_id) {
8482 ADD_INSN(body_seq, line_node, putnil);
8483 }
8484 l1 = NEW_LABEL(line);
8485 ADD_LABEL(body_seq, l1);
8486 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8487
8488 const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8489 add_trace_branch_coverage(
8490 iseq,
8491 body_seq,
8492 nd_code_loc(coverage_node),
8493 nd_node_id(coverage_node),
8494 branch_id++,
8495 "in",
8496 branches);
8497
8498 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8499 ADD_INSNL(body_seq, line_node, jump, endlabel);
8500
8501 pattern = RNODE_IN(node)->nd_head;
8502 if (pattern) {
8503 int pat_line = nd_line(pattern);
8504 LABEL *next_pat = NEW_LABEL(pat_line);
8505 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8506 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8507 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8508 ADD_LABEL(cond_seq, next_pat);
8509 LABEL_UNREMOVABLE(next_pat);
8510 }
8511 else {
8512 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8513 return COMPILE_NG;
8514 }
8515
8516 node = RNODE_IN(node)->nd_next;
8517 if (!node) {
8518 break;
8519 }
8520 type = nd_type(node);
8521 line = nd_line(node);
8522 line_node = node;
8523 }
8524 /* else */
8525 if (node) {
8526 ADD_LABEL(cond_seq, elselabel);
8527 ADD_INSN(cond_seq, line_node, pop);
8528 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8529 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8530 CHECK(COMPILE_(cond_seq, "else", node, popped));
8531 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8532 ADD_INSN(cond_seq, line_node, putnil);
8533 if (popped) {
8534 ADD_INSN(cond_seq, line_node, putnil);
8535 }
8536 }
8537 else {
8538 debugs("== else (implicit)\n");
8539 ADD_LABEL(cond_seq, elselabel);
8540 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8541 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8542
8543 if (single_pattern) {
8544 /*
8545 * if key_error_p
8546 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8547 * else
8548 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8549 * end
8550 */
8551 LABEL *key_error, *fin;
8552 struct rb_callinfo_kwarg *kw_arg;
8553
8554 key_error = NEW_LABEL(line);
8555 fin = NEW_LABEL(line);
8556
8557 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8558 kw_arg->references = 0;
8559 kw_arg->keyword_len = 2;
8560 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8561 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8562
8563 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8564 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8565 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8566 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8567 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8568 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8569 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8570 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8571 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8572 ADD_INSNL(cond_seq, orig_node, jump, fin);
8573
8574 ADD_LABEL(cond_seq, key_error);
8575 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8576 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8577 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8578 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8579 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8580 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8581 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8582 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8583 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8584 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8585
8586 ADD_LABEL(cond_seq, fin);
8587 }
8588 else {
8589 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8590 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8591 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8592 }
8593 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8594 if (!popped) {
8595 ADD_INSN(cond_seq, orig_node, putnil);
8596 }
8597 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8598 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8599 if (popped) {
8600 ADD_INSN(cond_seq, line_node, putnil);
8601 }
8602 }
8603
8604 ADD_SEQ(ret, cond_seq);
8605 ADD_SEQ(ret, body_seq);
8606 ADD_LABEL(ret, endlabel);
8607 return COMPILE_OK;
8608}
8609
8610#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8611#undef CASE3_BI_OFFSET_ERROR_STRING
8612#undef CASE3_BI_OFFSET_KEY_ERROR_P
8613#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8614#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8615
8616static int
8617compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8618{
8619 const int line = (int)nd_line(node);
8620 const NODE *line_node = node;
8621
8622 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8623 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8624 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8625 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8626 VALUE branches = Qfalse;
8627
8629
8630 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8631 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8632 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8633 LABEL *end_label = NEW_LABEL(line);
8634 LABEL *adjust_label = NEW_LABEL(line);
8635
8636 LABEL *next_catch_label = NEW_LABEL(line);
8637 LABEL *tmp_label = NULL;
8638
8639 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8640 push_ensure_entry(iseq, &enl, NULL, NULL);
8641
8642 if (RNODE_WHILE(node)->nd_state == 1) {
8643 ADD_INSNL(ret, line_node, jump, next_label);
8644 }
8645 else {
8646 tmp_label = NEW_LABEL(line);
8647 ADD_INSNL(ret, line_node, jump, tmp_label);
8648 }
8649 ADD_LABEL(ret, adjust_label);
8650 ADD_INSN(ret, line_node, putnil);
8651 ADD_LABEL(ret, next_catch_label);
8652 ADD_INSN(ret, line_node, pop);
8653 ADD_INSNL(ret, line_node, jump, next_label);
8654 if (tmp_label) ADD_LABEL(ret, tmp_label);
8655
8656 ADD_LABEL(ret, redo_label);
8657 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8658
8659 const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8660 add_trace_branch_coverage(
8661 iseq,
8662 ret,
8663 nd_code_loc(coverage_node),
8664 nd_node_id(coverage_node),
8665 0,
8666 "body",
8667 branches);
8668
8669 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8670 ADD_LABEL(ret, next_label); /* next */
8671
8672 if (type == NODE_WHILE) {
8673 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8674 redo_label, end_label));
8675 }
8676 else {
8677 /* until */
8678 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8679 end_label, redo_label));
8680 }
8681
8682 ADD_LABEL(ret, end_label);
8683 ADD_ADJUST_RESTORE(ret, adjust_label);
8684
8685 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8686 /* ADD_INSN(ret, line_node, putundef); */
8687 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8688 return COMPILE_NG;
8689 }
8690 else {
8691 ADD_INSN(ret, line_node, putnil);
8692 }
8693
8694 ADD_LABEL(ret, break_label); /* break */
8695
8696 if (popped) {
8697 ADD_INSN(ret, line_node, pop);
8698 }
8699
8700 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8701 break_label);
8702 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8703 next_catch_label);
8704 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8705 ISEQ_COMPILE_DATA(iseq)->redo_label);
8706
8707 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8708 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8709 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8710 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8711 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8712 return COMPILE_OK;
8713}
8714
8715static int
8716compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8717{
8718 const int line = nd_line(node);
8719 const NODE *line_node = node;
8720 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8721 LABEL *retry_label = NEW_LABEL(line);
8722 LABEL *retry_end_l = NEW_LABEL(line);
8723 const rb_iseq_t *child_iseq;
8724
8725 ADD_LABEL(ret, retry_label);
8726 if (nd_type_p(node, NODE_FOR)) {
8727 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8728
8729 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8730 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8731 ISEQ_TYPE_BLOCK, line);
8732 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8733 }
8734 else {
8735 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8736 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8737 ISEQ_TYPE_BLOCK, line);
8738 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8739 }
8740
8741 {
8742 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8743 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8744 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8745 //
8746 // Normally, "send" instruction is at the last.
8747 // However, qcall under branch coverage measurement adds some instructions after the "send".
8748 //
8749 // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8750 INSN *iobj;
8751 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8752 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8753 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8754 iobj = (INSN*) get_prev_insn(iobj);
8755 }
8756 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8757
8758 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8759 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8760 if (&iobj->link == LAST_ELEMENT(ret)) {
8761 ret->last = (LINK_ELEMENT*) retry_end_l;
8762 }
8763 }
8764
8765 if (popped) {
8766 ADD_INSN(ret, line_node, pop);
8767 }
8768
8769 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8770
8771 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8772 return COMPILE_OK;
8773}
8774
8775static int
8776compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8777{
8778 /* massign to var in "for"
8779 * (args.length == 1 && Array.try_convert(args[0])) || args
8780 */
8781 const NODE *line_node = node;
8782 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8783 LABEL *not_single = NEW_LABEL(nd_line(var));
8784 LABEL *not_ary = NEW_LABEL(nd_line(var));
8785 CHECK(COMPILE(ret, "for var", var));
8786 ADD_INSN(ret, line_node, dup);
8787 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8788 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8789 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8790 ADD_INSNL(ret, line_node, branchunless, not_single);
8791 ADD_INSN(ret, line_node, dup);
8792 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8793 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8794 ADD_INSN1(ret, line_node, putobject, rb_cArray);
8795 ADD_INSN(ret, line_node, swap);
8796 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8797 ADD_INSN(ret, line_node, dup);
8798 ADD_INSNL(ret, line_node, branchunless, not_ary);
8799 ADD_INSN(ret, line_node, swap);
8800 ADD_LABEL(ret, not_ary);
8801 ADD_INSN(ret, line_node, pop);
8802 ADD_LABEL(ret, not_single);
8803 return COMPILE_OK;
8804}
8805
8806static int
8807compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8808{
8809 const NODE *line_node = node;
8810 unsigned long throw_flag = 0;
8811
8812 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8813 /* while/until */
8814 LABEL *splabel = NEW_LABEL(0);
8815 ADD_LABEL(ret, splabel);
8816 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8817 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8818 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8819 add_ensure_iseq(ret, iseq, 0);
8820 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8821 ADD_ADJUST_RESTORE(ret, splabel);
8822
8823 if (!popped) {
8824 ADD_INSN(ret, line_node, putnil);
8825 }
8826 }
8827 else {
8828 const rb_iseq_t *ip = iseq;
8829
8830 while (ip) {
8831 if (!ISEQ_COMPILE_DATA(ip)) {
8832 ip = 0;
8833 break;
8834 }
8835
8836 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8837 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8838 }
8839 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8840 throw_flag = 0;
8841 }
8842 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8843 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8844 return COMPILE_NG;
8845 }
8846 else {
8847 ip = ISEQ_BODY(ip)->parent_iseq;
8848 continue;
8849 }
8850
8851 /* escape from block */
8852 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8853 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8854 if (popped) {
8855 ADD_INSN(ret, line_node, pop);
8856 }
8857 return COMPILE_OK;
8858 }
8859 COMPILE_ERROR(ERROR_ARGS "Invalid break");
8860 return COMPILE_NG;
8861 }
8862 return COMPILE_OK;
8863}
8864
8865static int
8866compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8867{
8868 const NODE *line_node = node;
8869 unsigned long throw_flag = 0;
8870
8871 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8872 LABEL *splabel = NEW_LABEL(0);
8873 debugs("next in while loop\n");
8874 ADD_LABEL(ret, splabel);
8875 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8876 add_ensure_iseq(ret, iseq, 0);
8877 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8878 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8879 ADD_ADJUST_RESTORE(ret, splabel);
8880 if (!popped) {
8881 ADD_INSN(ret, line_node, putnil);
8882 }
8883 }
8884 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8885 LABEL *splabel = NEW_LABEL(0);
8886 debugs("next in block\n");
8887 ADD_LABEL(ret, splabel);
8888 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8889 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8890 add_ensure_iseq(ret, iseq, 0);
8891 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8892 ADD_ADJUST_RESTORE(ret, splabel);
8893
8894 if (!popped) {
8895 ADD_INSN(ret, line_node, putnil);
8896 }
8897 }
8898 else {
8899 const rb_iseq_t *ip = iseq;
8900
8901 while (ip) {
8902 if (!ISEQ_COMPILE_DATA(ip)) {
8903 ip = 0;
8904 break;
8905 }
8906
8907 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8908 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8909 /* while loop */
8910 break;
8911 }
8912 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8913 break;
8914 }
8915 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8916 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8917 return COMPILE_NG;
8918 }
8919
8920 ip = ISEQ_BODY(ip)->parent_iseq;
8921 }
8922 if (ip != 0) {
8923 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8924 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8925
8926 if (popped) {
8927 ADD_INSN(ret, line_node, pop);
8928 }
8929 }
8930 else {
8931 COMPILE_ERROR(ERROR_ARGS "Invalid next");
8932 return COMPILE_NG;
8933 }
8934 }
8935 return COMPILE_OK;
8936}
8937
8938static int
8939compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8940{
8941 const NODE *line_node = node;
8942
8943 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8944 LABEL *splabel = NEW_LABEL(0);
8945 debugs("redo in while");
8946 ADD_LABEL(ret, splabel);
8947 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8948 add_ensure_iseq(ret, iseq, 0);
8949 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8950 ADD_ADJUST_RESTORE(ret, splabel);
8951 if (!popped) {
8952 ADD_INSN(ret, line_node, putnil);
8953 }
8954 }
8955 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8956 LABEL *splabel = NEW_LABEL(0);
8957
8958 debugs("redo in block");
8959 ADD_LABEL(ret, splabel);
8960 add_ensure_iseq(ret, iseq, 0);
8961 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8962 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8963 ADD_ADJUST_RESTORE(ret, splabel);
8964
8965 if (!popped) {
8966 ADD_INSN(ret, line_node, putnil);
8967 }
8968 }
8969 else {
8970 const rb_iseq_t *ip = iseq;
8971
8972 while (ip) {
8973 if (!ISEQ_COMPILE_DATA(ip)) {
8974 ip = 0;
8975 break;
8976 }
8977
8978 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8979 break;
8980 }
8981 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8982 break;
8983 }
8984 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8985 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8986 return COMPILE_NG;
8987 }
8988
8989 ip = ISEQ_BODY(ip)->parent_iseq;
8990 }
8991 if (ip != 0) {
8992 ADD_INSN(ret, line_node, putnil);
8993 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8994
8995 if (popped) {
8996 ADD_INSN(ret, line_node, pop);
8997 }
8998 }
8999 else {
9000 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
9001 return COMPILE_NG;
9002 }
9003 }
9004 return COMPILE_OK;
9005}
9006
9007static int
9008compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9009{
9010 const NODE *line_node = node;
9011
9012 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
9013 ADD_INSN(ret, line_node, putnil);
9014 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
9015
9016 if (popped) {
9017 ADD_INSN(ret, line_node, pop);
9018 }
9019 }
9020 else {
9021 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
9022 return COMPILE_NG;
9023 }
9024 return COMPILE_OK;
9025}
9026
9027static int
9028compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9029{
9030 const int line = nd_line(node);
9031 const NODE *line_node = node;
9032 LABEL *lstart = NEW_LABEL(line);
9033 LABEL *lend = NEW_LABEL(line);
9034 LABEL *lcont = NEW_LABEL(line);
9035 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
9036 rb_str_concat(rb_str_new2("rescue in "),
9037 ISEQ_BODY(iseq)->location.label),
9038 ISEQ_TYPE_RESCUE, line);
9039
9040 lstart->rescued = LABEL_RESCUE_BEG;
9041 lend->rescued = LABEL_RESCUE_END;
9042 ADD_LABEL(ret, lstart);
9043
9044 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
9045 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
9046 {
9047 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
9048 }
9049 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
9050
9051 ADD_LABEL(ret, lend);
9052 if (RNODE_RESCUE(node)->nd_else) {
9053 ADD_INSN(ret, line_node, pop);
9054 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
9055 }
9056 ADD_INSN(ret, line_node, nop);
9057 ADD_LABEL(ret, lcont);
9058
9059 if (popped) {
9060 ADD_INSN(ret, line_node, pop);
9061 }
9062
9063 /* register catch entry */
9064 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
9065 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
9066 return COMPILE_OK;
9067}
9068
9069static int
9070compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9071{
9072 const int line = nd_line(node);
9073 const NODE *line_node = node;
9074 const NODE *resq = node;
9075 const NODE *narg;
9076 LABEL *label_miss, *label_hit;
9077
9078 while (resq) {
9079 label_miss = NEW_LABEL(line);
9080 label_hit = NEW_LABEL(line);
9081
9082 narg = RNODE_RESBODY(resq)->nd_args;
9083 if (narg) {
9084 switch (nd_type(narg)) {
9085 case NODE_LIST:
9086 while (narg) {
9087 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
9088 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
9089 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
9090 ADD_INSNL(ret, line_node, branchif, label_hit);
9091 narg = RNODE_LIST(narg)->nd_next;
9092 }
9093 break;
9094 case NODE_SPLAT:
9095 case NODE_ARGSCAT:
9096 case NODE_ARGSPUSH:
9097 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
9098 CHECK(COMPILE(ret, "rescue/cond splat", narg));
9099 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
9100 ADD_INSNL(ret, line_node, branchif, label_hit);
9101 break;
9102 default:
9103 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
9104 }
9105 }
9106 else {
9107 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
9108 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
9109 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
9110 ADD_INSNL(ret, line_node, branchif, label_hit);
9111 }
9112 ADD_INSNL(ret, line_node, jump, label_miss);
9113 ADD_LABEL(ret, label_hit);
9114 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
9115
9116 if (RNODE_RESBODY(resq)->nd_exc_var) {
9117 CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
9118 }
9119
9120 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) {
9121 // empty body
9122 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
9123 }
9124 else {
9125 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
9126 }
9127
9128 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
9129 ADD_INSN(ret, line_node, nop);
9130 }
9131 ADD_INSN(ret, line_node, leave);
9132 ADD_LABEL(ret, label_miss);
9133 resq = RNODE_RESBODY(resq)->nd_next;
9134 }
9135 return COMPILE_OK;
9136}
9137
9138static int
9139compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9140{
9141 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
9142 const NODE *line_node = node;
9143 DECL_ANCHOR(ensr);
9144 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
9145 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
9146 ISEQ_TYPE_ENSURE, line);
9147 LABEL *lstart = NEW_LABEL(line);
9148 LABEL *lend = NEW_LABEL(line);
9149 LABEL *lcont = NEW_LABEL(line);
9150 LINK_ELEMENT *last;
9151 int last_leave = 0;
9152 struct ensure_range er;
9154 struct ensure_range *erange;
9155
9156 INIT_ANCHOR(ensr);
9157 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
9158 last = ensr->last;
9159 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
9160
9161 er.begin = lstart;
9162 er.end = lend;
9163 er.next = 0;
9164 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
9165
9166 ADD_LABEL(ret, lstart);
9167 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
9168 ADD_LABEL(ret, lend);
9169 ADD_SEQ(ret, ensr);
9170 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
9171 ADD_LABEL(ret, lcont);
9172 if (last_leave) ADD_INSN(ret, line_node, pop);
9173
9174 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
9175 if (lstart->link.next != &lend->link) {
9176 while (erange) {
9177 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
9178 ensure, lcont);
9179 erange = erange->next;
9180 }
9181 }
9182
9183 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
9184 return COMPILE_OK;
9185}
9186
9187static int
9188compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9189{
9190 const NODE *line_node = node;
9191
9192 if (iseq) {
9193 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
9194 const rb_iseq_t *is = iseq;
9195 enum rb_iseq_type t = type;
9196 const NODE *retval = RNODE_RETURN(node)->nd_stts;
9197 LABEL *splabel = 0;
9198
9199 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
9200 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
9201 t = ISEQ_BODY(is)->type;
9202 }
9203 switch (t) {
9204 case ISEQ_TYPE_TOP:
9205 case ISEQ_TYPE_MAIN:
9206 if (retval) {
9207 rb_warn("argument of top-level return is ignored");
9208 }
9209 if (is == iseq) {
9210 /* plain top-level, leave directly */
9211 type = ISEQ_TYPE_METHOD;
9212 }
9213 break;
9214 default:
9215 break;
9216 }
9217
9218 if (type == ISEQ_TYPE_METHOD) {
9219 splabel = NEW_LABEL(0);
9220 ADD_LABEL(ret, splabel);
9221 ADD_ADJUST(ret, line_node, 0);
9222 }
9223
9224 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
9225
9226 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
9227 add_ensure_iseq(ret, iseq, 1);
9228 ADD_TRACE(ret, RUBY_EVENT_RETURN);
9229 ADD_INSN(ret, line_node, leave);
9230 ADD_ADJUST_RESTORE(ret, splabel);
9231
9232 if (!popped) {
9233 ADD_INSN(ret, line_node, putnil);
9234 }
9235 }
9236 else {
9237 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
9238 if (popped) {
9239 ADD_INSN(ret, line_node, pop);
9240 }
9241 }
9242 }
9243 return COMPILE_OK;
9244}
9245
9246static bool
9247drop_unreachable_return(LINK_ANCHOR *ret)
9248{
9249 LINK_ELEMENT *i = ret->last, *last;
9250 if (!i) return false;
9251 if (IS_TRACE(i)) i = i->prev;
9252 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
9253 last = i = i->prev;
9254 if (IS_ADJUST(i)) i = i->prev;
9255 if (!IS_INSN(i)) return false;
9256 switch (INSN_OF(i)) {
9257 case BIN(leave):
9258 case BIN(jump):
9259 break;
9260 default:
9261 return false;
9262 }
9263 (ret->last = last->prev)->next = NULL;
9264 return true;
9265}
9266
9267static int
9268compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9269{
9270 CHECK(COMPILE_(ret, "nd_body", node, popped));
9271
9272 if (!popped && !all_string_result_p(node)) {
9273 const NODE *line_node = node;
9274 const unsigned int flag = VM_CALL_FCALL;
9275
9276 // Note, this dup could be removed if we are willing to change anytostring. It pops
9277 // two VALUEs off the stack when it could work by replacing the top most VALUE.
9278 ADD_INSN(ret, line_node, dup);
9279 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
9280 ADD_INSN(ret, line_node, anytostring);
9281 }
9282 return COMPILE_OK;
9283}
9284
9285static void
9286compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
9287{
9288 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
9289
9290 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
9291 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
9292}
9293
9294static LABEL *
9295qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
9296{
9297 LABEL *else_label = NEW_LABEL(nd_line(line_node));
9298 VALUE br = 0;
9299
9300 br = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), "&.");
9301 *branches = br;
9302 ADD_INSN(recv, line_node, dup);
9303 ADD_INSNL(recv, line_node, branchnil, else_label);
9304 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
9305 return else_label;
9306}
9307
9308static void
9309qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
9310{
9311 LABEL *end_label;
9312 if (!else_label) return;
9313 end_label = NEW_LABEL(nd_line(line_node));
9314 ADD_INSNL(ret, line_node, jump, end_label);
9315 ADD_LABEL(ret, else_label);
9316 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
9317 ADD_LABEL(ret, end_label);
9318}
9319
9320static int
9321compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
9322{
9323 /* optimization shortcut
9324 * "literal".freeze -> opt_str_freeze("literal")
9325 */
9326 if (get_nd_recv(node) &&
9327 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
9328 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
9329 get_nd_args(node) == NULL &&
9330 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
9331 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
9332 VALUE str = get_string_value(get_nd_recv(node));
9333 if (get_node_call_nd_mid(node) == idUMinus) {
9334 ADD_INSN2(ret, line_node, opt_str_uminus, str,
9335 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
9336 }
9337 else {
9338 ADD_INSN2(ret, line_node, opt_str_freeze, str,
9339 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
9340 }
9341 RB_OBJ_WRITTEN(iseq, Qundef, str);
9342 if (popped) {
9343 ADD_INSN(ret, line_node, pop);
9344 }
9345 return TRUE;
9346 }
9347 return FALSE;
9348}
9349
9350static int
9351iseq_has_builtin_function_table(const rb_iseq_t *iseq)
9352{
9353 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
9354}
9355
9356static const struct rb_builtin_function *
9357iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
9358{
9359 int i;
9360 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
9361 for (i=0; table[i].index != -1; i++) {
9362 if (strcmp(table[i].name, name) == 0) {
9363 return &table[i];
9364 }
9365 }
9366 return NULL;
9367}
9368
9369static const char *
9370iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
9371{
9372 const char *name = rb_id2name(mid);
9373 static const char prefix[] = "__builtin_";
9374 const size_t prefix_len = sizeof(prefix) - 1;
9375
9376 switch (type) {
9377 case NODE_CALL:
9378 if (recv) {
9379 switch (nd_type(recv)) {
9380 case NODE_VCALL:
9381 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
9382 return name;
9383 }
9384 break;
9385 case NODE_CONST:
9386 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
9387 return name;
9388 }
9389 break;
9390 default: break;
9391 }
9392 }
9393 break;
9394 case NODE_VCALL:
9395 case NODE_FCALL:
9396 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
9397 return &name[prefix_len];
9398 }
9399 break;
9400 default: break;
9401 }
9402 return NULL;
9403}
9404
9405static int
9406delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
9407{
9408
9409 if (argc == 0) {
9410 *pstart_index = 0;
9411 return TRUE;
9412 }
9413 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
9414 unsigned int start=0;
9415
9416 // local_table: [p1, p2, p3, l1, l2, l3]
9417 // arguments: [p3, l1, l2] -> 2
9418 for (start = 0;
9419 argc + start <= ISEQ_BODY(iseq)->local_table_size;
9420 start++) {
9421 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
9422
9423 for (unsigned int i=start; i-start<argc; i++) {
9424 if (IS_INSN(elem) &&
9425 INSN_OF(elem) == BIN(getlocal)) {
9426 int local_index = FIX2INT(OPERAND_AT(elem, 0));
9427 int local_level = FIX2INT(OPERAND_AT(elem, 1));
9428
9429 if (local_level == 0) {
9430 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
9431 if (0) { // for debug
9432 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
9433 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
9434 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9435 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
9436 }
9437 if (i == index) {
9438 elem = elem->next;
9439 continue; /* for */
9440 }
9441 else {
9442 goto next;
9443 }
9444 }
9445 else {
9446 goto fail; // level != 0 is unsupported
9447 }
9448 }
9449 else {
9450 goto fail; // insn is not a getlocal
9451 }
9452 }
9453 goto success;
9454 next:;
9455 }
9456 fail:
9457 return FALSE;
9458 success:
9459 *pstart_index = start;
9460 return TRUE;
9461 }
9462 else {
9463 return FALSE;
9464 }
9465}
9466
9467static int
9468compile_builtin_attr_symbol(rb_iseq_t *iseq, VALUE symbol)
9469{
9470 VALUE string = rb_sym2str(symbol);
9471 if (rb_streql_lit(string, "leaf")) {
9472 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9473 }
9474 else if (rb_streql_lit(string, "inline_block")) {
9475 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9476 }
9477 else if (rb_streql_lit(string, "use_block")) {
9478 iseq_set_use_block(iseq);
9479 }
9480 else if (rb_streql_lit(string, "c_trace")) {
9481 // Let the iseq act like a C method in backtraces
9482 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9483 }
9484 else if (rb_streql_lit(string, "without_interrupts")) {
9485 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_WITHOUT_INTERRUPTS;
9486 }
9487 else if (rb_streql_lit(string, "caller_user_box")) {
9488 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_CALLER_USER_BOX;
9489 }
9490 else if (rb_streql_lit(string, "always_inline")) {
9491 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_ALWAYS_INLINE;
9492 }
9493 else {
9494 return COMPILE_NG;
9495 }
9496 return COMPILE_OK;
9497}
9498
9499// Compile Primitive.attr! :leaf, ...
9500static int
9501compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9502{
9503 VALUE symbol;
9504 if (!node) goto no_arg;
9505 while (node) {
9506 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9507 const NODE *next = RNODE_LIST(node)->nd_next;
9508
9509 node = RNODE_LIST(node)->nd_head;
9510 if (!node) goto no_arg;
9511 switch (nd_type(node)) {
9512 case NODE_SYM:
9513 symbol = rb_node_sym_string_val(node);
9514 break;
9515 default:
9516 goto bad_arg;
9517 }
9518
9519 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9520 if (compile_builtin_attr_symbol(iseq, symbol) != COMPILE_OK) goto unknown_arg;
9521 node = next;
9522 }
9523 return COMPILE_OK;
9524 no_arg:
9525 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9526 return COMPILE_NG;
9527 non_symbol_arg:
9528 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9529 return COMPILE_NG;
9530 unknown_arg:
9531 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %" PRIsVALUE, symbol);
9532 return COMPILE_NG;
9533 bad_arg:
9534 UNKNOWN_NODE("attr!", node, COMPILE_NG);
9535}
9536
9537static int
9538compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9539{
9540 VALUE name;
9541
9542 if (!node) goto no_arg;
9543 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9544 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9545 node = RNODE_LIST(node)->nd_head;
9546 if (!node) goto no_arg;
9547 switch (nd_type(node)) {
9548 case NODE_SYM:
9549 name = rb_node_sym_string_val(node);
9550 break;
9551 default:
9552 goto bad_arg;
9553 }
9554 if (!SYMBOL_P(name)) goto non_symbol_arg;
9555 if (!popped) {
9556 compile_lvar(iseq, ret, line_node, SYM2ID(name));
9557 }
9558 return COMPILE_OK;
9559 no_arg:
9560 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9561 return COMPILE_NG;
9562 too_many_arg:
9563 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9564 return COMPILE_NG;
9565 non_symbol_arg:
9566 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9567 rb_builtin_class_name(name));
9568 return COMPILE_NG;
9569 bad_arg:
9570 UNKNOWN_NODE("arg!", node, COMPILE_NG);
9571}
9572
9573static NODE *
9574mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9575{
9576 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9577 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9578 return RNODE_IF(node)->nd_body;
9579 }
9580 else {
9581 rb_bug("mandatory_node: can't find mandatory node");
9582 }
9583}
9584
9585static int
9586compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9587{
9588 // arguments
9589 struct rb_args_info args = {
9590 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9591 };
9592 rb_node_args_t args_node;
9593 rb_node_init(RNODE(&args_node), NODE_ARGS);
9594 args_node.nd_ainfo = args;
9595
9596 // local table without non-mandatory parameters
9597 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9598 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9599
9600 VALUE idtmp = 0;
9601 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9602 tbl->size = table_size;
9603
9604 int i;
9605
9606 // lead parameters
9607 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9608 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9609 }
9610 // local variables
9611 for (; i<table_size; i++) {
9612 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9613 }
9614
9615 rb_node_scope_t scope_node;
9616 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9617 scope_node.nd_tbl = tbl;
9618 scope_node.nd_body = mandatory_node(iseq, node);
9619 scope_node.nd_parent = NULL;
9620 scope_node.nd_args = &args_node;
9621
9622 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9623
9624 const rb_iseq_t *mandatory_only_iseq =
9625 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9626 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9627 nd_line(line_node), NULL, 0,
9628 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9629 ISEQ_SCRIPT_LINES(iseq));
9630 RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
9631
9632 ALLOCV_END(idtmp);
9633 return COMPILE_OK;
9634}
9635
9636static int
9637compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9638 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9639{
9640 NODE *args_node = get_nd_args(node);
9641
9642 if (parent_block != NULL) {
9643 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9644 return COMPILE_NG;
9645 }
9646 else {
9647# define BUILTIN_INLINE_PREFIX "_bi"
9648 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9649 bool cconst = false;
9650 retry:;
9651 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9652
9653 if (bf == NULL) {
9654 if (strcmp("cstmt!", builtin_func) == 0 ||
9655 strcmp("cexpr!", builtin_func) == 0) {
9656 // ok
9657 }
9658 else if (strcmp("cconst!", builtin_func) == 0) {
9659 cconst = true;
9660 }
9661 else if (strcmp("cinit!", builtin_func) == 0) {
9662 // ignore
9663 return COMPILE_OK;
9664 }
9665 else if (strcmp("attr!", builtin_func) == 0) {
9666 return compile_builtin_attr(iseq, args_node);
9667 }
9668 else if (strcmp("arg!", builtin_func) == 0) {
9669 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9670 }
9671 else if (strcmp("mandatory_only?", builtin_func) == 0) {
9672 if (popped) {
9673 rb_bug("mandatory_only? should be in if condition");
9674 }
9675 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9676 rb_bug("mandatory_only? should be put on top");
9677 }
9678
9679 ADD_INSN1(ret, line_node, putobject, Qfalse);
9680 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9681 }
9682 else if (strcmp("local_self!", builtin_func) == 0) {
9683 // Push the local named "self" (e.g. the `self:` keyword
9684 // parameter of Ractor.shareable_proc) onto the stack.
9685 ID id_self;
9686 CONST_ID(id_self, "self");
9687 compile_lvar(iseq, ret, line_node, id_self);
9688 return COMPILE_OK;
9689 }
9690 else if (1) {
9691 rb_bug("can't find builtin function:%s", builtin_func);
9692 }
9693 else {
9694 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9695 return COMPILE_NG;
9696 }
9697
9698 int inline_index = nd_line(node);
9699 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9700 builtin_func = inline_func;
9701 args_node = NULL;
9702 goto retry;
9703 }
9704
9705 if (cconst) {
9706 typedef VALUE(*builtin_func0)(void *, VALUE);
9707 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9708 ADD_INSN1(ret, line_node, putobject, const_val);
9709 return COMPILE_OK;
9710 }
9711
9712 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9713
9714 unsigned int flag = 0;
9715 struct rb_callinfo_kwarg *keywords = NULL;
9716 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9717
9718 if (FIX2INT(argc) != bf->argc) {
9719 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9720 builtin_func, bf->argc, FIX2INT(argc));
9721 return COMPILE_NG;
9722 }
9723
9724 unsigned int start_index;
9725 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9726 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9727 }
9728 else {
9729 ADD_SEQ(ret, args);
9730 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9731 }
9732
9733 if (popped) ADD_INSN(ret, line_node, pop);
9734 return COMPILE_OK;
9735 }
9736}
9737
9738static int
9739compile_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)
9740{
9741 /* call: obj.method(...)
9742 * fcall: func(...)
9743 * vcall: func
9744 */
9745 DECL_ANCHOR(recv);
9746 DECL_ANCHOR(args);
9747 ID mid = get_node_call_nd_mid(node);
9748 VALUE argc;
9749 unsigned int flag = 0;
9750 struct rb_callinfo_kwarg *keywords = NULL;
9751 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9752 LABEL *else_label = NULL;
9753 VALUE branches = Qfalse;
9754
9755 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9756
9757 INIT_ANCHOR(recv);
9758 INIT_ANCHOR(args);
9759
9760#if OPT_SUPPORT_JOKE
9761 if (nd_type_p(node, NODE_VCALL)) {
9762 ID id_bitblt;
9763 ID id_answer;
9764
9765 CONST_ID(id_bitblt, "bitblt");
9766 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9767
9768 if (mid == id_bitblt) {
9769 ADD_INSN(ret, line_node, bitblt);
9770 return COMPILE_OK;
9771 }
9772 else if (mid == id_answer) {
9773 ADD_INSN(ret, line_node, answer);
9774 return COMPILE_OK;
9775 }
9776 }
9777 /* only joke */
9778 {
9779 ID goto_id;
9780 ID label_id;
9781
9782 CONST_ID(goto_id, "__goto__");
9783 CONST_ID(label_id, "__label__");
9784
9785 if (nd_type_p(node, NODE_FCALL) &&
9786 (mid == goto_id || mid == label_id)) {
9787 LABEL *label;
9788 st_data_t data;
9789 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9790 VALUE label_name;
9791
9792 if (!labels_table) {
9793 labels_table = st_init_numtable();
9794 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9795 }
9796 {
9797 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9798 return COMPILE_NG;
9799 }
9800
9801 if (mid == goto_id) {
9802 ADD_INSNL(ret, line_node, jump, label);
9803 }
9804 else {
9805 ADD_LABEL(ret, label);
9806 }
9807 return COMPILE_OK;
9808 }
9809 }
9810#endif
9811
9812 const char *builtin_func;
9813 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9814 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9815 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9816 }
9817
9818 /* receiver */
9819 if (!assume_receiver) {
9820 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9821 int idx, level;
9822
9823 if ((mid == idCall || mid == idAREF || mid == idYield || mid == idEqq) &&
9824 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9825 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9826 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9827 }
9828 else if (private_recv_p(node)) {
9829 ADD_INSN(recv, node, putself);
9830 flag |= VM_CALL_FCALL;
9831 }
9832 else {
9833 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9834 }
9835
9836 if (type == NODE_QCALL) {
9837 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9838 }
9839 }
9840 else if (type == NODE_FCALL || type == NODE_VCALL) {
9841 ADD_CALL_RECEIVER(recv, line_node);
9842 }
9843 }
9844
9845 /* args */
9846 if (type != NODE_VCALL) {
9847 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9848 CHECK(!NIL_P(argc));
9849 }
9850 else {
9851 argc = INT2FIX(0);
9852 }
9853
9854 ADD_SEQ(ret, recv);
9855
9856 bool inline_new = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction &&
9857 mid == rb_intern("new") &&
9858 parent_block == NULL &&
9859 !(flag & VM_CALL_ARGS_BLOCKARG);
9860
9861 if (inline_new) {
9862 ADD_INSN(ret, node, putnil);
9863 ADD_INSN(ret, node, swap);
9864 }
9865
9866 ADD_SEQ(ret, args);
9867
9868 debugp_param("call args argc", argc);
9869 debugp_param("call method", ID2SYM(mid));
9870
9871 switch ((int)type) {
9872 case NODE_VCALL:
9873 flag |= VM_CALL_VCALL;
9874 /* VCALL is funcall, so fall through */
9875 case NODE_FCALL:
9876 flag |= VM_CALL_FCALL;
9877 }
9878
9879 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9880 ADD_INSN(ret, line_node, splatkw);
9881 }
9882
9883 LABEL *not_basic_new = NEW_LABEL(nd_line(node));
9884 LABEL *not_basic_new_finish = NEW_LABEL(nd_line(node));
9885
9886 if (inline_new) {
9887 // Jump unless the receiver uses the "basic" implementation of "new"
9888 VALUE ci;
9889 if (flag & VM_CALL_FORWARDING) {
9890 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc) + 1, flag, keywords, 0);
9891 }
9892 else {
9893 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc), flag, keywords, 0);
9894 }
9895 ADD_INSN2(ret, node, opt_new, ci, not_basic_new);
9896 LABEL_REF(not_basic_new);
9897
9898 // optimized path
9899 ADD_SEND_R(ret, line_node, rb_intern("initialize"), argc, parent_block, INT2FIX(flag | VM_CALL_FCALL), keywords);
9900 ADD_INSNL(ret, line_node, jump, not_basic_new_finish);
9901
9902 ADD_LABEL(ret, not_basic_new);
9903 // Fall back to normal send
9904 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9905 ADD_INSN(ret, line_node, swap);
9906
9907 ADD_LABEL(ret, not_basic_new_finish);
9908 ADD_INSN(ret, line_node, pop);
9909 }
9910 else {
9911 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9912 }
9913
9914 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9915 if (popped) {
9916 ADD_INSN(ret, line_node, pop);
9917 }
9918 return COMPILE_OK;
9919}
9920
9921static int
9922compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9923{
9924 const int line = nd_line(node);
9925 VALUE argc;
9926 unsigned int flag = 0;
9927 int asgnflag = 0;
9928 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9929
9930 /*
9931 * a[x] (op)= y
9932 *
9933 * nil # nil
9934 * eval a # nil a
9935 * eval x # nil a x
9936 * dupn 2 # nil a x a x
9937 * send :[] # nil a x a[x]
9938 * eval y # nil a x a[x] y
9939 * send op # nil a x ret
9940 * setn 3 # ret a x ret
9941 * send []= # ret ?
9942 * pop # ret
9943 */
9944
9945 /*
9946 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9947 * NODE_OP_ASGN nd_recv
9948 * nd_args->nd_head
9949 * nd_args->nd_body
9950 * nd_mid
9951 */
9952
9953 if (!popped) {
9954 ADD_INSN(ret, node, putnil);
9955 }
9956 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9957 CHECK(asgnflag != -1);
9958 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9959 case NODE_ZLIST:
9960 argc = INT2FIX(0);
9961 break;
9962 default:
9963 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9964 CHECK(!NIL_P(argc));
9965 }
9966 int dup_argn = FIX2INT(argc) + 1;
9967 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9968 flag |= asgnflag;
9969 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9970
9971 if (id == idOROP || id == idANDOP) {
9972 /* a[x] ||= y or a[x] &&= y
9973
9974 unless/if a[x]
9975 a[x]= y
9976 else
9977 nil
9978 end
9979 */
9980 LABEL *label = NEW_LABEL(line);
9981 LABEL *lfin = NEW_LABEL(line);
9982
9983 ADD_INSN(ret, node, dup);
9984 if (id == idOROP) {
9985 ADD_INSNL(ret, node, branchif, label);
9986 }
9987 else { /* idANDOP */
9988 ADD_INSNL(ret, node, branchunless, label);
9989 }
9990 ADD_INSN(ret, node, pop);
9991
9992 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9993 if (!popped) {
9994 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9995 }
9996 if (flag & VM_CALL_ARGS_SPLAT) {
9997 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9998 ADD_INSN(ret, node, swap);
9999 ADD_INSN1(ret, node, splatarray, Qtrue);
10000 ADD_INSN(ret, node, swap);
10001 flag |= VM_CALL_ARGS_SPLAT_MUT;
10002 }
10003 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
10004 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
10005 }
10006 else {
10007 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
10008 }
10009 ADD_INSN(ret, node, pop);
10010 ADD_INSNL(ret, node, jump, lfin);
10011 ADD_LABEL(ret, label);
10012 if (!popped) {
10013 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
10014 }
10015 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
10016 ADD_LABEL(ret, lfin);
10017 }
10018 else {
10019 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
10020 ADD_SEND(ret, node, id, INT2FIX(1));
10021 if (!popped) {
10022 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
10023 }
10024 if (flag & VM_CALL_ARGS_SPLAT) {
10025 if (flag & VM_CALL_KW_SPLAT) {
10026 ADD_INSN1(ret, node, topn, INT2FIX(2));
10027 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
10028 ADD_INSN1(ret, node, splatarray, Qtrue);
10029 flag |= VM_CALL_ARGS_SPLAT_MUT;
10030 }
10031 ADD_INSN(ret, node, swap);
10032 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
10033 ADD_INSN1(ret, node, setn, INT2FIX(2));
10034 ADD_INSN(ret, node, pop);
10035 }
10036 else {
10037 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
10038 ADD_INSN(ret, node, swap);
10039 ADD_INSN1(ret, node, splatarray, Qtrue);
10040 ADD_INSN(ret, node, swap);
10041 flag |= VM_CALL_ARGS_SPLAT_MUT;
10042 }
10043 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
10044 }
10045 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
10046 }
10047 else {
10048 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
10049 }
10050 ADD_INSN(ret, node, pop);
10051 }
10052 return COMPILE_OK;
10053}
10054
10055static int
10056compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10057{
10058 const int line = nd_line(node);
10059 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
10060 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
10061 int asgnflag;
10062 LABEL *lfin = NEW_LABEL(line);
10063 LABEL *lcfin = NEW_LABEL(line);
10064 LABEL *lskip = 0;
10065 /*
10066 class C; attr_accessor :c; end
10067 r = C.new
10068 r.a &&= v # asgn2
10069
10070 eval r # r
10071 dup # r r
10072 eval r.a # r o
10073
10074 # or
10075 dup # r o o
10076 if lcfin # r o
10077 pop # r
10078 eval v # r v
10079 swap # v r
10080 topn 1 # v r v
10081 send a= # v ?
10082 jump lfin # v ?
10083
10084 lcfin: # r o
10085 swap # o r
10086
10087 lfin: # o ?
10088 pop # o
10089
10090 # or (popped)
10091 if lcfin # r
10092 eval v # r v
10093 send a= # ?
10094 jump lfin # ?
10095
10096 lcfin: # r
10097
10098 lfin: # ?
10099 pop #
10100
10101 # and
10102 dup # r o o
10103 unless lcfin
10104 pop # r
10105 eval v # r v
10106 swap # v r
10107 topn 1 # v r v
10108 send a= # v ?
10109 jump lfin # v ?
10110
10111 # others
10112 eval v # r o v
10113 send ?? # r w
10114 send a= # w
10115
10116 */
10117
10118 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
10119 CHECK(asgnflag != -1);
10120 if (RNODE_OP_ASGN2(node)->nd_aid) {
10121 lskip = NEW_LABEL(line);
10122 ADD_INSN(ret, node, dup);
10123 ADD_INSNL(ret, node, branchnil, lskip);
10124 }
10125 ADD_INSN(ret, node, dup);
10126 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
10127
10128 if (atype == idOROP || atype == idANDOP) {
10129 if (!popped) {
10130 ADD_INSN(ret, node, dup);
10131 }
10132 if (atype == idOROP) {
10133 ADD_INSNL(ret, node, branchif, lcfin);
10134 }
10135 else { /* idANDOP */
10136 ADD_INSNL(ret, node, branchunless, lcfin);
10137 }
10138 if (!popped) {
10139 ADD_INSN(ret, node, pop);
10140 }
10141 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
10142 if (!popped) {
10143 ADD_INSN(ret, node, swap);
10144 ADD_INSN1(ret, node, topn, INT2FIX(1));
10145 }
10146 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
10147 ADD_INSNL(ret, node, jump, lfin);
10148
10149 ADD_LABEL(ret, lcfin);
10150 if (!popped) {
10151 ADD_INSN(ret, node, swap);
10152 }
10153
10154 ADD_LABEL(ret, lfin);
10155 }
10156 else {
10157 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
10158 ADD_SEND(ret, node, atype, INT2FIX(1));
10159 if (!popped) {
10160 ADD_INSN(ret, node, swap);
10161 ADD_INSN1(ret, node, topn, INT2FIX(1));
10162 }
10163 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
10164 }
10165 if (lskip && popped) {
10166 ADD_LABEL(ret, lskip);
10167 }
10168 ADD_INSN(ret, node, pop);
10169 if (lskip && !popped) {
10170 ADD_LABEL(ret, lskip);
10171 }
10172 return COMPILE_OK;
10173}
10174
10175static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
10176
10177static int
10178compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10179{
10180 const int line = nd_line(node);
10181 LABEL *lfin = 0;
10182 LABEL *lassign = 0;
10183 ID mid;
10184
10185 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
10186 case NODE_COLON3:
10187 ADD_INSN1(ret, node, putobject, rb_cObject);
10188 break;
10189 case NODE_COLON2:
10190 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
10191 break;
10192 default:
10193 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
10194 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
10195 return COMPILE_NG;
10196 }
10197 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
10198 /* cref */
10199 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
10200 lassign = NEW_LABEL(line);
10201 ADD_INSN(ret, node, dup); /* cref cref */
10202 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
10203 ID2SYM(mid), Qtrue); /* cref bool */
10204 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
10205 }
10206 ADD_INSN(ret, node, dup); /* cref cref */
10207 ADD_INSN1(ret, node, putobject, Qtrue);
10208 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
10209
10210 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
10211 lfin = NEW_LABEL(line);
10212 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
10213 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
10214 ADD_INSNL(ret, node, branchif, lfin);
10215 else /* idANDOP */
10216 ADD_INSNL(ret, node, branchunless, lfin);
10217 /* cref [obj] */
10218 if (!popped) ADD_INSN(ret, node, pop); /* cref */
10219 if (lassign) ADD_LABEL(ret, lassign);
10220 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
10221 /* cref value */
10222 if (popped)
10223 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
10224 else {
10225 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
10226 ADD_INSN(ret, node, swap); /* cref value value cref */
10227 }
10228 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
10229 ADD_LABEL(ret, lfin); /* cref [value] */
10230 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
10231 ADD_INSN(ret, node, pop); /* [value] */
10232 }
10233 else {
10234 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
10235 /* cref obj value */
10236 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
10237 /* cref value */
10238 ADD_INSN(ret, node, swap); /* value cref */
10239 if (!popped) {
10240 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
10241 ADD_INSN(ret, node, swap); /* value value cref */
10242 }
10243 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
10244 }
10245 return COMPILE_OK;
10246}
10247
10248static int
10249compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10250{
10251 const int line = nd_line(node);
10252 LABEL *lfin = NEW_LABEL(line);
10253 LABEL *lassign;
10254
10255 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
10256 LABEL *lfinish[2];
10257 lfinish[0] = lfin;
10258 lfinish[1] = 0;
10259 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
10260 lassign = lfinish[1];
10261 if (!lassign) {
10262 lassign = NEW_LABEL(line);
10263 }
10264 ADD_INSNL(ret, node, branchunless, lassign);
10265 }
10266 else {
10267 lassign = NEW_LABEL(line);
10268 }
10269
10270 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
10271
10272 if (!popped) {
10273 ADD_INSN(ret, node, dup);
10274 }
10275
10276 if (type == NODE_OP_ASGN_AND) {
10277 ADD_INSNL(ret, node, branchunless, lfin);
10278 }
10279 else {
10280 ADD_INSNL(ret, node, branchif, lfin);
10281 }
10282
10283 if (!popped) {
10284 ADD_INSN(ret, node, pop);
10285 }
10286
10287 ADD_LABEL(ret, lassign);
10288 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
10289 ADD_LABEL(ret, lfin);
10290 return COMPILE_OK;
10291}
10292
10293static int
10294compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10295{
10296 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10297 DECL_ANCHOR(args);
10298 int argc;
10299 unsigned int flag = 0;
10300 struct rb_callinfo_kwarg *keywords = NULL;
10301 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
10302 int use_block = 1;
10303
10304 INIT_ANCHOR(args);
10305 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
10306
10307 if (type == NODE_SUPER) {
10308 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
10309 CHECK(!NIL_P(vargc));
10310 argc = FIX2INT(vargc);
10311 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
10312 ADD_INSN(args, node, splatkw);
10313 }
10314
10315 if (flag & VM_CALL_ARGS_BLOCKARG) {
10316 use_block = 0;
10317 }
10318 }
10319 else {
10320 /* NODE_ZSUPER */
10321 int i;
10322 const rb_iseq_t *liseq = body->local_iseq;
10323 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
10324 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
10325 int lvar_level = get_lvar_level(iseq);
10326
10327 argc = local_body->param.lead_num;
10328
10329 /* normal arguments */
10330 for (i = 0; i < local_body->param.lead_num; i++) {
10331 int idx = local_body->local_table_size - i;
10332 ADD_GETLOCAL(args, node, idx, lvar_level);
10333 }
10334
10335 /* forward ... */
10336 if (local_body->param.flags.forwardable) {
10337 flag |= VM_CALL_FORWARDING;
10338 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
10339 ADD_GETLOCAL(args, node, idx, lvar_level);
10340 }
10341
10342 if (local_body->param.flags.has_opt) {
10343 /* optional arguments */
10344 int j;
10345 for (j = 0; j < local_body->param.opt_num; j++) {
10346 int idx = local_body->local_table_size - (i + j);
10347 ADD_GETLOCAL(args, node, idx, lvar_level);
10348 }
10349 i += j;
10350 argc = i;
10351 }
10352 if (local_body->param.flags.has_rest) {
10353 /* rest argument */
10354 int idx = local_body->local_table_size - local_body->param.rest_start;
10355 ADD_GETLOCAL(args, node, idx, lvar_level);
10356 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
10357
10358 argc = local_body->param.rest_start + 1;
10359 flag |= VM_CALL_ARGS_SPLAT;
10360 }
10361 if (local_body->param.flags.has_post) {
10362 /* post arguments */
10363 int post_len = local_body->param.post_num;
10364 int post_start = local_body->param.post_start;
10365
10366 if (local_body->param.flags.has_rest) {
10367 int j;
10368 for (j=0; j<post_len; j++) {
10369 int idx = local_body->local_table_size - (post_start + j);
10370 ADD_GETLOCAL(args, node, idx, lvar_level);
10371 }
10372 ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
10373 flag |= VM_CALL_ARGS_SPLAT_MUT;
10374 /* argc is settled at above */
10375 }
10376 else {
10377 int j;
10378 for (j=0; j<post_len; j++) {
10379 int idx = local_body->local_table_size - (post_start + j);
10380 ADD_GETLOCAL(args, node, idx, lvar_level);
10381 }
10382 argc = post_len + post_start;
10383 }
10384 }
10385
10386 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
10387 int local_size = local_body->local_table_size;
10388 argc++;
10389
10390 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10391
10392 if (local_body->param.flags.has_kwrest) {
10393 int idx = local_body->local_table_size - local_kwd->rest_start;
10394 ADD_GETLOCAL(args, node, idx, lvar_level);
10395 RUBY_ASSERT(local_kwd->num > 0);
10396 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
10397 }
10398 else {
10399 ADD_INSN1(args, node, newhash, INT2FIX(0));
10400 }
10401 for (i = 0; i < local_kwd->num; ++i) {
10402 ID id = local_kwd->table[i];
10403 int idx = local_size - get_local_var_idx(liseq, id);
10404 ADD_INSN1(args, node, putobject, ID2SYM(id));
10405 ADD_GETLOCAL(args, node, idx, lvar_level);
10406 }
10407 ADD_SEND(args, node, id_core_hash_merge_bang_ptr, INT2FIX(i * 2 + 1));
10408 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
10409 }
10410 else if (local_body->param.flags.has_kwrest) {
10411 int idx = local_body->local_table_size - local_kwd->rest_start;
10412 ADD_GETLOCAL(args, node, idx, lvar_level);
10413 argc++;
10414 flag |= VM_CALL_KW_SPLAT;
10415 }
10416 }
10417
10418 if (use_block && parent_block == NULL) {
10419 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10420 }
10421
10422 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
10423 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
10424 ADD_INSN(ret, node, putself);
10425 ADD_SEQ(ret, args);
10426
10427 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
10428
10429 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
10430 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
10431 }
10432 else {
10433 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
10434 }
10435
10436 if (popped) {
10437 ADD_INSN(ret, node, pop);
10438 }
10439 return COMPILE_OK;
10440}
10441
10442static int
10443compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10444{
10445 DECL_ANCHOR(args);
10446 VALUE argc;
10447 unsigned int flag = 0;
10448 struct rb_callinfo_kwarg *keywords = NULL;
10449
10450 INIT_ANCHOR(args);
10451
10452 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
10453 case ISEQ_TYPE_TOP:
10454 case ISEQ_TYPE_MAIN:
10455 case ISEQ_TYPE_CLASS:
10456 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
10457 return COMPILE_NG;
10458 default: /* valid */;
10459 }
10460
10461 if (RNODE_YIELD(node)->nd_head) {
10462 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
10463 CHECK(!NIL_P(argc));
10464 }
10465 else {
10466 argc = INT2FIX(0);
10467 }
10468
10469 ADD_SEQ(ret, args);
10470 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
10471 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10472
10473 if (popped) {
10474 ADD_INSN(ret, node, pop);
10475 }
10476
10477 int level = 0;
10478 const rb_iseq_t *tmp_iseq = iseq;
10479 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
10480 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
10481 }
10482 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
10483
10484 return COMPILE_OK;
10485}
10486
10487static int
10488compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10489{
10490 DECL_ANCHOR(recv);
10491 DECL_ANCHOR(val);
10492
10493 INIT_ANCHOR(recv);
10494 INIT_ANCHOR(val);
10495 switch ((int)type) {
10496 case NODE_MATCH:
10497 {
10498 VALUE re = rb_node_regx_string_val(node);
10500 ADD_INSN1(recv, node, putobject, re);
10501 ADD_INSN2(val, node, getspecial, INT2FIX(0),
10502 INT2FIX(0));
10503 }
10504 break;
10505 case NODE_MATCH2:
10506 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
10507 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
10508 break;
10509 case NODE_MATCH3:
10510 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
10511 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
10512 break;
10513 }
10514
10515 ADD_SEQ(ret, recv);
10516 ADD_SEQ(ret, val);
10517 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
10518
10519 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10520 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10521 }
10522
10523 if (popped) {
10524 ADD_INSN(ret, node, pop);
10525 }
10526 return COMPILE_OK;
10527}
10528
10529static int
10530compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10531{
10532 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10533 /* constant */
10534 VALUE segments;
10535 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10536 (segments = collect_const_segments(iseq, node))) {
10537 ISEQ_BODY(iseq)->ic_size++;
10538 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10539 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10540 }
10541 else {
10542 /* constant */
10543 DECL_ANCHOR(pref);
10544 DECL_ANCHOR(body);
10545
10546 INIT_ANCHOR(pref);
10547 INIT_ANCHOR(body);
10548 CHECK(compile_const_prefix(iseq, node, pref, body));
10549 if (LIST_INSN_SIZE_ZERO(pref)) {
10550 ADD_INSN(ret, node, putnil);
10551 ADD_SEQ(ret, body);
10552 }
10553 else {
10554 ADD_SEQ(ret, pref);
10555 ADD_SEQ(ret, body);
10556 }
10557 }
10558 }
10559 else {
10560 /* function call */
10561 ADD_CALL_RECEIVER(ret, node);
10562 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10563 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10564 }
10565 if (popped) {
10566 ADD_INSN(ret, node, pop);
10567 }
10568 return COMPILE_OK;
10569}
10570
10571static int
10572compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10573{
10574 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10575
10576 /* add cache insn */
10577 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10578 ISEQ_BODY(iseq)->ic_size++;
10579 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10581 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10582 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10583 }
10584 else {
10585 ADD_INSN1(ret, node, putobject, rb_cObject);
10586 ADD_INSN1(ret, node, putobject, Qtrue);
10587 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10588 }
10589
10590 if (popped) {
10591 ADD_INSN(ret, node, pop);
10592 }
10593 return COMPILE_OK;
10594}
10595
10596static int
10597compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10598{
10599 VALUE flag = INT2FIX(excl);
10600 const NODE *b = RNODE_DOT2(node)->nd_beg;
10601 const NODE *e = RNODE_DOT2(node)->nd_end;
10602
10603 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10604 if (!popped) {
10605 VALUE bv = optimized_range_item(b);
10606 VALUE ev = optimized_range_item(e);
10607 VALUE val = rb_range_new(bv, ev, excl);
10609 ADD_INSN1(ret, node, putobject, val);
10610 RB_OBJ_WRITTEN(iseq, Qundef, val);
10611 }
10612 }
10613 else {
10614 CHECK(COMPILE_(ret, "min", b, popped));
10615 CHECK(COMPILE_(ret, "max", e, popped));
10616 if (!popped) {
10617 ADD_INSN1(ret, node, newrange, flag);
10618 }
10619 }
10620 return COMPILE_OK;
10621}
10622
10623static int
10624compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10625{
10626 if (!popped) {
10627 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10628 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10629 }
10630 else {
10631 const rb_iseq_t *ip = iseq;
10632 int level = 0;
10633 while (ip) {
10634 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10635 break;
10636 }
10637 ip = ISEQ_BODY(ip)->parent_iseq;
10638 level++;
10639 }
10640 if (ip) {
10641 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10642 }
10643 else {
10644 ADD_INSN(ret, node, putnil);
10645 }
10646 }
10647 }
10648 return COMPILE_OK;
10649}
10650
10651static int
10652compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10653{
10654 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10655 LABEL *end_label = NEW_LABEL(nd_line(node));
10656 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10657
10658 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10659 /* required argument. do nothing */
10660 COMPILE_ERROR(ERROR_ARGS "unreachable");
10661 return COMPILE_NG;
10662 }
10663 else if (nd_type_p(default_value, NODE_SYM) ||
10664 nd_type_p(default_value, NODE_REGX) ||
10665 nd_type_p(default_value, NODE_LINE) ||
10666 nd_type_p(default_value, NODE_INTEGER) ||
10667 nd_type_p(default_value, NODE_FLOAT) ||
10668 nd_type_p(default_value, NODE_RATIONAL) ||
10669 nd_type_p(default_value, NODE_IMAGINARY) ||
10670 nd_type_p(default_value, NODE_NIL) ||
10671 nd_type_p(default_value, NODE_TRUE) ||
10672 nd_type_p(default_value, NODE_FALSE)) {
10673 COMPILE_ERROR(ERROR_ARGS "unreachable");
10674 return COMPILE_NG;
10675 }
10676 else {
10677 /* if keywordcheck(_kw_bits, nth_keyword)
10678 * kw = default_value
10679 * end
10680 */
10681 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10682 int keyword_idx = body->param.keyword->num;
10683
10684 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10685 ADD_INSNL(ret, node, branchif, end_label);
10686 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10687 ADD_LABEL(ret, end_label);
10688 }
10689 return COMPILE_OK;
10690}
10691
10692static int
10693compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10694{
10695 DECL_ANCHOR(recv);
10696 DECL_ANCHOR(args);
10697 unsigned int flag = 0;
10698 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10699 VALUE argc;
10700 LABEL *else_label = NULL;
10701 VALUE branches = Qfalse;
10702
10703 INIT_ANCHOR(recv);
10704 INIT_ANCHOR(args);
10705 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10706 CHECK(!NIL_P(argc));
10707
10708 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10709 CHECK(asgnflag != -1);
10710 flag |= (unsigned int)asgnflag;
10711
10712 debugp_param("argc", argc);
10713 debugp_param("nd_mid", ID2SYM(mid));
10714
10715 if (!rb_is_attrset_id(mid)) {
10716 /* safe nav attr */
10717 mid = rb_id_attrset(mid);
10718 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10719 }
10720 if (!popped) {
10721 ADD_INSN(ret, node, putnil);
10722 ADD_SEQ(ret, recv);
10723 ADD_SEQ(ret, args);
10724
10725 if (flag & VM_CALL_ARGS_SPLAT) {
10726 ADD_INSN(ret, node, dup);
10727 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10728 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10729 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10730 ADD_INSN (ret, node, pop);
10731 }
10732 else {
10733 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10734 }
10735 }
10736 else {
10737 ADD_SEQ(ret, recv);
10738 ADD_SEQ(ret, args);
10739 }
10740 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10741 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10742 ADD_INSN(ret, node, pop);
10743 return COMPILE_OK;
10744}
10745
10746static int
10747compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10748{
10749 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10750 ADD_SEQ(ret, sub);
10751
10752 if (copy) {
10753 /*
10754 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10755 * NEW_LIST(value, loc), loc);
10756 */
10757 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10758 }
10759 else {
10760 /*
10761 * NEW_CALL(fcore, rb_intern("make_shareable"),
10762 * NEW_LIST(value, loc), loc);
10763 */
10764 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10765 }
10766
10767 return COMPILE_OK;
10768}
10769
10770static VALUE
10771node_const_decl_val(const NODE *node)
10772{
10773 VALUE path;
10774 switch (nd_type(node)) {
10775 case NODE_CDECL:
10776 if (RNODE_CDECL(node)->nd_vid) {
10777 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10778 goto end;
10779 }
10780 else {
10781 node = RNODE_CDECL(node)->nd_else;
10782 }
10783 break;
10784 case NODE_COLON2:
10785 break;
10786 case NODE_COLON3:
10787 // ::Const
10788 path = rb_str_new_cstr("::");
10789 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10790 goto end;
10791 default:
10792 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10794 }
10795
10796 path = rb_ary_new();
10797 if (node) {
10798 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10799 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10800 }
10801 if (node && nd_type_p(node, NODE_CONST)) {
10802 // Const::Name
10803 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10804 }
10805 else if (node && nd_type_p(node, NODE_COLON3)) {
10806 // ::Const::Name
10807 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10808 rb_ary_push(path, rb_str_new(0, 0));
10809 }
10810 else {
10811 // expression::Name
10812 rb_ary_push(path, rb_str_new_cstr("..."));
10813 }
10814 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10815 }
10816 end:
10817 path = rb_fstring(path);
10818 return path;
10819}
10820
10821static VALUE
10822const_decl_path(NODE *dest)
10823{
10824 VALUE path = Qnil;
10825 if (!nd_type_p(dest, NODE_CALL)) {
10826 path = node_const_decl_val(dest);
10827 }
10828 return path;
10829}
10830
10831static int
10832compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10833{
10834 /*
10835 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10836 */
10837 VALUE path = const_decl_path(dest);
10838 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10839 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10840 ADD_INSN1(ret, value, putobject, path);
10841 RB_OBJ_WRITTEN(iseq, Qundef, path);
10842 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10843
10844 return COMPILE_OK;
10845}
10846
10847#ifndef SHAREABLE_BARE_EXPRESSION
10848#define SHAREABLE_BARE_EXPRESSION 1
10849#endif
10850
10851static int
10852compile_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)
10853{
10854# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10855 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10856 VALUE lit = Qnil;
10857 DECL_ANCHOR(anchor);
10858
10859 enum node_type type = node ? nd_type(node) : NODE_NIL;
10860 switch (type) {
10861 case NODE_TRUE:
10862 *value_p = Qtrue;
10863 goto compile;
10864 case NODE_FALSE:
10865 *value_p = Qfalse;
10866 goto compile;
10867 case NODE_NIL:
10868 *value_p = Qnil;
10869 goto compile;
10870 case NODE_SYM:
10871 *value_p = rb_node_sym_string_val(node);
10872 goto compile;
10873 case NODE_REGX:
10874 *value_p = rb_node_regx_string_val(node);
10875 goto compile;
10876 case NODE_LINE:
10877 *value_p = rb_node_line_lineno_val(node);
10878 goto compile;
10879 case NODE_INTEGER:
10880 *value_p = rb_node_integer_literal_val(node);
10881 goto compile;
10882 case NODE_FLOAT:
10883 *value_p = rb_node_float_literal_val(node);
10884 goto compile;
10885 case NODE_RATIONAL:
10886 *value_p = rb_node_rational_literal_val(node);
10887 goto compile;
10888 case NODE_IMAGINARY:
10889 *value_p = rb_node_imaginary_literal_val(node);
10890 goto compile;
10891 case NODE_ENCODING:
10892 *value_p = rb_node_encoding_val(node);
10893
10894 compile:
10895 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10896 *shareable_literal_p = 1;
10897 return COMPILE_OK;
10898
10899 case NODE_DSTR:
10900 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10901 if (shareable == rb_parser_shareable_literal) {
10902 /*
10903 * NEW_CALL(node, idUMinus, 0, loc);
10904 *
10905 * -"#{var}"
10906 */
10907 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10908 }
10909 *value_p = Qundef;
10910 *shareable_literal_p = 1;
10911 return COMPILE_OK;
10912
10913 case NODE_STR:{
10914 VALUE lit = rb_node_str_string_val(node);
10915 ADD_INSN1(ret, node, putobject, lit);
10916 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10917 *value_p = lit;
10918 *shareable_literal_p = 1;
10919
10920 return COMPILE_OK;
10921 }
10922
10923 case NODE_FILE:{
10924 VALUE lit = rb_node_file_path_val(node);
10925 ADD_INSN1(ret, node, putobject, lit);
10926 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10927 *value_p = lit;
10928 *shareable_literal_p = 1;
10929
10930 return COMPILE_OK;
10931 }
10932
10933 case NODE_ZLIST:{
10934 VALUE lit = rb_ary_new();
10935 OBJ_FREEZE(lit);
10936 ADD_INSN1(ret, node, putobject, lit);
10937 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10938 *value_p = lit;
10939 *shareable_literal_p = 1;
10940
10941 return COMPILE_OK;
10942 }
10943
10944 case NODE_LIST:{
10945 INIT_ANCHOR(anchor);
10946 lit = rb_ary_new();
10947 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10948 VALUE val;
10949 int shareable_literal_p2;
10950 NODE *elt = RNODE_LIST(n)->nd_head;
10951 if (elt) {
10952 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10953 if (shareable_literal_p2) {
10954 /* noop */
10955 }
10956 else if (RTEST(lit)) {
10957 rb_ary_clear(lit);
10958 lit = Qfalse;
10959 }
10960 }
10961 if (RTEST(lit)) {
10962 if (!UNDEF_P(val)) {
10963 rb_ary_push(lit, val);
10964 }
10965 else {
10966 rb_ary_clear(lit);
10967 lit = Qnil; /* make shareable at runtime */
10968 }
10969 }
10970 }
10971 break;
10972 }
10973 case NODE_HASH:{
10974 if (!RNODE_HASH(node)->nd_brace) {
10975 *value_p = Qundef;
10976 *shareable_literal_p = 0;
10977 return COMPILE_OK;
10978 }
10979 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10980 if (!RNODE_LIST(n)->nd_head) {
10981 // If the hash node have a keyword splat, fall back to the default case.
10982 goto compile_shareable;
10983 }
10984 }
10985
10986 INIT_ANCHOR(anchor);
10987 lit = rb_hash_new();
10988 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10989 VALUE key_val = 0;
10990 VALUE value_val = 0;
10991 int shareable_literal_p2;
10992 NODE *key = RNODE_LIST(n)->nd_head;
10993 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10994 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10995 if (shareable_literal_p2) {
10996 /* noop */
10997 }
10998 else if (RTEST(lit)) {
10999 rb_hash_clear(lit);
11000 lit = Qfalse;
11001 }
11002 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
11003 if (shareable_literal_p2) {
11004 /* noop */
11005 }
11006 else if (RTEST(lit)) {
11007 rb_hash_clear(lit);
11008 lit = Qfalse;
11009 }
11010 if (RTEST(lit)) {
11011 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
11012 rb_hash_aset(lit, key_val, value_val);
11013 }
11014 else {
11015 rb_hash_clear(lit);
11016 lit = Qnil; /* make shareable at runtime */
11017 }
11018 }
11019 }
11020 break;
11021 }
11022
11023 default:
11024
11025 compile_shareable:
11026 if (shareable == rb_parser_shareable_literal &&
11027 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
11028 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
11029 *value_p = Qundef;
11030 *shareable_literal_p = 1;
11031 return COMPILE_OK;
11032 }
11033 CHECK(COMPILE(ret, "shareable_literal_constant", node));
11034 *value_p = Qundef;
11035 *shareable_literal_p = 0;
11036 return COMPILE_OK;
11037 }
11038
11039 /* Array or Hash that does not have keyword splat */
11040 if (!lit) {
11041 if (nd_type(node) == NODE_LIST) {
11042 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
11043 }
11044 else if (nd_type(node) == NODE_HASH) {
11045 long len = RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
11048 ADD_INSN1(anchor, node, newhash, LONG2FIX(len));
11049 }
11050 *value_p = Qundef;
11051 *shareable_literal_p = 0;
11052 ADD_SEQ(ret, anchor);
11053 return COMPILE_OK;
11054 }
11055 if (NIL_P(lit)) {
11056 // if shareable_literal, all elements should have been ensured
11057 // as shareable
11058 if (nd_type(node) == NODE_LIST) {
11059 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
11060 }
11061 else if (nd_type(node) == NODE_HASH) {
11062 long len = RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
11065 ADD_INSN1(anchor, node, newhash, LONG2FIX(len));
11066 }
11067 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
11068 *value_p = Qundef;
11069 *shareable_literal_p = 1;
11070 }
11071 else {
11073 ADD_INSN1(ret, node, putobject, val);
11074 RB_OBJ_WRITTEN(iseq, Qundef, val);
11075 *value_p = val;
11076 *shareable_literal_p = 1;
11077 }
11078
11079 return COMPILE_OK;
11080}
11081
11082static int
11083compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
11084{
11085 int literal_p = 0;
11086 VALUE val;
11087 DECL_ANCHOR(anchor);
11088 INIT_ANCHOR(anchor);
11089
11090 switch (shareable) {
11091 case rb_parser_shareable_none:
11092 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
11093 return COMPILE_OK;
11094
11095 case rb_parser_shareable_literal:
11096 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
11097 ADD_SEQ(ret, anchor);
11098 return COMPILE_OK;
11099
11100 case rb_parser_shareable_copy:
11101 case rb_parser_shareable_everything:
11102 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
11103 if (!literal_p) {
11104 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
11105 }
11106 else {
11107 ADD_SEQ(ret, anchor);
11108 }
11109 return COMPILE_OK;
11110 default:
11111 rb_bug("unexpected rb_parser_shareability: %d", shareable);
11112 }
11113}
11114
11115static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
11123static int
11124iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
11125{
11126 if (node == 0) {
11127 if (!popped) {
11128 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
11129 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
11130 debugs("node: NODE_NIL(implicit)\n");
11131 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
11132 }
11133 return COMPILE_OK;
11134 }
11135 return iseq_compile_each0(iseq, ret, node, popped);
11136}
11137
11138static int
11139iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
11140{
11141 const int line = (int)nd_line(node);
11142 const enum node_type type = nd_type(node);
11143 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
11144
11145 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
11146 /* ignore */
11147 }
11148 else {
11149 if (nd_fl_newline(node)) {
11150 int event = RUBY_EVENT_LINE;
11151 ISEQ_COMPILE_DATA(iseq)->last_line = line;
11152 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
11153 event |= RUBY_EVENT_COVERAGE_LINE;
11154 }
11155 ADD_TRACE(ret, event);
11156 }
11157 }
11158
11159 debug_node_start(node);
11160#undef BEFORE_RETURN
11161#define BEFORE_RETURN debug_node_end()
11162
11163 switch (type) {
11164 case NODE_BLOCK:
11165 CHECK(compile_block(iseq, ret, node, popped));
11166 break;
11167 case NODE_IF:
11168 case NODE_UNLESS:
11169 CHECK(compile_if(iseq, ret, node, popped, type));
11170 break;
11171 case NODE_CASE:
11172 CHECK(compile_case(iseq, ret, node, popped));
11173 break;
11174 case NODE_CASE2:
11175 CHECK(compile_case2(iseq, ret, node, popped));
11176 break;
11177 case NODE_CASE3:
11178 CHECK(compile_case3(iseq, ret, node, popped));
11179 break;
11180 case NODE_WHILE:
11181 case NODE_UNTIL:
11182 CHECK(compile_loop(iseq, ret, node, popped, type));
11183 break;
11184 case NODE_FOR:
11185 case NODE_ITER:
11186 CHECK(compile_iter(iseq, ret, node, popped));
11187 break;
11188 case NODE_FOR_MASGN:
11189 CHECK(compile_for_masgn(iseq, ret, node, popped));
11190 break;
11191 case NODE_BREAK:
11192 CHECK(compile_break(iseq, ret, node, popped));
11193 break;
11194 case NODE_NEXT:
11195 CHECK(compile_next(iseq, ret, node, popped));
11196 break;
11197 case NODE_REDO:
11198 CHECK(compile_redo(iseq, ret, node, popped));
11199 break;
11200 case NODE_RETRY:
11201 CHECK(compile_retry(iseq, ret, node, popped));
11202 break;
11203 case NODE_BEGIN:{
11204 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
11205 break;
11206 }
11207 case NODE_RESCUE:
11208 CHECK(compile_rescue(iseq, ret, node, popped));
11209 break;
11210 case NODE_RESBODY:
11211 CHECK(compile_resbody(iseq, ret, node, popped));
11212 break;
11213 case NODE_ENSURE:
11214 CHECK(compile_ensure(iseq, ret, node, popped));
11215 break;
11216
11217 case NODE_AND:
11218 case NODE_OR:{
11219 LABEL *end_label = NEW_LABEL(line);
11220 const NODE *cond = node;
11221 /* Compile a chain of the same operator (`a && b && ...`) against one
11222 * shared end label, so every branch targets it directly. Compiling
11223 * nd_2nd recursively would instead give each operator its own label,
11224 * and the peephole optimizer would rewrite that chain in quadratic
11225 * time. */
11226 while (1) {
11227 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(cond)->nd_1st));
11228 if (!popped) {
11229 ADD_INSN(ret, cond, dup);
11230 }
11231 if (type == NODE_AND) {
11232 ADD_INSNL(ret, cond, branchunless, end_label);
11233 }
11234 else {
11235 ADD_INSNL(ret, cond, branchif, end_label);
11236 }
11237 if (!popped) {
11238 ADD_INSN(ret, cond, pop);
11239 }
11240 const NODE *rest = RNODE_OR(cond)->nd_2nd;
11241 if (nd_type_p(rest, type)) {
11242 cond = rest;
11243 continue;
11244 }
11245 CHECK(COMPILE_(ret, "nd_2nd", rest, popped));
11246 break;
11247 }
11248 ADD_LABEL(ret, end_label);
11249 break;
11250 }
11251
11252 case NODE_MASGN:{
11253 compile_massign(iseq, ret, node, popped);
11254 break;
11255 }
11256
11257 case NODE_LASGN:{
11258 ID id = RNODE_LASGN(node)->nd_vid;
11259 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
11260
11261 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
11262 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
11263
11264 if (!popped) {
11265 ADD_INSN(ret, node, dup);
11266 }
11267 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
11268 break;
11269 }
11270 case NODE_DASGN: {
11271 int idx, lv, ls;
11272 ID id = RNODE_DASGN(node)->nd_vid;
11273 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
11274 debugi("dassn id", rb_id2str(id) ? id : '*');
11275
11276 if (!popped) {
11277 ADD_INSN(ret, node, dup);
11278 }
11279
11280 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
11281
11282 if (idx < 0) {
11283 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
11284 rb_id2str(id));
11285 goto ng;
11286 }
11287 ADD_SETLOCAL(ret, node, ls - idx, lv);
11288 break;
11289 }
11290 case NODE_GASGN:{
11291 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
11292
11293 if (!popped) {
11294 ADD_INSN(ret, node, dup);
11295 }
11296 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
11297 break;
11298 }
11299 case NODE_IASGN:{
11300 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
11301 if (!popped) {
11302 ADD_INSN(ret, node, dup);
11303 }
11304 ADD_INSN2(ret, node, setinstancevariable,
11305 ID2SYM(RNODE_IASGN(node)->nd_vid),
11306 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
11307 break;
11308 }
11309 case NODE_CDECL:{
11310 if (RNODE_CDECL(node)->nd_vid) {
11311 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11312
11313 if (!popped) {
11314 ADD_INSN(ret, node, dup);
11315 }
11316
11317 ADD_INSN1(ret, node, putspecialobject,
11318 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
11319 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
11320 }
11321 else {
11322 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
11323 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11324 ADD_INSN(ret, node, swap);
11325
11326 if (!popped) {
11327 ADD_INSN1(ret, node, topn, INT2FIX(1));
11328 ADD_INSN(ret, node, swap);
11329 }
11330
11331 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
11332 }
11333 break;
11334 }
11335 case NODE_CVASGN:{
11336 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
11337 if (!popped) {
11338 ADD_INSN(ret, node, dup);
11339 }
11340 ADD_INSN2(ret, node, setclassvariable,
11341 ID2SYM(RNODE_CVASGN(node)->nd_vid),
11342 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
11343 break;
11344 }
11345 case NODE_OP_ASGN1:
11346 CHECK(compile_op_asgn1(iseq, ret, node, popped));
11347 break;
11348 case NODE_OP_ASGN2:
11349 CHECK(compile_op_asgn2(iseq, ret, node, popped));
11350 break;
11351 case NODE_OP_CDECL:
11352 CHECK(compile_op_cdecl(iseq, ret, node, popped));
11353 break;
11354 case NODE_OP_ASGN_AND:
11355 case NODE_OP_ASGN_OR:
11356 CHECK(compile_op_log(iseq, ret, node, popped, type));
11357 break;
11358 case NODE_CALL: /* obj.foo */
11359 case NODE_OPCALL: /* foo[] */
11360 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
11361 break;
11362 }
11363 case NODE_QCALL: /* obj&.foo */
11364 case NODE_FCALL: /* foo() */
11365 case NODE_VCALL: /* foo (variable or call) */
11366 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
11367 goto ng;
11368 }
11369 break;
11370 case NODE_SUPER:
11371 case NODE_ZSUPER:
11372 CHECK(compile_super(iseq, ret, node, popped, type));
11373 break;
11374 case NODE_LIST:{
11375 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
11376 break;
11377 }
11378 case NODE_ZLIST:{
11379 if (!popped) {
11380 ADD_INSN1(ret, node, newarray, INT2FIX(0));
11381 }
11382 break;
11383 }
11384 case NODE_HASH:
11385 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
11386 break;
11387 case NODE_RETURN:
11388 CHECK(compile_return(iseq, ret, node, popped));
11389 break;
11390 case NODE_YIELD:
11391 CHECK(compile_yield(iseq, ret, node, popped));
11392 break;
11393 case NODE_LVAR:{
11394 if (!popped) {
11395 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
11396 }
11397 break;
11398 }
11399 case NODE_DVAR:{
11400 int lv, idx, ls;
11401 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
11402 if (!popped) {
11403 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
11404 if (idx < 0) {
11405 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
11406 rb_id2str(RNODE_DVAR(node)->nd_vid));
11407 goto ng;
11408 }
11409 ADD_GETLOCAL(ret, node, ls - idx, lv);
11410 }
11411 break;
11412 }
11413 case NODE_GVAR:{
11414 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
11415 if (popped) {
11416 ADD_INSN(ret, node, pop);
11417 }
11418 break;
11419 }
11420 case NODE_IVAR:{
11421 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
11422 if (!popped) {
11423 ADD_INSN2(ret, node, getinstancevariable,
11424 ID2SYM(RNODE_IVAR(node)->nd_vid),
11425 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
11426 }
11427 break;
11428 }
11429 case NODE_CONST:{
11430 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
11431
11432 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
11433 body->ic_size++;
11434 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
11436 ADD_INSN1(ret, node, opt_getconstant_path, segments);
11437 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11438 }
11439 else {
11440 ADD_INSN(ret, node, putnil);
11441 ADD_INSN1(ret, node, putobject, Qtrue);
11442 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
11443 }
11444
11445 if (popped) {
11446 ADD_INSN(ret, node, pop);
11447 }
11448 break;
11449 }
11450 case NODE_CVAR:{
11451 if (!popped) {
11452 ADD_INSN2(ret, node, getclassvariable,
11453 ID2SYM(RNODE_CVAR(node)->nd_vid),
11454 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
11455 }
11456 break;
11457 }
11458 case NODE_NTH_REF:{
11459 if (!popped) {
11460 if (!RNODE_NTH_REF(node)->nd_nth) {
11461 ADD_INSN(ret, node, putnil);
11462 break;
11463 }
11464 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11465 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
11466 }
11467 break;
11468 }
11469 case NODE_BACK_REF:{
11470 if (!popped) {
11471 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11472 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
11473 }
11474 break;
11475 }
11476 case NODE_MATCH:
11477 case NODE_MATCH2:
11478 case NODE_MATCH3:
11479 CHECK(compile_match(iseq, ret, node, popped, type));
11480 break;
11481 case NODE_SYM:{
11482 if (!popped) {
11483 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
11484 }
11485 break;
11486 }
11487 case NODE_LINE:{
11488 if (!popped) {
11489 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
11490 }
11491 break;
11492 }
11493 case NODE_ENCODING:{
11494 if (!popped) {
11495 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11496 }
11497 break;
11498 }
11499 case NODE_INTEGER:{
11500 VALUE lit = rb_node_integer_literal_val(node);
11501 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11502 debugp_param("integer", lit);
11503 if (!popped) {
11504 ADD_INSN1(ret, node, putobject, lit);
11505 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11506 }
11507 break;
11508 }
11509 case NODE_FLOAT:{
11510 VALUE lit = rb_node_float_literal_val(node);
11511 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11512 debugp_param("float", lit);
11513 if (!popped) {
11514 ADD_INSN1(ret, node, putobject, lit);
11515 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11516 }
11517 break;
11518 }
11519 case NODE_RATIONAL:{
11520 VALUE lit = rb_node_rational_literal_val(node);
11522 debugp_param("rational", lit);
11523 if (!popped) {
11524 ADD_INSN1(ret, node, putobject, lit);
11525 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11526 }
11527 break;
11528 }
11529 case NODE_IMAGINARY:{
11530 VALUE lit = rb_node_imaginary_literal_val(node);
11532 debugp_param("imaginary", lit);
11533 if (!popped) {
11534 ADD_INSN1(ret, node, putobject, lit);
11535 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11536 }
11537 break;
11538 }
11539 case NODE_FILE:
11540 case NODE_STR:{
11541 debugp_param("nd_lit", get_string_value(node));
11542 if (!popped) {
11543 VALUE lit = get_string_value(node);
11544 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11545 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11546 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11547 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11549 }
11550 switch (option->frozen_string_literal) {
11551 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11552 ADD_INSN1(ret, node, dupchilledstring, lit);
11553 break;
11554 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11555 ADD_INSN1(ret, node, dupstring, lit);
11556 break;
11557 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11558 ADD_INSN1(ret, node, putobject, lit);
11559 break;
11560 default:
11561 rb_bug("invalid frozen_string_literal");
11562 }
11563 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11564 }
11565 break;
11566 }
11567 case NODE_DSTR:{
11568 compile_dstr(iseq, ret, node);
11569
11570 if (popped) {
11571 ADD_INSN(ret, node, pop);
11572 }
11573 break;
11574 }
11575 case NODE_XSTR:{
11576 ADD_CALL_RECEIVER(ret, node);
11577 VALUE str = rb_node_str_string_val(node);
11578 ADD_INSN1(ret, node, putobject, str);
11579 RB_OBJ_WRITTEN(iseq, Qundef, str);
11580 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11581
11582 if (popped) {
11583 ADD_INSN(ret, node, pop);
11584 }
11585 break;
11586 }
11587 case NODE_DXSTR:{
11588 ADD_CALL_RECEIVER(ret, node);
11589 compile_dstr(iseq, ret, node);
11590 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11591
11592 if (popped) {
11593 ADD_INSN(ret, node, pop);
11594 }
11595 break;
11596 }
11597 case NODE_EVSTR:
11598 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11599 break;
11600 case NODE_REGX:{
11601 if (!popped) {
11602 VALUE lit = rb_node_regx_string_val(node);
11604 ADD_INSN1(ret, node, putobject, lit);
11605 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11606 }
11607 break;
11608 }
11609 case NODE_DREGX:
11610 compile_dregx(iseq, ret, node, popped);
11611 break;
11612 case NODE_ONCE:{
11613 int ic_index = body->ise_size++;
11614 const rb_iseq_t *block_iseq;
11615 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11616
11617 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11618 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11619
11620 if (popped) {
11621 ADD_INSN(ret, node, pop);
11622 }
11623 break;
11624 }
11625 case NODE_ARGSCAT:{
11626 if (popped) {
11627 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11628 ADD_INSN1(ret, node, splatarray, Qfalse);
11629 ADD_INSN(ret, node, pop);
11630 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11631 ADD_INSN1(ret, node, splatarray, Qfalse);
11632 ADD_INSN(ret, node, pop);
11633 }
11634 else {
11635 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11636 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11637 if (nd_type_p(body_node, NODE_LIST)) {
11638 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11639 }
11640 else {
11641 CHECK(COMPILE(ret, "argscat body", body_node));
11642 ADD_INSN(ret, node, concattoarray);
11643 }
11644 }
11645 break;
11646 }
11647 case NODE_ARGSPUSH:{
11648 if (popped) {
11649 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11650 ADD_INSN1(ret, node, splatarray, Qfalse);
11651 ADD_INSN(ret, node, pop);
11652 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11653 }
11654 else {
11655 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11656 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11657 if (keyword_node_p(body_node)) {
11658 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11659 ADD_INSN(ret, node, pushtoarraykwsplat);
11660 }
11661 else if (static_literal_node_p(body_node, iseq, false)) {
11662 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11663 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11664 }
11665 else {
11666 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11667 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11668 }
11669 }
11670 break;
11671 }
11672 case NODE_SPLAT:{
11673 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11674 ADD_INSN1(ret, node, splatarray, Qtrue);
11675
11676 if (popped) {
11677 ADD_INSN(ret, node, pop);
11678 }
11679 break;
11680 }
11681 case NODE_DEFN:{
11682 ID mid = RNODE_DEFN(node)->nd_mid;
11683 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11684 rb_id2str(mid),
11685 ISEQ_TYPE_METHOD, line);
11686
11687 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11688 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11689 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11690
11691 if (!popped) {
11692 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11693 }
11694
11695 break;
11696 }
11697 case NODE_DEFS:{
11698 ID mid = RNODE_DEFS(node)->nd_mid;
11699 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11700 rb_id2str(mid),
11701 ISEQ_TYPE_METHOD, line);
11702
11703 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11704 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11705 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11706 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11707
11708 if (!popped) {
11709 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11710 }
11711 break;
11712 }
11713 case NODE_ALIAS:{
11714 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11715 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11716 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11717 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11718 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11719
11720 if (popped) {
11721 ADD_INSN(ret, node, pop);
11722 }
11723 break;
11724 }
11725 case NODE_VALIAS:{
11726 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11727 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11728 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11729 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11730
11731 if (popped) {
11732 ADD_INSN(ret, node, pop);
11733 }
11734 break;
11735 }
11736 case NODE_UNDEF:{
11737 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11738
11739 for (long i = 0; i < ary->len; i++) {
11740 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11741 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11742 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11743 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11744
11745 if (i < ary->len - 1) {
11746 ADD_INSN(ret, node, pop);
11747 }
11748 }
11749
11750 if (popped) {
11751 ADD_INSN(ret, node, pop);
11752 }
11753 break;
11754 }
11755 case NODE_CLASS:{
11756 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11757 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11758 ISEQ_TYPE_CLASS, line);
11759 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11760 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11761 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11762
11763 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11764 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11765 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11766
11767 if (popped) {
11768 ADD_INSN(ret, node, pop);
11769 }
11770 break;
11771 }
11772 case NODE_MODULE:{
11773 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11774 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11775 ISEQ_TYPE_CLASS, line);
11776 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11777 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11778
11779 ADD_INSN (ret, node, putnil); /* dummy */
11780 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11781 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11782
11783 if (popped) {
11784 ADD_INSN(ret, node, pop);
11785 }
11786 break;
11787 }
11788 case NODE_SCLASS:{
11789 ID singletonclass;
11790 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11791 ISEQ_TYPE_CLASS, line);
11792
11793 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11794 ADD_INSN (ret, node, putnil);
11795 CONST_ID(singletonclass, "singletonclass");
11796
11797 /* `class << self` in a class body and `class << Foo` (constant
11798 receiver) are stable. All other forms are potentially dynamic. */
11799 int sclass_flags = VM_DEFINECLASS_TYPE_SINGLETON_CLASS;
11800 const NODE *recv = RNODE_SCLASS(node)->nd_recv;
11801 if (!(nd_type_p(recv, NODE_SELF) &&
11802 ISEQ_BODY(iseq)->type == ISEQ_TYPE_CLASS) &&
11803 !cpath_const_p(recv)) {
11804 sclass_flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF;
11805 }
11806
11807 ADD_INSN3(ret, node, defineclass,
11808 ID2SYM(singletonclass), singleton_class,
11809 INT2FIX(sclass_flags));
11810 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11811
11812 if (popped) {
11813 ADD_INSN(ret, node, pop);
11814 }
11815 break;
11816 }
11817 case NODE_COLON2:
11818 CHECK(compile_colon2(iseq, ret, node, popped));
11819 break;
11820 case NODE_COLON3:
11821 CHECK(compile_colon3(iseq, ret, node, popped));
11822 break;
11823 case NODE_DOT2:
11824 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11825 break;
11826 case NODE_DOT3:
11827 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11828 break;
11829 case NODE_FLIP2:
11830 case NODE_FLIP3:{
11831 LABEL *lend = NEW_LABEL(line);
11832 LABEL *ltrue = NEW_LABEL(line);
11833 LABEL *lfalse = NEW_LABEL(line);
11834 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11835 ltrue, lfalse));
11836 ADD_LABEL(ret, ltrue);
11837 ADD_INSN1(ret, node, putobject, Qtrue);
11838 ADD_INSNL(ret, node, jump, lend);
11839 ADD_LABEL(ret, lfalse);
11840 ADD_INSN1(ret, node, putobject, Qfalse);
11841 ADD_LABEL(ret, lend);
11842 break;
11843 }
11844 case NODE_SELF:{
11845 if (!popped) {
11846 ADD_INSN(ret, node, putself);
11847 }
11848 break;
11849 }
11850 case NODE_NIL:{
11851 if (!popped) {
11852 ADD_INSN(ret, node, putnil);
11853 }
11854 break;
11855 }
11856 case NODE_TRUE:{
11857 if (!popped) {
11858 ADD_INSN1(ret, node, putobject, Qtrue);
11859 }
11860 break;
11861 }
11862 case NODE_FALSE:{
11863 if (!popped) {
11864 ADD_INSN1(ret, node, putobject, Qfalse);
11865 }
11866 break;
11867 }
11868 case NODE_ERRINFO:
11869 CHECK(compile_errinfo(iseq, ret, node, popped));
11870 break;
11871 case NODE_DEFINED:
11872 if (!popped) {
11873 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11874 }
11875 break;
11876 case NODE_POSTEXE:{
11877 /* compiled to:
11878 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11879 */
11880 int is_index = body->ise_size++;
11882 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11883 const rb_iseq_t *once_iseq =
11884 NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc, rb_fstring(make_name_for_block(iseq)), ISEQ_TYPE_BLOCK, line);
11885
11886 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11887 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11888
11889 if (popped) {
11890 ADD_INSN(ret, node, pop);
11891 }
11892 break;
11893 }
11894 case NODE_KW_ARG:
11895 CHECK(compile_kw_arg(iseq, ret, node, popped));
11896 break;
11897 case NODE_DSYM:{
11898 compile_dstr(iseq, ret, node);
11899 if (!popped) {
11900 ADD_INSN(ret, node, intern);
11901 }
11902 else {
11903 ADD_INSN(ret, node, pop);
11904 }
11905 break;
11906 }
11907 case NODE_ATTRASGN:
11908 CHECK(compile_attrasgn(iseq, ret, node, popped));
11909 break;
11910 case NODE_LAMBDA:{
11911 /* compile same as lambda{...} */
11912 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11913 VALUE argc = INT2FIX(0);
11914
11915 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11916 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11917 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11918
11919 if (popped) {
11920 ADD_INSN(ret, node, pop);
11921 }
11922 break;
11923 }
11924 default:
11925 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11926 ng:
11927 debug_node_end();
11928 return COMPILE_NG;
11929 }
11930
11931 debug_node_end();
11932 return COMPILE_OK;
11933}
11934
11935/***************************/
11936/* instruction information */
11937/***************************/
11938
11939static int
11940insn_data_length(INSN *iobj)
11941{
11942 return insn_len(iobj->insn_id);
11943}
11944
11945static int
11946calc_sp_depth(int depth, INSN *insn)
11947{
11948 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11949}
11950
11951static VALUE
11952opobj_inspect(VALUE obj)
11953{
11954 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11955 switch (BUILTIN_TYPE(obj)) {
11956 case T_STRING:
11957 obj = rb_str_resurrect(obj);
11958 break;
11959 case T_ARRAY:
11960 obj = rb_ary_resurrect(obj);
11961 break;
11962 default:
11963 break;
11964 }
11965 }
11966 return rb_inspect(obj);
11967}
11968
11969
11970
11971static VALUE
11972insn_data_to_s_detail(INSN *iobj)
11973{
11974 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11975
11976 if (iobj->operands) {
11977 const char *types = insn_op_types(iobj->insn_id);
11978 int j;
11979
11980 for (j = 0; types[j]; j++) {
11981 char type = types[j];
11982
11983 switch (type) {
11984 case TS_OFFSET: /* label(destination position) */
11985 {
11986 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11987 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11988 break;
11989 }
11990 break;
11991 case TS_ISEQ: /* iseq */
11992 {
11993 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11994 VALUE val = Qnil;
11995 if (0 && iseq) { /* TODO: invalidate now */
11996 val = (VALUE)iseq;
11997 }
11998 rb_str_concat(str, opobj_inspect(val));
11999 }
12000 break;
12001 case TS_LINDEX:
12002 case TS_NUM: /* ulong */
12003 case TS_VALUE: /* VALUE */
12004 {
12005 VALUE v = OPERAND_AT(iobj, j);
12006 if (!CLASS_OF(v))
12007 rb_str_cat2(str, "<hidden>");
12008 else {
12009 rb_str_concat(str, opobj_inspect(v));
12010 }
12011 break;
12012 }
12013 case TS_ID: /* ID */
12014 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
12015 break;
12016 case TS_IC: /* inline cache */
12017 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
12018 break;
12019 case TS_IVC: /* inline ivar cache */
12020 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
12021 break;
12022 case TS_ICVARC: /* inline cvar cache */
12023 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
12024 break;
12025 case TS_ISE: /* inline storage entry */
12026 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
12027 break;
12028 case TS_CALLDATA: /* we store these as call infos at compile time */
12029 {
12030 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
12031 rb_str_cat2(str, "<calldata:");
12032 if (vm_ci_mid(ci)) rb_str_append(str, rb_id2str(vm_ci_mid(ci)));
12033 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
12034 break;
12035 }
12036 case TS_CDHASH: /* case/when condition cache */
12037 rb_str_cat2(str, "<ch>");
12038 break;
12039 case TS_FUNCPTR:
12040 {
12041 void *func = (void *)OPERAND_AT(iobj, j);
12042#ifdef HAVE_DLADDR
12043 Dl_info info;
12044 if (dladdr(func, &info) && info.dli_sname) {
12045 rb_str_cat2(str, info.dli_sname);
12046 break;
12047 }
12048#endif
12049 rb_str_catf(str, "<%p>", func);
12050 }
12051 break;
12052 case TS_BUILTIN:
12053 rb_str_cat2(str, "<TS_BUILTIN>");
12054 break;
12055 default:{
12056 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
12057 }
12058 }
12059 if (types[j + 1]) {
12060 rb_str_cat2(str, ", ");
12061 }
12062 }
12063 }
12064 return str;
12065}
12066
12067static void
12068dump_disasm_list(const LINK_ELEMENT *link)
12069{
12070 dump_disasm_list_with_cursor(link, NULL, NULL);
12071}
12072
12073static void
12074dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
12075{
12076 int pos = 0;
12077 INSN *iobj;
12078 LABEL *lobj;
12079 VALUE str;
12080
12081 printf("-- raw disasm--------\n");
12082
12083 while (link) {
12084 if (curr) printf(curr == link ? "*" : " ");
12085 switch (link->type) {
12086 case ISEQ_ELEMENT_INSN:
12087 {
12088 iobj = (INSN *)link;
12089 str = insn_data_to_s_detail(iobj);
12090 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
12091 pos += insn_data_length(iobj);
12092 break;
12093 }
12094 case ISEQ_ELEMENT_LABEL:
12095 {
12096 lobj = (LABEL *)link;
12097 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
12098 dest == lobj ? " <---" : "");
12099 break;
12100 }
12101 case ISEQ_ELEMENT_TRACE:
12102 {
12103 TRACE *trace = (TRACE *)link;
12104 printf(" trace: %0x\n", trace->event);
12105 break;
12106 }
12107 case ISEQ_ELEMENT_ADJUST:
12108 {
12109 ADJUST *adjust = (ADJUST *)link;
12110 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
12111 break;
12112 }
12113 default:
12114 /* ignore */
12115 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
12116 }
12117 link = link->next;
12118 }
12119 printf("---------------------\n");
12120 fflush(stdout);
12121}
12122
12123int
12124rb_insn_len(VALUE insn)
12125{
12126 return insn_len(insn);
12127}
12128
12129const char *
12130rb_insns_name(int i)
12131{
12132 return insn_name(i);
12133}
12134
12135VALUE
12136rb_insns_name_array(void)
12137{
12138 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
12139 int i;
12140 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
12141 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
12142 }
12143 return rb_ary_freeze(ary);
12144}
12145
12146static LABEL *
12147register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
12148{
12149 LABEL *label = 0;
12150 st_data_t tmp;
12151 obj = rb_to_symbol_type(obj);
12152
12153 if (st_lookup(labels_table, obj, &tmp) == 0) {
12154 label = NEW_LABEL(0);
12155 st_insert(labels_table, obj, (st_data_t)label);
12156 }
12157 else {
12158 label = (LABEL *)tmp;
12159 }
12160 LABEL_REF(label);
12161 return label;
12162}
12163
12164static VALUE
12165get_exception_sym2type(VALUE sym)
12166{
12167 static VALUE symRescue, symEnsure, symRetry;
12168 static VALUE symBreak, symRedo, symNext;
12169
12170 if (symRescue == 0) {
12171 symRescue = ID2SYM(rb_intern_const("rescue"));
12172 symEnsure = ID2SYM(rb_intern_const("ensure"));
12173 symRetry = ID2SYM(rb_intern_const("retry"));
12174 symBreak = ID2SYM(rb_intern_const("break"));
12175 symRedo = ID2SYM(rb_intern_const("redo"));
12176 symNext = ID2SYM(rb_intern_const("next"));
12177 }
12178
12179 if (sym == symRescue) return CATCH_TYPE_RESCUE;
12180 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
12181 if (sym == symRetry) return CATCH_TYPE_RETRY;
12182 if (sym == symBreak) return CATCH_TYPE_BREAK;
12183 if (sym == symRedo) return CATCH_TYPE_REDO;
12184 if (sym == symNext) return CATCH_TYPE_NEXT;
12185 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
12186 return 0;
12187}
12188
12189static int
12190iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
12191 VALUE exception)
12192{
12193 int i;
12194
12195 for (i=0; i<RARRAY_LEN(exception); i++) {
12196 const rb_iseq_t *eiseq;
12197 VALUE v, type;
12198 LABEL *lstart, *lend, *lcont;
12199 unsigned int sp;
12200
12201 v = rb_to_array_type(RARRAY_AREF(exception, i));
12202 if (RARRAY_LEN(v) != 6) {
12203 rb_raise(rb_eSyntaxError, "wrong exception entry");
12204 }
12205 type = get_exception_sym2type(RARRAY_AREF(v, 0));
12206 if (NIL_P(RARRAY_AREF(v, 1))) {
12207 eiseq = NULL;
12208 }
12209 else {
12210 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
12211 }
12212
12213 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
12214 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
12215 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
12216 sp = NUM2UINT(RARRAY_AREF(v, 5));
12217
12218 /* TODO: Dirty Hack! Fix me */
12219 if (type == CATCH_TYPE_RESCUE ||
12220 type == CATCH_TYPE_BREAK ||
12221 type == CATCH_TYPE_NEXT) {
12222 ++sp;
12223 }
12224
12225 lcont->sp = sp;
12226
12227 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
12228
12229 RB_GC_GUARD(v);
12230 }
12231 return COMPILE_OK;
12232}
12233
12234static struct st_table *
12235insn_make_insn_table(void)
12236{
12237 struct st_table *table;
12238 int i;
12239 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
12240
12241 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
12242 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
12243 }
12244
12245 return table;
12246}
12247
12248static const rb_iseq_t *
12249iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
12250{
12251 VALUE iseqw;
12252 const rb_iseq_t *loaded_iseq;
12253
12254 if (RB_TYPE_P(op, T_ARRAY)) {
12255 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
12256 }
12257 else if (CLASS_OF(op) == rb_cISeq) {
12258 iseqw = op;
12259 }
12260 else {
12261 rb_raise(rb_eSyntaxError, "ISEQ is required");
12262 }
12263
12264 loaded_iseq = rb_iseqw_to_iseq(iseqw);
12265 return loaded_iseq;
12266}
12267
12268static VALUE
12269iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
12270{
12271 ID mid = 0;
12272 int orig_argc = 0;
12273 unsigned int flag = 0;
12274 struct rb_callinfo_kwarg *kw_arg = 0;
12275
12276 if (!NIL_P(op)) {
12277 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
12278 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
12279 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
12280 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
12281
12282 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
12283 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
12284 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
12285
12286 if (!NIL_P(vkw_arg)) {
12287 int i;
12288 int len = RARRAY_LENINT(vkw_arg);
12289 size_t n = rb_callinfo_kwarg_bytes(len);
12290
12291 kw_arg = xmalloc(n);
12292 kw_arg->references = 0;
12293 kw_arg->keyword_len = len;
12294 for (i = 0; i < len; i++) {
12295 VALUE kw = RARRAY_AREF(vkw_arg, i);
12296 SYM2ID(kw); /* make immortal */
12297 kw_arg->keywords[i] = kw;
12298 }
12299 }
12300 }
12301
12302 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
12303 RB_OBJ_WRITTEN(iseq, Qundef, ci);
12304 return (VALUE)ci;
12305}
12306
12307static rb_event_flag_t
12308event_name_to_flag(VALUE sym)
12309{
12310#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
12311 CHECK_EVENT(RUBY_EVENT_LINE);
12312 CHECK_EVENT(RUBY_EVENT_CLASS);
12313 CHECK_EVENT(RUBY_EVENT_END);
12314 CHECK_EVENT(RUBY_EVENT_CALL);
12315 CHECK_EVENT(RUBY_EVENT_RETURN);
12316 CHECK_EVENT(RUBY_EVENT_B_CALL);
12317 CHECK_EVENT(RUBY_EVENT_B_RETURN);
12318 CHECK_EVENT(RUBY_EVENT_RESCUE);
12319#undef CHECK_EVENT
12320 return RUBY_EVENT_NONE;
12321}
12322
12323static int
12324iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
12325 VALUE body, VALUE node_ids, VALUE labels_wrapper)
12326{
12327 /* TODO: body should be frozen */
12328 rb_len_t i, len = RARRAY_LEN(body);
12329 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
12330 int j;
12331 int line_no = 0, node_id = -1, insn_idx = 0;
12332 int ret = COMPILE_OK;
12333
12334 /*
12335 * index -> LABEL *label
12336 */
12337 static struct st_table *insn_table;
12338
12339 if (insn_table == 0) {
12340 insn_table = insn_make_insn_table();
12341 }
12342
12343 for (i=0; i<len; i++) {
12344 VALUE obj = RARRAY_AREF(body, i);
12345
12346 if (SYMBOL_P(obj)) {
12347 rb_event_flag_t event;
12348 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
12349 ADD_TRACE(anchor, event);
12350 }
12351 else {
12352 LABEL *label = register_label(iseq, labels_table, obj);
12353 ADD_LABEL(anchor, label);
12354 }
12355 }
12356 else if (FIXNUM_P(obj)) {
12357 line_no = NUM2INT(obj);
12358 }
12359 else if (RB_TYPE_P(obj, T_ARRAY)) {
12360 VALUE *argv = 0;
12361 int argc = RARRAY_LENINT(obj) - 1;
12362 st_data_t insn_id;
12363 VALUE insn;
12364
12365 if (node_ids) {
12366 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
12367 }
12368
12369 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
12370 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
12371 /* TODO: exception */
12372 COMPILE_ERROR(iseq, line_no,
12373 "unknown instruction: %+"PRIsVALUE, insn);
12374 ret = COMPILE_NG;
12375 break;
12376 }
12377
12378 if (argc != insn_len((VALUE)insn_id)-1) {
12379 COMPILE_ERROR(iseq, line_no,
12380 "operand size mismatch");
12381 ret = COMPILE_NG;
12382 break;
12383 }
12384
12385 if (argc > 0) {
12386 argv = compile_data_calloc2_type(iseq, VALUE, argc);
12387
12388 // add element before operand setup to make GC root
12389 ADD_ELEM(anchor,
12390 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12391 (enum ruby_vminsn_type)insn_id, argc, argv));
12392
12393 for (j=0; j<argc; j++) {
12394 VALUE op = rb_ary_entry(obj, j+1);
12395 switch (insn_op_type((VALUE)insn_id, j)) {
12396 case TS_OFFSET: {
12397 LABEL *label = register_label(iseq, labels_table, op);
12398 argv[j] = (VALUE)label;
12399 break;
12400 }
12401 case TS_LINDEX:
12402 case TS_NUM:
12403 (void)NUM2INT(op);
12404 argv[j] = op;
12405 break;
12406 case TS_VALUE:
12407 argv[j] = op;
12408 RB_OBJ_WRITTEN(iseq, Qundef, op);
12409 break;
12410 case TS_ISEQ:
12411 {
12412 if (op != Qnil) {
12413 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
12414 argv[j] = v;
12415 RB_OBJ_WRITTEN(iseq, Qundef, v);
12416 }
12417 else {
12418 argv[j] = 0;
12419 }
12420 }
12421 break;
12422 case TS_ISE:
12423 argv[j] = op;
12424 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
12425 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
12426 }
12427 break;
12428 case TS_IC:
12429 {
12430 VALUE segments = rb_ary_new();
12431 op = rb_to_array_type(op);
12432
12433 for (int i = 0; i < RARRAY_LEN(op); i++) {
12434 VALUE sym = RARRAY_AREF(op, i);
12435 sym = rb_to_symbol_type(sym);
12436 rb_ary_push(segments, sym);
12437 }
12438
12439 RB_GC_GUARD(op);
12440 argv[j] = segments;
12441 RB_OBJ_WRITTEN(iseq, Qundef, segments);
12442 ISEQ_BODY(iseq)->ic_size++;
12443 }
12444 break;
12445 case TS_IVC: /* inline ivar cache */
12446 argv[j] = op;
12447 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
12448 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
12449 }
12450 break;
12451 case TS_ICVARC: /* inline cvar cache */
12452 argv[j] = op;
12453 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
12454 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
12455 }
12456 break;
12457 case TS_CALLDATA:
12458 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
12459 break;
12460 case TS_ID:
12461 argv[j] = rb_to_symbol_type(op);
12462 break;
12463 case TS_CDHASH:
12464 {
12465 int i;
12466 VALUE map = cdhash_new(RARRAY_LEN(op) / 2);
12467
12468 op = rb_to_array_type(op);
12469 for (i=0; i<RARRAY_LEN(op); i+=2) {
12470 VALUE key = RARRAY_AREF(op, i);
12471 VALUE sym = RARRAY_AREF(op, i+1);
12472 LABEL *label =
12473 register_label(iseq, labels_table, sym);
12474 cdhash_aset(map, key, (VALUE)label);
12475 }
12476 RB_GC_GUARD(op);
12477 RB_OBJ_SET_SHAREABLE(map); // allow mutation while compiling
12478 argv[j] = map;
12479 RB_OBJ_WRITTEN(iseq, Qundef, map);
12480 }
12481 break;
12482 case TS_FUNCPTR:
12483 {
12484#if SIZEOF_VALUE <= SIZEOF_LONG
12485 long funcptr = NUM2LONG(op);
12486#else
12487 LONG_LONG funcptr = NUM2LL(op);
12488#endif
12489 argv[j] = (VALUE)funcptr;
12490 }
12491 break;
12492 default:
12493 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
12494 }
12495 }
12496 }
12497 else {
12498 ADD_ELEM(anchor,
12499 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12500 (enum ruby_vminsn_type)insn_id, argc, NULL));
12501 }
12502 }
12503 else {
12504 rb_raise(rb_eTypeError, "unexpected object for instruction");
12505 }
12506 }
12507 RTYPEDDATA_DATA(labels_wrapper) = 0;
12508 RB_GC_GUARD(labels_wrapper);
12509 validate_labels(iseq, labels_table);
12510 if (!ret) return ret;
12511 return iseq_setup(iseq, anchor);
12512}
12513
12514#define CHECK_ARRAY(v) rb_to_array_type(v)
12515#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12516
12517static int
12518int_param(int *dst, VALUE param, VALUE sym)
12519{
12520 VALUE val = rb_hash_aref(param, sym);
12521 if (FIXNUM_P(val)) {
12522 *dst = FIX2INT(val);
12523 return TRUE;
12524 }
12525 else if (!NIL_P(val)) {
12526 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
12527 sym, val);
12528 }
12529 return FALSE;
12530}
12531
12532static const struct rb_iseq_param_keyword *
12533iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12534{
12535 int i, j;
12536 int len = RARRAY_LENINT(keywords);
12537 int default_len;
12538 VALUE key, sym, default_val;
12539 VALUE *dvs;
12540 ID *ids;
12541 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12542
12543 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12544
12545 keyword->num = len;
12546#define SYM(s) ID2SYM(rb_intern_const(#s))
12547 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12548 i = keyword->bits_start - keyword->num;
12549 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12550#undef SYM
12551
12552 /* required args */
12553 for (i = 0; i < len; i++) {
12554 VALUE val = RARRAY_AREF(keywords, i);
12555
12556 if (!SYMBOL_P(val)) {
12557 goto default_values;
12558 }
12559 ids[i] = SYM2ID(val);
12560 keyword->required_num++;
12561 }
12562
12563 default_values: /* note: we intentionally preserve `i' from previous loop */
12564 default_len = len - i;
12565 if (default_len == 0) {
12566 keyword->table = ids;
12567 return keyword;
12568 }
12569 else if (default_len < 0) {
12571 }
12572
12573 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12574
12575 for (j = 0; i < len; i++, j++) {
12576 key = RARRAY_AREF(keywords, i);
12577 CHECK_ARRAY(key);
12578
12579 switch (RARRAY_LEN(key)) {
12580 case 1:
12581 sym = RARRAY_AREF(key, 0);
12582 default_val = Qundef;
12583 break;
12584 case 2:
12585 sym = RARRAY_AREF(key, 0);
12586 default_val = RARRAY_AREF(key, 1);
12587 break;
12588 default:
12589 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12590 }
12591 ids[i] = SYM2ID(sym);
12592 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12593 }
12594
12595 keyword->table = ids;
12596 keyword->default_values = dvs;
12597
12598 return keyword;
12599}
12600
12601static void
12602iseq_insn_each_object_mark_and_move(VALUE * obj, VALUE _)
12603{
12604 rb_gc_mark_and_move(obj);
12605}
12606
12607void
12608rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
12609{
12610 INSN *iobj = 0;
12611 size_t size = sizeof(INSN);
12612 size_t align = ALIGNMENT_SIZE_OF(INSN);
12613 unsigned int pos = 0;
12614
12615 while (storage) {
12616 size_t padding = calc_padding((void *)&storage->buff[pos], align);
12617 size_t offset = pos + size + padding;
12618 if (offset > storage->size || offset > storage->pos) {
12619 pos = 0;
12620 storage = storage->next;
12621 }
12622 else {
12623 pos += (int)padding;
12624
12625 iobj = (INSN *)&storage->buff[pos];
12626
12627 if (iobj->operands) {
12628 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (VALUE)0);
12629 }
12630 pos += (int)size;
12631 }
12632 }
12633}
12634
12635static const rb_data_type_t labels_wrapper_type = {
12636 .wrap_struct_name = "compiler/labels_wrapper",
12637 .function = {
12638 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12639 .dfree = (RUBY_DATA_FUNC)st_free_table,
12640 },
12641 .flags = RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED,
12642};
12643
12644void
12645rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12646 VALUE exception, VALUE body)
12647{
12648#define SYM(s) ID2SYM(rb_intern_const(#s))
12649 int i, len;
12650 unsigned int arg_size, local_size, stack_max;
12651 ID *tbl;
12652 struct st_table *labels_table = st_init_numtable();
12653 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12654 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12655 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12656 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12657 DECL_ANCHOR(anchor);
12658 INIT_ANCHOR(anchor);
12659
12660 len = RARRAY_LENINT(locals);
12661 ISEQ_BODY(iseq)->local_table_size = len;
12662 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12663
12664 for (i = 0; i < len; i++) {
12665 VALUE lv = RARRAY_AREF(locals, i);
12666
12667 if (sym_arg_rest == lv) {
12668 tbl[i] = 0;
12669 }
12670 else {
12671 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12672 }
12673 }
12674
12675#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12676 if (INT_PARAM(lead_num)) {
12677 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12678 }
12679 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12680 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12681 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12682 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12683#undef INT_PARAM
12684 {
12685#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12686 int x;
12687 INT_PARAM(arg_size);
12688 INT_PARAM(local_size);
12689 INT_PARAM(stack_max);
12690#undef INT_PARAM
12691 }
12692
12693 VALUE source_hash = rb_hash_aref(misc, ID2SYM(rb_intern("source_hash")));
12694 if (!NIL_P(source_hash)) {
12695 ISEQ_BODY(iseq)->source_hash = NUM2ULL(source_hash);
12696 }
12697
12698 VALUE node_ids = Qfalse;
12699#ifdef USE_ISEQ_NODE_ID
12700 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12701 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12702 rb_raise(rb_eTypeError, "node_ids is not an array");
12703 }
12704#endif
12705
12706 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12707 len = RARRAY_LENINT(arg_opt_labels);
12708 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12709
12710 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12711 VALUE *opt_table = ALLOC_N(VALUE, len);
12712
12713 for (i = 0; i < len; i++) {
12714 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12715 LABEL *label = register_label(iseq, labels_table, ent);
12716 opt_table[i] = (VALUE)label;
12717 }
12718
12719 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12720 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12721 }
12722 }
12723 else if (!NIL_P(arg_opt_labels)) {
12724 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12725 arg_opt_labels);
12726 }
12727
12728 if (RB_TYPE_P(keywords, T_ARRAY)) {
12729 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12730 }
12731 else if (!NIL_P(keywords)) {
12732 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12733 keywords);
12734 }
12735
12736 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12737 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12738 }
12739
12740 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12741 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12742 }
12743
12744 if (int_param(&i, params, SYM(kwrest))) {
12745 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12746 if (keyword == NULL) {
12747 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12748 }
12749 keyword->rest_start = i;
12750 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12751 }
12752#undef SYM
12753 iseq_calc_param_size(iseq);
12754
12755 /* exception */
12756 iseq_build_from_ary_exception(iseq, labels_table, exception);
12757
12758 /* body */
12759 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12760
12761 ISEQ_BODY(iseq)->param.size = arg_size;
12762 ISEQ_BODY(iseq)->local_table_size = local_size;
12763 ISEQ_BODY(iseq)->stack_max = stack_max;
12764}
12765
12766/* for parser */
12767
12768int
12769rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12770{
12771 if (iseq) {
12772 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12773 while (body->type == ISEQ_TYPE_BLOCK ||
12774 body->type == ISEQ_TYPE_RESCUE ||
12775 body->type == ISEQ_TYPE_ENSURE ||
12776 body->type == ISEQ_TYPE_EVAL ||
12777 body->type == ISEQ_TYPE_MAIN
12778 ) {
12779 unsigned int i;
12780
12781 for (i = 0; i < body->local_table_size; i++) {
12782 if (body->local_table[i] == id) {
12783 return 1;
12784 }
12785 }
12786 iseq = body->parent_iseq;
12787 body = ISEQ_BODY(iseq);
12788 }
12789 }
12790 return 0;
12791}
12792
12793int
12794rb_local_defined(ID id, const rb_iseq_t *iseq)
12795{
12796 if (iseq) {
12797 unsigned int i;
12798 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12799
12800 for (i=0; i<body->local_table_size; i++) {
12801 if (body->local_table[i] == id) {
12802 return 1;
12803 }
12804 }
12805 }
12806 return 0;
12807}
12808
12809/* ISeq binary format */
12810
12811#ifndef IBF_ISEQ_DEBUG
12812#define IBF_ISEQ_DEBUG 0
12813#endif
12814
12815#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12816#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12817#endif
12818
12819typedef uint32_t ibf_offset_t;
12820#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12821
12822#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12823#ifdef RUBY_DEVEL
12824#define IBF_DEVEL_VERSION 12
12825#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12826#else
12827#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12828#endif
12829
12830static const char IBF_ENDIAN_MARK =
12831#ifdef WORDS_BIGENDIAN
12832 'b'
12833#else
12834 'l'
12835#endif
12836 ;
12837
12839 char magic[4]; /* YARB */
12840 uint32_t major_version;
12841 uint32_t minor_version;
12842 uint32_t size;
12843 uint32_t extra_size;
12844
12845 uint32_t iseq_list_size;
12846 uint32_t global_object_list_size;
12847 ibf_offset_t iseq_list_offset;
12848 ibf_offset_t global_object_list_offset;
12849 uint8_t endian;
12850 uint8_t wordsize; /* assume no 2048-bit CPU */
12851};
12852
12854 VALUE str;
12855 st_table *obj_table; /* obj -> obj number */
12856};
12857
12858struct ibf_dump {
12859 st_table *iseq_table; /* iseq -> iseq number */
12860 struct ibf_dump_buffer global_buffer;
12861 struct ibf_dump_buffer *current_buffer;
12862};
12863
12865 const char *buff;
12866 ibf_offset_t size;
12867
12868 VALUE obj_list; /* [obj0, ...] */
12869 unsigned int obj_list_size;
12870 ibf_offset_t obj_list_offset;
12871};
12872
12873struct ibf_load {
12874 const struct ibf_header *header;
12875 VALUE iseq_list; /* [iseq0, ...] */
12876 struct ibf_load_buffer global_buffer;
12877 VALUE loader_obj;
12878 rb_iseq_t *iseq;
12879 VALUE str;
12880 struct ibf_load_buffer *current_buffer;
12881};
12882
12884 long size;
12885 VALUE buffer[1];
12886};
12887
12888static void
12889pinned_list_mark(void *ptr)
12890{
12891 long i;
12892 struct pinned_list *list = (struct pinned_list *)ptr;
12893 for (i = 0; i < list->size; i++) {
12894 if (list->buffer[i]) {
12895 rb_gc_mark(list->buffer[i]);
12896 }
12897 }
12898}
12899
12900static const rb_data_type_t pinned_list_type = {
12901 "pinned_list",
12902 {
12903 pinned_list_mark,
12905 NULL, // No external memory to report,
12906 },
12907 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_EMBEDDABLE
12908};
12909
12910static VALUE
12911pinned_list_fetch(VALUE list, long offset)
12912{
12913 struct pinned_list * ptr;
12914
12915 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12916
12917 if (offset < 0 || offset >= ptr->size) {
12918 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12919 }
12920
12921 return ptr->buffer[offset];
12922}
12923
12924static void
12925pinned_list_store(VALUE list, long offset, VALUE object)
12926{
12927 struct pinned_list * ptr;
12928
12929 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12930
12931 if (offset < 0 || offset >= ptr->size) {
12932 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12933 }
12934
12935 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12936}
12937
12938static VALUE
12939pinned_list_new(long size)
12940{
12941 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12942 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12943 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12944 ptr->size = size;
12945 return obj_list;
12946}
12947
12948static ibf_offset_t
12949ibf_dump_pos(struct ibf_dump *dump)
12950{
12951 rb_len_t pos = RSTRING_LEN(dump->current_buffer->str);
12952#if SIZEOF_RB_LEN_T > SIZEOF_INT
12953 if (pos >= UINT_MAX) {
12954 rb_raise(rb_eRuntimeError, "dump size exceeds");
12955 }
12956#endif
12957 return (unsigned int)pos;
12958}
12959
12960static void
12961ibf_dump_align(struct ibf_dump *dump, size_t align)
12962{
12963 ibf_offset_t pos = ibf_dump_pos(dump);
12964 if (pos % align) {
12965 static const char padding[sizeof(VALUE)];
12966 size_t size = align - ((size_t)pos % align);
12967#if SIZEOF_RB_LEN_T > SIZEOF_INT
12968 if (pos + size >= UINT_MAX) {
12969 rb_raise(rb_eRuntimeError, "dump size exceeds");
12970 }
12971#endif
12972 for (; size > sizeof(padding); size -= sizeof(padding)) {
12973 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12974 }
12975 rb_str_cat(dump->current_buffer->str, padding, size);
12976 }
12977}
12978
12979static ibf_offset_t
12980ibf_dump_write(struct ibf_dump *dump, const void *buff, size_t size)
12981{
12982 ibf_offset_t pos = ibf_dump_pos(dump);
12983#if SIZEOF_RB_LEN_T > SIZEOF_INT
12984 /* ensure the resulting dump does not exceed UINT_MAX */
12985 if (size >= UINT_MAX || pos + size >= UINT_MAX) {
12986 rb_raise(rb_eRuntimeError, "dump size exceeds");
12987 }
12988#endif
12989 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12990 return pos;
12991}
12992
12993static ibf_offset_t
12994ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12995{
12996 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12997}
12998
12999static void
13000ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, rb_len_t offset)
13001{
13002 VALUE str = dump->current_buffer->str;
13003 char *ptr = RSTRING_PTR(str);
13004 if ((rb_ulen_t)(size + offset) > (rb_ulen_t)RSTRING_LEN(str))
13005 rb_bug("ibf_dump_overwrite: overflow");
13006 memcpy(ptr + offset, buff, size);
13007}
13008
13009static const void *
13010ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
13011{
13012 ibf_offset_t beg = *offset;
13013 *offset += size;
13014 return load->current_buffer->buff + beg;
13015}
13016
13017static void *
13018ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
13019{
13020 void *buff = ruby_xmalloc2(x, y);
13021 size_t size = x * y;
13022 memcpy(buff, load->current_buffer->buff + offset, size);
13023 return buff;
13024}
13025
13026#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
13027
13028#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
13029#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
13030#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
13031#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
13032#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
13033
13034static int
13035ibf_table_lookup(struct st_table *table, st_data_t key)
13036{
13037 st_data_t val;
13038
13039 if (st_lookup(table, key, &val)) {
13040 return (int)val;
13041 }
13042 else {
13043 return -1;
13044 }
13045}
13046
13047static int
13048ibf_table_find_or_insert(struct st_table *table, st_data_t key)
13049{
13050 int index = ibf_table_lookup(table, key);
13051
13052 if (index < 0) { /* not found */
13053 index = (int)table->num_entries;
13054 st_insert(table, key, (st_data_t)index);
13055 }
13056
13057 return index;
13058}
13059
13060/* dump/load generic */
13061
13062static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
13063
13064static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
13065static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
13066
13067static st_table *
13068ibf_dump_object_table_new(void)
13069{
13070 st_table *obj_table = st_init_numtable(); /* need free */
13071 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
13072
13073 return obj_table;
13074}
13075
13076static VALUE
13077ibf_dump_object(struct ibf_dump *dump, VALUE obj)
13078{
13079 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
13080}
13081
13082static VALUE
13083ibf_dump_id(struct ibf_dump *dump, ID id)
13084{
13085 if (id == 0 || rb_id2name(id) == NULL) {
13086 return 0;
13087 }
13088 return ibf_dump_object(dump, rb_id2sym(id));
13089}
13090
13091static ID
13092ibf_load_id(const struct ibf_load *load, const ID id_index)
13093{
13094 if (id_index == 0) {
13095 return 0;
13096 }
13097 VALUE sym = ibf_load_object(load, id_index);
13098 if (rb_integer_type_p(sym)) {
13099 /* Load hidden local variables as indexes */
13100 return NUM2ULONG(sym);
13101 }
13102 return rb_sym2id(sym);
13103}
13104
13105/* dump/load: code */
13106
13107static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
13108
13109static int
13110ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
13111{
13112 if (iseq == NULL) {
13113 return -1;
13114 }
13115 else {
13116 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
13117 }
13118}
13119
13120static unsigned char
13121ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
13122{
13123 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
13124 return (unsigned char)load->current_buffer->buff[(*offset)++];
13125}
13126
13127/*
13128 * Small uint serialization
13129 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
13130 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
13131 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
13132 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
13133 * ...
13134 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
13135 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
13136 */
13137static void
13138ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
13139{
13140 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
13141 ibf_dump_write(dump, &x, sizeof(VALUE));
13142 return;
13143 }
13144
13145 enum { max_byte_length = sizeof(VALUE) + 1 };
13146
13147 unsigned char bytes[max_byte_length];
13148 ibf_offset_t n;
13149
13150 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
13151 bytes[max_byte_length - 1 - n] = (unsigned char)x;
13152 }
13153
13154 x <<= 1;
13155 x |= 1;
13156 x <<= n;
13157 bytes[max_byte_length - 1 - n] = (unsigned char)x;
13158 n++;
13159
13160 ibf_dump_write(dump, bytes + max_byte_length - n, n);
13161}
13162
13163static VALUE
13164ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
13165{
13166 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
13167 union { char s[sizeof(VALUE)]; VALUE v; } x;
13168
13169 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
13170 *offset += sizeof(VALUE);
13171
13172 return x.v;
13173 }
13174
13175 enum { max_byte_length = sizeof(VALUE) + 1 };
13176
13177 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
13178 const unsigned char c = buffer[*offset];
13179
13180 ibf_offset_t n =
13181 c & 1 ? 1 :
13182 c == 0 ? 9 : ntz_int32(c) + 1;
13183 VALUE x = (VALUE)c >> n;
13184
13185 if (*offset + n > load->current_buffer->size) {
13186 rb_raise(rb_eRuntimeError, "invalid byte sequence");
13187 }
13188
13189 ibf_offset_t i;
13190 for (i = 1; i < n; i++) {
13191 x <<= 8;
13192 x |= (VALUE)buffer[*offset + i];
13193 }
13194
13195 *offset += n;
13196 return x;
13197}
13198
13199static void
13200ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
13201{
13202 // short: index
13203 // short: name.length
13204 // bytes: name
13205 // // omit argc (only verify with name)
13206 ibf_dump_write_small_value(dump, (VALUE)bf->index);
13207
13208 size_t len = strlen(bf->name);
13209 ibf_dump_write_small_value(dump, (VALUE)len);
13210 ibf_dump_write(dump, bf->name, len);
13211}
13212
13213static const struct rb_builtin_function *
13214ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
13215{
13216 int i = (int)ibf_load_small_value(load, offset);
13217 int len = (int)ibf_load_small_value(load, offset);
13218 const char *name = (char *)ibf_load_ptr(load, offset, len);
13219
13220 if (0) {
13221 fprintf(stderr, "%.*s!!\n", len, name);
13222 }
13223
13224 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
13225 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
13226 if (strncmp(table[i].name, name, len) != 0) {
13227 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %.*s but %s)",
13228 i, len, name, table[i].name);
13229 }
13230 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
13231
13232 return &table[i];
13233}
13234
13235static ibf_offset_t
13236ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
13237{
13238 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13239 const int iseq_size = body->iseq_size;
13240 int code_index;
13241 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
13242
13243 ibf_offset_t offset = ibf_dump_pos(dump);
13244
13245 for (code_index=0; code_index<iseq_size;) {
13246 const VALUE insn = orig_code[code_index++];
13247 const char *types = insn_op_types(insn);
13248 int op_index;
13249
13250 /* opcode */
13251 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
13252 ibf_dump_write_small_value(dump, insn);
13253
13254 /* operands */
13255 for (op_index=0; types[op_index]; op_index++, code_index++) {
13256 VALUE op = orig_code[code_index];
13257 VALUE wv;
13258
13259 switch (types[op_index]) {
13260 case TS_CDHASH:
13261 case TS_VALUE:
13262 wv = ibf_dump_object(dump, op);
13263 break;
13264 case TS_ISEQ:
13265 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
13266 break;
13267 case TS_IC:
13268 {
13269 IC ic = (IC)op;
13270 VALUE arr = idlist_to_array(ic->segments);
13271 wv = ibf_dump_object(dump, arr);
13272 }
13273 break;
13274 case TS_ISE:
13275 case TS_IVC:
13276 case TS_ICVARC:
13277 {
13279 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
13280 }
13281 break;
13282 case TS_CALLDATA:
13283 {
13284 goto skip_wv;
13285 }
13286 case TS_ID:
13287 wv = ibf_dump_id(dump, (ID)op);
13288 break;
13289 case TS_FUNCPTR:
13290 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13291 goto skip_wv;
13292 case TS_BUILTIN:
13293 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
13294 goto skip_wv;
13295 default:
13296 wv = op;
13297 break;
13298 }
13299 ibf_dump_write_small_value(dump, wv);
13300 skip_wv:;
13301 }
13302 RUBY_ASSERT(insn_len(insn) == op_index+1);
13303 }
13304
13305 return offset;
13306}
13307
13308static VALUE *
13309ibf_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)
13310{
13311 VALUE iseqv = (VALUE)iseq;
13312 unsigned int code_index;
13313 ibf_offset_t reading_pos = bytecode_offset;
13314 VALUE *code = ZALLOC_N(VALUE, iseq_size);
13315
13316 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
13317 struct rb_call_data *cd_entries = load_body->call_data;
13318 int ic_index = 0;
13319
13320 load_body->iseq_encoded = code;
13321 load_body->iseq_size = iseq_size;
13322
13323 iseq_bits_t * mark_offset_bits;
13324 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
13325 load_body->mark_bits.single = 0;
13326 mark_offset_bits = &load_body->mark_bits.single;
13327 }
13328 else {
13329 load_body->mark_bits.list = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
13330 mark_offset_bits = load_body->mark_bits.list;
13331 }
13332 bool needs_bitmap = false;
13333
13334 for (code_index=0; code_index<iseq_size;) {
13335 /* opcode */
13336 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
13337 const char *types = insn_op_types(insn);
13338 int op_index;
13339
13340 code_index++;
13341
13342 /* operands */
13343 for (op_index=0; types[op_index]; op_index++, code_index++) {
13344 const char operand_type = types[op_index];
13345 switch (operand_type) {
13346 case TS_VALUE:
13347 {
13348 VALUE op = ibf_load_small_value(load, &reading_pos);
13349 VALUE v = ibf_load_object(load, op);
13350 code[code_index] = v;
13351 if (!SPECIAL_CONST_P(v)) {
13352 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13353 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13354 needs_bitmap = true;
13355 }
13356 break;
13357 }
13358 case TS_CDHASH:
13359 {
13360 VALUE op = ibf_load_small_value(load, &reading_pos);
13361 VALUE v = ibf_load_object(load, op);
13362
13363 // Overwrite the existing hash in the object list. This
13364 // is to keep the object alive during load time.
13365 // [Bug #17984] [ruby-core:104259]
13366 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
13367
13368 code[code_index] = v;
13369 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13370 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13371 needs_bitmap = true;
13372 break;
13373 }
13374 case TS_ISEQ:
13375 {
13376 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
13377 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
13378 code[code_index] = v;
13379 if (!SPECIAL_CONST_P(v)) {
13380 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13381 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13382 needs_bitmap = true;
13383 }
13384 break;
13385 }
13386 case TS_IC:
13387 {
13388 VALUE op = ibf_load_small_value(load, &reading_pos);
13389 VALUE arr = ibf_load_object(load, op);
13390
13391 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
13392 ic->segments = array_to_idlist(arr);
13393
13394 code[code_index] = (VALUE)ic;
13395 }
13396 break;
13397 case TS_ISE:
13398 case TS_ICVARC:
13399 case TS_IVC:
13400 {
13401 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
13402
13403 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
13404 code[code_index] = (VALUE)ic;
13405
13406 if (operand_type == TS_IVC) {
13407 IVC cache = (IVC)ic;
13408
13409 if (insn == BIN(setinstancevariable)) {
13410 ID iv_name = (ID)code[code_index - 1];
13411 cache->iv_set_name = iv_name;
13412 cache->value = IVAR_CACHE_INIT;
13413 }
13414 else {
13415 cache->iv_set_name = 0;
13416 cache->value = rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET);
13417 }
13418 }
13419
13420 }
13421 break;
13422 case TS_CALLDATA:
13423 {
13424 code[code_index] = (VALUE)cd_entries++;
13425 }
13426 break;
13427 case TS_ID:
13428 {
13429 VALUE op = ibf_load_small_value(load, &reading_pos);
13430 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
13431 }
13432 break;
13433 case TS_FUNCPTR:
13434 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13435 break;
13436 case TS_BUILTIN:
13437 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
13438 break;
13439 default:
13440 code[code_index] = ibf_load_small_value(load, &reading_pos);
13441 continue;
13442 }
13443 }
13444 if (insn_len(insn) != op_index+1) {
13445 rb_raise(rb_eRuntimeError, "operand size mismatch");
13446 }
13447 }
13448
13449 if (!needs_bitmap) {
13450 SIZED_FREE_N(load_body->mark_bits.list, ISEQ_MBITS_BUFLEN(iseq_size));
13451 load_body->mark_bits.list = NULL;
13452 }
13453
13454 RUBY_ASSERT(code_index == iseq_size);
13455 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
13456 return code;
13457}
13458
13459static ibf_offset_t
13460ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13461{
13462 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
13463
13464 if (opt_num > 0) {
13465 IBF_W_ALIGN(VALUE);
13466 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
13467 }
13468 else {
13469 return ibf_dump_pos(dump);
13470 }
13471}
13472
13473static VALUE *
13474ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
13475{
13476 if (opt_num > 0) {
13477 VALUE *table = ALLOC_N(VALUE, opt_num+1);
13478 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
13479 return table;
13480 }
13481 else {
13482 return NULL;
13483 }
13484}
13485
13486static ibf_offset_t
13487ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
13488{
13489 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
13490
13491 if (kw) {
13492 struct rb_iseq_param_keyword dump_kw = *kw;
13493 int dv_num = kw->num - kw->required_num;
13494 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
13495 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
13496 int i;
13497
13498 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
13499 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
13500
13501 dump_kw.table = IBF_W(ids, ID, kw->num);
13502 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
13503 IBF_W_ALIGN(struct rb_iseq_param_keyword);
13504 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
13505 }
13506 else {
13507 return 0;
13508 }
13509}
13510
13511static const struct rb_iseq_param_keyword *
13512ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13513{
13514 if (param_keyword_offset) {
13515 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
13516 int dv_num = kw->num - kw->required_num;
13517 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
13518
13519 int i;
13520 for (i=0; i<dv_num; i++) {
13521 dvs[i] = ibf_load_object(load, dvs[i]);
13522 }
13523
13524 // Will be set once the local table is loaded.
13525 kw->table = NULL;
13526
13527 kw->default_values = dvs;
13528 return kw;
13529 }
13530 else {
13531 return NULL;
13532 }
13533}
13534
13535static ibf_offset_t
13536ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13537{
13538 ibf_offset_t offset = ibf_dump_pos(dump);
13539 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13540 const struct iseq_insn_info_entry *entries = body->insns_info.body;
13541
13542#ifdef USE_ISEQ_NODE_ID
13543 ibf_dump_write_small_value(dump, body->insns_info.node_ids_size);
13544#endif
13545 unsigned int i;
13546 for (i = 0; i < body->insns_info.size; i++) {
13547 ibf_dump_write_small_value(dump, entries[i].line_no);
13548 ibf_dump_write_small_value(dump, entries[i].events);
13549 }
13550#ifdef USE_ISEQ_NODE_ID
13551 if (body->insns_info.node_ids_size > 0) {
13552 ibf_dump_write(dump, body->insns_info.node_ids, body->insns_info.node_ids_size);
13553 }
13554#endif
13555
13556 return offset;
13557}
13558
13559static void
13560ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size,
13561 struct rb_iseq_constant_body *load_body)
13562{
13563 ibf_offset_t reading_pos = body_offset;
13564 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13565
13566#ifdef USE_ISEQ_NODE_ID
13567 const unsigned int node_ids_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13568#endif
13569 unsigned int i;
13570 for (i = 0; i < size; i++) {
13571 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13572 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13573 }
13574#ifdef USE_ISEQ_NODE_ID
13575 if (node_ids_size > 0) {
13576 if (node_ids_size > load->current_buffer->size - reading_pos) {
13577 rb_raise(rb_eRuntimeError, "invalid byte sequence");
13578 }
13579 uint8_t *node_ids = ALLOC_N(uint8_t, node_ids_size);
13580 memcpy(node_ids, load->current_buffer->buff + reading_pos, node_ids_size);
13581 load_body->insns_info.node_ids = node_ids;
13582 load_body->insns_info.node_ids_size = node_ids_size;
13583 }
13584#endif
13585 load_body->insns_info.body = entries;
13586}
13587
13588static ibf_offset_t
13589ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13590{
13591 ibf_offset_t offset = ibf_dump_pos(dump);
13592
13593 unsigned int last = 0;
13594 unsigned int i;
13595 for (i = 0; i < size; i++) {
13596 ibf_dump_write_small_value(dump, positions[i] - last);
13597 last = positions[i];
13598 }
13599
13600 return offset;
13601}
13602
13603static unsigned int *
13604ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13605{
13606 ibf_offset_t reading_pos = positions_offset;
13607 unsigned int *positions = ALLOC_N(unsigned int, size);
13608
13609 unsigned int last = 0;
13610 unsigned int i;
13611 for (i = 0; i < size; i++) {
13612 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13613 last = positions[i];
13614 }
13615
13616 return positions;
13617}
13618
13619static ibf_offset_t
13620ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13621{
13622 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13623 const int size = body->local_table_size;
13624 ID *table = ALLOCA_N(ID, size);
13625 int i;
13626
13627 for (i=0; i<size; i++) {
13628 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13629 if (v == 0) {
13630 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13631 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13632 }
13633 table[i] = v;
13634 }
13635
13636 IBF_W_ALIGN(ID);
13637 return ibf_dump_write(dump, table, sizeof(ID) * size);
13638}
13639
13640static const ID *
13641ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13642{
13643 if (size > 0) {
13644 ID *table = IBF_R(local_table_offset, ID, size);
13645 int i;
13646
13647 for (i=0; i<size; i++) {
13648 table[i] = ibf_load_id(load, table[i]);
13649 }
13650
13651 if (size == 1 && table[0] == idERROR_INFO) {
13652 ruby_xfree_sized(table, sizeof(ID) * size);
13653 return rb_iseq_shared_exc_local_tbl;
13654 }
13655 else {
13656 return table;
13657 }
13658 }
13659 else {
13660 return NULL;
13661 }
13662}
13663
13664static ibf_offset_t
13665ibf_dump_lvar_states(struct ibf_dump *dump, const rb_iseq_t *iseq)
13666{
13667 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13668 const int size = ISEQ_LVAR_STATES_BUFLEN(body->local_table_size);
13669 IBF_W_ALIGN(uint8_t);
13670 if (iseq_has_lvar_states_p(body)) {
13671 return ibf_dump_write(dump, iseq_lvar_states(body), sizeof(uint8_t) * size);
13672 }
13673 else {
13674 return ibf_dump_write(dump, NULL, 0);
13675 }
13676}
13677
13678static void
13679ibf_load_lvar_states(const struct ibf_load *load, struct rb_iseq_constant_body *load_body, ibf_offset_t lvar_states_offset, int size, const ID *local_table)
13680{
13681 if (local_table == rb_iseq_shared_exc_local_tbl ||
13682 size <= 0) {
13683 load_body->lvar_states.list = NULL;
13684 }
13685 else if (ISEQ_LVAR_STATES_EMBED_P((unsigned int)size)) {
13686 ibf_offset_t pos = lvar_states_offset;
13687 const int len = sizeof(uint8_t) * ISEQ_LVAR_STATES_BUFLEN(size);
13688 memcpy(load_body->lvar_states.single, ibf_load_ptr(load, &pos, len), len);
13689 }
13690 else {
13691 load_body->lvar_states.list = IBF_R(lvar_states_offset, uint8_t, ISEQ_LVAR_STATES_BUFLEN(size));
13692 }
13693}
13694
13695static ibf_offset_t
13696ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13697{
13698 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13699
13700 if (table) {
13701 int *iseq_indices = ALLOCA_N(int, table->size);
13702 unsigned int i;
13703
13704 for (i=0; i<table->size; i++) {
13705 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13706 }
13707
13708 const ibf_offset_t offset = ibf_dump_pos(dump);
13709
13710 for (i=0; i<table->size; i++) {
13711 ibf_dump_write_small_value(dump, iseq_indices[i]);
13712 ibf_dump_write_small_value(dump, table->entries[i].type);
13713 ibf_dump_write_small_value(dump, table->entries[i].start);
13714 ibf_dump_write_small_value(dump, table->entries[i].end);
13715 ibf_dump_write_small_value(dump, table->entries[i].cont);
13716 ibf_dump_write_small_value(dump, table->entries[i].sp);
13717 }
13718 return offset;
13719 }
13720 else {
13721 return ibf_dump_pos(dump);
13722 }
13723}
13724
13725static void
13726ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size, const rb_iseq_t *parent_iseq)
13727{
13728 if (size) {
13729 struct iseq_catch_table *table = ruby_xcalloc(1, iseq_catch_table_bytes(size));
13730 table->size = size;
13731 ISEQ_BODY(parent_iseq)->catch_table = table;
13732
13733 ibf_offset_t reading_pos = catch_table_offset;
13734
13735 unsigned int i;
13736 for (i=0; i<table->size; i++) {
13737 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13738 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13739 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13740 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13741 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13742 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13743
13744 rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13745 RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
13746 }
13747 }
13748 else {
13749 ISEQ_BODY(parent_iseq)->catch_table = NULL;
13750 }
13751}
13752
13753static ibf_offset_t
13754ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13755{
13756 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13757 const unsigned int ci_size = body->ci_size;
13758 const struct rb_call_data *cds = body->call_data;
13759
13760 ibf_offset_t offset = ibf_dump_pos(dump);
13761
13762 unsigned int i;
13763
13764 for (i = 0; i < ci_size; i++) {
13765 const struct rb_callinfo *ci = cds[i].ci;
13766 if (ci != NULL) {
13767 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13768 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13769 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13770
13771 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13772 if (kwarg) {
13773 int len = kwarg->keyword_len;
13774 ibf_dump_write_small_value(dump, len);
13775 for (int j=0; j<len; j++) {
13776 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13777 ibf_dump_write_small_value(dump, keyword);
13778 }
13779 }
13780 else {
13781 ibf_dump_write_small_value(dump, 0);
13782 }
13783 }
13784 else {
13785 // TODO: truncate NULL ci from call_data.
13786 ibf_dump_write_small_value(dump, (VALUE)-1);
13787 }
13788 }
13789
13790 return offset;
13791}
13792
13794 ID id;
13795 VALUE name;
13796 VALUE val;
13797};
13798
13800 size_t num;
13801 struct outer_variable_pair pairs[1];
13802};
13803
13804static enum rb_id_table_iterator_result
13805store_outer_variable(ID id, VALUE val, void *dump)
13806{
13807 struct outer_variable_list *ovlist = dump;
13808 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13809 pair->id = id;
13810 pair->name = rb_id2str(id);
13811 pair->val = val;
13812 return ID_TABLE_CONTINUE;
13813}
13814
13815static int
13816outer_variable_cmp(const void *a, const void *b, void *arg)
13817{
13818 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13819 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13820
13821 if (!ap->name) {
13822 return -1;
13823 }
13824 else if (!bp->name) {
13825 return 1;
13826 }
13827
13828 return rb_str_cmp(ap->name, bp->name);
13829}
13830
13831static ibf_offset_t
13832ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13833{
13834 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13835
13836 ibf_offset_t offset = ibf_dump_pos(dump);
13837
13838 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13839 ibf_dump_write_small_value(dump, (VALUE)size);
13840 if (size > 0) {
13841 VALUE buff;
13842 size_t buffsize =
13843 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13844 offsetof(struct outer_variable_list, pairs),
13845 rb_eArgError);
13846 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13847 ovlist->num = 0;
13848 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13849 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13850 for (size_t i = 0; i < size; ++i) {
13851 ID id = ovlist->pairs[i].id;
13852 ID val = ovlist->pairs[i].val;
13853 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13854 ibf_dump_write_small_value(dump, val);
13855 }
13856 ALLOCV_END(buff);
13857 }
13858
13859 return offset;
13860}
13861
13862/* note that we dump out rb_call_info but load back rb_call_data */
13863static void
13864ibf_load_ci_entries(const struct ibf_load *load,
13865 ibf_offset_t ci_entries_offset,
13866 unsigned int ci_size,
13867 struct rb_call_data **cd_ptr)
13868{
13869 if (!ci_size) {
13870 *cd_ptr = NULL;
13871 return;
13872 }
13873
13874 ibf_offset_t reading_pos = ci_entries_offset;
13875
13876 unsigned int i;
13877
13878 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13879 *cd_ptr = cds;
13880
13881 for (i = 0; i < ci_size; i++) {
13882 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13883 if (mid_index != (VALUE)-1) {
13884 ID mid = ibf_load_id(load, mid_index);
13885 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13886 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13887
13888 struct rb_callinfo_kwarg *kwarg = NULL;
13889 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13890 if (kwlen > 0) {
13891 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13892 kwarg->references = 0;
13893 kwarg->keyword_len = kwlen;
13894 for (int j=0; j<kwlen; j++) {
13895 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13896 kwarg->keywords[j] = ibf_load_object(load, keyword);
13897 }
13898 }
13899
13900 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13901 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13902 cds[i].cc = vm_cc_empty();
13903 }
13904 else {
13905 // NULL ci
13906 cds[i].ci = NULL;
13907 cds[i].cc = NULL;
13908 }
13909 }
13910}
13911
13912static struct rb_id_table *
13913ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13914{
13915 ibf_offset_t reading_pos = outer_variables_offset;
13916
13917 struct rb_id_table *tbl = NULL;
13918
13919 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13920
13921 if (table_size > 0) {
13922 tbl = rb_id_table_create(table_size);
13923 }
13924
13925 for (size_t i = 0; i < table_size; i++) {
13926 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13927 VALUE value = ibf_load_small_value(load, &reading_pos);
13928 if (!key) key = rb_make_temporary_id(i);
13929 rb_id_table_insert(tbl, key, value);
13930 }
13931
13932 return tbl;
13933}
13934
13935static ibf_offset_t
13936ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13937{
13938 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13939
13940 unsigned int *positions;
13941
13942 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13943
13944 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13945 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13946
13947#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13948 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13949
13950 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13951 struct ibf_dump_buffer buffer;
13952 buffer.str = rb_str_new(0, 0);
13953 buffer.obj_table = ibf_dump_object_table_new();
13954 dump->current_buffer = &buffer;
13955#endif
13956
13957 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13958 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13959 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13960 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13961 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13962
13963 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13964 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13965 SIZED_FREE_N(positions, ISEQ_BODY(iseq)->insns_info.size);
13966
13967 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13968 const ibf_offset_t lvar_states_offset = ibf_dump_lvar_states(dump, iseq);
13969 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13970 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13971 /* a NULL parent (persisted root) and references outside a Proc#refined subtree dump come out absent (-1) */
13972 const int parent_iseq_index = ibf_table_lookup(dump->iseq_table, (st_data_t)ISEQ_BODY(iseq)->parent_iseq);
13973 const int local_iseq_index = ibf_table_lookup(dump->iseq_table, (st_data_t)ISEQ_BODY(iseq)->local_iseq);
13974 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13975 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13976 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13977
13978#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13979 ibf_offset_t local_obj_list_offset;
13980 unsigned int local_obj_list_size;
13981
13982 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13983#endif
13984
13985 ibf_offset_t body_offset = ibf_dump_pos(dump);
13986
13987 /* dump the constant body */
13988 unsigned int param_flags =
13989 (body->param.flags.has_lead << 0) |
13990 (body->param.flags.has_opt << 1) |
13991 (body->param.flags.has_rest << 2) |
13992 (body->param.flags.has_post << 3) |
13993 (body->param.flags.has_kw << 4) |
13994 (body->param.flags.has_kwrest << 5) |
13995 (body->param.flags.has_block << 6) |
13996 (body->param.flags.ambiguous_param0 << 7) |
13997 (body->param.flags.accepts_no_kwarg << 8) |
13998 (body->param.flags.ruby2_keywords << 9) |
13999 (body->param.flags.anon_rest << 10) |
14000 (body->param.flags.anon_kwrest << 11) |
14001 (body->param.flags.use_block << 12) |
14002 (body->param.flags.forwardable << 13) |
14003 (body->param.flags.accepts_no_block << 14);
14004
14005#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14006# define IBF_BODY_OFFSET(x) (x)
14007#else
14008# define IBF_BODY_OFFSET(x) (body_offset - (x))
14009#endif
14010
14011 ibf_dump_write_small_value(dump, body->type);
14012 ibf_dump_write_small_value(dump, body->iseq_size);
14013 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
14014 ibf_dump_write_small_value(dump, bytecode_size);
14015 ibf_dump_write_small_value(dump, param_flags);
14016 ibf_dump_write_small_value(dump, body->param.size);
14017 ibf_dump_write_small_value(dump, body->param.lead_num);
14018 ibf_dump_write_small_value(dump, body->param.opt_num);
14019 ibf_dump_write_small_value(dump, body->param.rest_start);
14020 ibf_dump_write_small_value(dump, body->param.post_start);
14021 ibf_dump_write_small_value(dump, body->param.post_num);
14022 ibf_dump_write_small_value(dump, body->param.block_start);
14023 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
14024 ibf_dump_write_small_value(dump, param_keyword_offset);
14025 ibf_dump_write_small_value(dump, location_pathobj_index);
14026 ibf_dump_write_small_value(dump, body->no_realpath);
14027 ibf_dump_write_small_value(dump, location_label_index);
14028 ibf_dump_write_small_value(dump, body->location.first_lineno);
14029 ibf_dump_write_small_value(dump, body->location.node_id);
14030 /* Dump the source hash (0 if unavailable) in two 32-bit halves, because
14031 * VALUE may be 32 bits wide. */
14032 ibf_dump_write_small_value(dump, (VALUE)(uint32_t)(body->source_hash >> 32));
14033 ibf_dump_write_small_value(dump, (VALUE)(uint32_t)body->source_hash);
14034 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
14035 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
14036 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
14037 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
14038 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
14039 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
14040 ibf_dump_write_small_value(dump, body->insns_info.size);
14041 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
14042 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(lvar_states_offset));
14043 ibf_dump_write_small_value(dump, catch_table_size);
14044 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
14045 ibf_dump_write_small_value(dump, parent_iseq_index);
14046 ibf_dump_write_small_value(dump, local_iseq_index);
14047 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
14048 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
14049 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
14050 ibf_dump_write_small_value(dump, ISEQ_FLIP_CNT(iseq));
14051 ibf_dump_write_small_value(dump, body->local_table_size);
14052 ibf_dump_write_small_value(dump, body->ivc_size);
14053 ibf_dump_write_small_value(dump, body->icvarc_size);
14054 ibf_dump_write_small_value(dump, body->ise_size);
14055 ibf_dump_write_small_value(dump, body->ic_size);
14056 ibf_dump_write_small_value(dump, body->ci_size);
14057 ibf_dump_write_small_value(dump, body->stack_max);
14058 ibf_dump_write_small_value(dump, body->builtin_attrs);
14059 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
14060
14061#undef IBF_BODY_OFFSET
14062
14063#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14064 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
14065
14066 dump->current_buffer = saved_buffer;
14067 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
14068
14069 ibf_offset_t offset = ibf_dump_pos(dump);
14070 ibf_dump_write_small_value(dump, iseq_start);
14071 ibf_dump_write_small_value(dump, iseq_length_bytes);
14072 ibf_dump_write_small_value(dump, body_offset);
14073
14074 ibf_dump_write_small_value(dump, local_obj_list_offset);
14075 ibf_dump_write_small_value(dump, local_obj_list_size);
14076
14077 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
14078
14079 return offset;
14080#else
14081 return body_offset;
14082#endif
14083}
14084
14085static VALUE
14086ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
14087{
14088 VALUE str = ibf_load_object(load, str_index);
14089 if (str != Qnil) {
14090 str = rb_fstring(str);
14091 }
14092 return str;
14093}
14094
14095static void
14096ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
14097{
14098 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
14099
14100 ibf_offset_t reading_pos = offset;
14101
14102#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14103 struct ibf_load_buffer *saved_buffer = load->current_buffer;
14104 load->current_buffer = &load->global_buffer;
14105
14106 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14107 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14108 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14109
14110 struct ibf_load_buffer buffer;
14111 buffer.buff = load->global_buffer.buff + iseq_start;
14112 buffer.size = iseq_length_bytes;
14113 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14114 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14115 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
14116
14117 load->current_buffer = &buffer;
14118 reading_pos = body_offset;
14119#endif
14120
14121#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14122# define IBF_BODY_OFFSET(x) (x)
14123#else
14124# define IBF_BODY_OFFSET(x) (offset - (x))
14125#endif
14126
14127 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
14128 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14129 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14130 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14131 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
14132 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14133 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
14134 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
14135 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
14136 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
14137 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
14138 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
14139 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14140 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14141 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
14142 const bool no_realpath = (bool)ibf_load_small_value(load, &reading_pos);
14143 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
14144 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
14145 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
14146 const uint64_t source_hash_hi = (uint64_t)ibf_load_small_value(load, &reading_pos);
14147 const uint64_t source_hash_lo = (uint64_t)ibf_load_small_value(load, &reading_pos);
14148 const uint64_t source_hash = (source_hash_hi << 32) | (uint32_t)source_hash_lo;
14149 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
14150 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
14151 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
14152 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
14153 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14154 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14155 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14156 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14157 const ibf_offset_t lvar_states_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14158 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14159 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14160 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
14161 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
14162 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
14163 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14164 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14165 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
14166 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14167
14168 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14169 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14170 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14171 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14172
14173 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14174 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
14175 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
14176 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
14177
14178 // setup fname and dummy frame
14179 VALUE path = ibf_load_object(load, location_pathobj_index);
14180 {
14181 VALUE realpath = Qnil;
14182
14183 if (RB_TYPE_P(path, T_STRING)) {
14184 path = rb_fstring(path);
14185 realpath = no_realpath ? Qnil : path;
14186 }
14187 else if (RB_TYPE_P(path, T_ARRAY)) {
14188 VALUE pathobj = path;
14189 if (RARRAY_LEN(pathobj) != 2) {
14190 rb_raise(rb_eRuntimeError, "path object size mismatch");
14191 }
14192 path = rb_fstring(RARRAY_AREF(pathobj, 0));
14193 realpath = RARRAY_AREF(pathobj, 1);
14194 if (!NIL_P(realpath)) {
14195 if (!RB_TYPE_P(realpath, T_STRING)) {
14196 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
14197 "(%x), path=%+"PRIsVALUE,
14198 realpath, TYPE(realpath), path);
14199 }
14200 realpath = rb_fstring(realpath);
14201 }
14202 }
14203 else {
14204 rb_raise(rb_eRuntimeError, "unexpected path object");
14205 }
14206 rb_iseq_pathobj_set(iseq, path, realpath);
14207 }
14208
14209 // push dummy frame
14210 rb_execution_context_t *ec = GET_EC();
14211 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
14212
14213#undef IBF_BODY_OFFSET
14214
14215 load_body->type = type;
14216 load_body->stack_max = stack_max;
14217 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
14218 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
14219 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
14220 load_body->param.flags.has_post = (param_flags >> 3) & 1;
14221 load_body->param.flags.has_kw = FALSE;
14222 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
14223 load_body->param.flags.has_block = (param_flags >> 6) & 1;
14224 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
14225 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
14226 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
14227 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
14228 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
14229 load_body->param.flags.use_block = (param_flags >> 12) & 1;
14230 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
14231 load_body->param.flags.accepts_no_block = (param_flags >> 14) & 1;
14232 load_body->param.size = param_size;
14233 load_body->param.lead_num = param_lead_num;
14234 load_body->param.opt_num = param_opt_num;
14235 load_body->param.rest_start = param_rest_start;
14236 load_body->param.post_start = param_post_start;
14237 load_body->param.post_num = param_post_num;
14238 load_body->param.block_start = param_block_start;
14239 load_body->local_table_size = local_table_size;
14240 load_body->ci_size = ci_size;
14241 load_body->insns_info.size = insns_info_size;
14242
14243 // variable is NULL from ZALLOC; only allocate if flip_count is non-zero.
14244 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
14245 if (variable_flip_count) {
14246 struct rb_iseq_variable *v = rb_iseq_variable_ensure(iseq);
14247 v->flip_count = variable_flip_count;
14248 }
14249
14250 load_body->location.first_lineno = location_first_lineno;
14251 load_body->location.node_id = location_node_id;
14252 load_body->source_hash = source_hash;
14253 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
14254 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
14255 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
14256 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
14257 load_body->builtin_attrs = builtin_attrs;
14258 load_body->prism = prism;
14259
14260 load_body->ivc_size = ivc_size;
14261 load_body->icvarc_size = icvarc_size;
14262 load_body->ise_size = ise_size;
14263 load_body->ic_size = ic_size;
14264
14265 if (ISEQ_IS_SIZE(load_body)) {
14266 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
14267 }
14268 else {
14269 load_body->is_entries = NULL;
14270 }
14271 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
14272 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
14273 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
14274 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
14275 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
14276 ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size, load_body);
14277 load_body->insns_info.positions_or_succ_index_table.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
14278 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
14279 ibf_load_lvar_states(load, load_body, lvar_states_offset, local_table_size, load_body->local_table);
14280 ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
14281
14282 const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
14283 const rb_iseq_t *local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
14284 const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
14285
14286 RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
14287 RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
14288 RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
14289
14290 // This must be done after the local table is loaded.
14291 if (load_body->param.keyword != NULL) {
14292 RUBY_ASSERT(load_body->local_table);
14293 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
14294 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
14295 }
14296
14297 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
14298#if VM_INSN_INFO_TABLE_IMPL == 2
14299 rb_iseq_insns_info_encode_positions(iseq);
14300#endif
14301
14302 rb_iseq_translate_threaded_code(iseq);
14303
14304#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14305 load->current_buffer = &load->global_buffer;
14306#endif
14307
14308 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
14309
14310#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14311 load->current_buffer = saved_buffer;
14312#endif
14313 verify_call_cache(iseq);
14314
14315 RB_GC_GUARD(dummy_frame);
14316 rb_vm_pop_frame_no_int(ec);
14317}
14318
14320{
14321 struct ibf_dump *dump;
14322 VALUE offset_list;
14323};
14324
14325static int
14326ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14327{
14328 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
14329 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
14330
14331 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
14332 rb_ary_push(args->offset_list, UINT2NUM(offset));
14333
14334 return ST_CONTINUE;
14335}
14336
14337static void
14338ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
14339{
14340 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
14341
14342 struct ibf_dump_iseq_list_arg args;
14343 args.dump = dump;
14344 args.offset_list = offset_list;
14345
14346 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
14347
14348 st_index_t i;
14349 st_index_t size = dump->iseq_table->num_entries;
14350 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
14351
14352 for (i = 0; i < size; i++) {
14353 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
14354 }
14355
14356 ibf_dump_align(dump, sizeof(ibf_offset_t));
14357 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
14358 header->iseq_list_size = (unsigned int)size;
14359}
14360
14361/*
14362 * Binary format
14363 * - ibf_object_header
14364 * - ibf_object_xxx (xxx is type)
14365 */
14366
14368 unsigned int type: 5;
14369 unsigned int special_const: 1;
14370 unsigned int frozen: 1;
14371 unsigned int internal: 1;
14372};
14373
14374enum ibf_object_class_index {
14375 IBF_OBJECT_CLASS_OBJECT,
14376 IBF_OBJECT_CLASS_ARRAY,
14377 IBF_OBJECT_CLASS_STANDARD_ERROR,
14378 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
14379 IBF_OBJECT_CLASS_TYPE_ERROR,
14380 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
14381};
14382
14384 long srcstr;
14385 char option;
14386};
14387
14389 long len;
14390 long keyval[FLEX_ARY_LEN];
14391};
14392
14394 long class_index;
14395 long len;
14396 long beg;
14397 long end;
14398 int excl;
14399};
14400
14402 ssize_t slen;
14403 BDIGIT digits[FLEX_ARY_LEN];
14404};
14405
14406enum ibf_object_data_type {
14407 IBF_OBJECT_DATA_ENCODING,
14408};
14409
14411 long a, b;
14412};
14413
14415 long str;
14416};
14417
14418#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
14419 ((((offset) - 1) / (align) + 1) * (align))
14420/* No cast, since it's UB to create an unaligned pointer.
14421 * Leave as void* for use with memcpy in those cases.
14422 * We align the offset, but the buffer pointer is only VALUE aligned,
14423 * so the returned pointer may be unaligned for `type` .*/
14424#define IBF_OBJBODY(type, offset) \
14425 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
14426
14427static const void *
14428ibf_load_check_offset(const struct ibf_load *load, size_t offset)
14429{
14430 if (offset >= load->current_buffer->size) {
14431 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
14432 }
14433 return load->current_buffer->buff + offset;
14434}
14435
14436NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
14437
14438static void
14439ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
14440{
14441 char buff[0x100];
14442 rb_raw_obj_info(buff, sizeof(buff), obj);
14443 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
14444}
14445
14446NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
14447
14448static VALUE
14449ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14450{
14451 rb_raise(rb_eArgError, "unsupported");
14453}
14454
14455static void
14456ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
14457{
14458 enum ibf_object_class_index cindex;
14459 if (obj == rb_cObject) {
14460 cindex = IBF_OBJECT_CLASS_OBJECT;
14461 }
14462 else if (obj == rb_cArray) {
14463 cindex = IBF_OBJECT_CLASS_ARRAY;
14464 }
14465 else if (obj == rb_eStandardError) {
14466 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
14467 }
14468 else if (obj == rb_eNoMatchingPatternError) {
14469 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
14470 }
14471 else if (obj == rb_eTypeError) {
14472 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
14473 }
14474 else if (obj == rb_eNoMatchingPatternKeyError) {
14475 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
14476 }
14477 else {
14478 rb_obj_info_dump(obj);
14479 rb_p(obj);
14480 rb_bug("unsupported class");
14481 }
14482 ibf_dump_write_small_value(dump, (VALUE)cindex);
14483}
14484
14485static VALUE
14486ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14487{
14488 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
14489
14490 switch (cindex) {
14491 case IBF_OBJECT_CLASS_OBJECT:
14492 return rb_cObject;
14493 case IBF_OBJECT_CLASS_ARRAY:
14494 return rb_cArray;
14495 case IBF_OBJECT_CLASS_STANDARD_ERROR:
14496 return rb_eStandardError;
14497 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
14499 case IBF_OBJECT_CLASS_TYPE_ERROR:
14500 return rb_eTypeError;
14501 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
14503 }
14504
14505 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
14506}
14507
14508
14509static void
14510ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
14511{
14512 double dbl = RFLOAT_VALUE(obj);
14513 (void)IBF_W(&dbl, double, 1);
14514}
14515
14516static VALUE
14517ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14518{
14519 double d;
14520 /* Avoid unaligned VFP load on ARMv7; IBF payload may be unaligned (C99 6.3.2.3 p7). */
14521 memcpy(&d, IBF_OBJBODY(double, offset), sizeof(d));
14522 VALUE f = DBL2NUM(d);
14523 if (!FLONUM_P(f)) RB_OBJ_SET_SHAREABLE(f);
14524 return f;
14525}
14526
14527static void
14528ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
14529{
14530 long encindex = (long)rb_enc_get_index(obj);
14531 rb_len_t len = RSTRING_LEN(obj);
14532 const char *ptr = RSTRING_PTR(obj);
14533
14534 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14535 rb_encoding *enc = rb_enc_from_index((int)encindex);
14536 const char *enc_name = rb_enc_name(enc);
14537 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
14538 }
14539
14540 ibf_dump_write_small_value(dump, encindex);
14541 ibf_dump_write_small_value(dump, len);
14542 IBF_WP(ptr, char, len);
14543}
14544
14545static VALUE
14546ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14547{
14548 ibf_offset_t reading_pos = offset;
14549
14550 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14551 const rb_len_t len = (rb_len_t)ibf_load_small_value(load, &reading_pos);
14552 const char *ptr = load->current_buffer->buff + reading_pos;
14553
14554 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14555 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14556 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14557 }
14558
14559 VALUE str;
14560 if (header->frozen && !header->internal) {
14561 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
14562 }
14563 else {
14564 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
14565
14566 if (header->internal) rb_obj_hide(str);
14567 if (header->frozen) str = rb_fstring(str);
14568 }
14569 return str;
14570}
14571
14572static void
14573ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
14574{
14575 VALUE srcstr = RREGEXP_SRC(obj);
14576 struct ibf_object_regexp regexp;
14577 regexp.option = (char)rb_reg_options(obj);
14578 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
14579
14580 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
14581 ibf_dump_write_small_value(dump, regexp.srcstr);
14582}
14583
14584static VALUE
14585ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14586{
14587 struct ibf_object_regexp regexp;
14588 regexp.option = ibf_load_byte(load, &offset);
14589 regexp.srcstr = ibf_load_small_value(load, &offset);
14590
14591 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14592 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
14593
14594 if (header->internal) rb_obj_hide(reg);
14595 if (header->frozen) RB_OBJ_SET_SHAREABLE(rb_obj_freeze(reg));
14596
14597 return reg;
14598}
14599
14600static void
14601ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
14602{
14603 rb_len_t i, len = RARRAY_LEN(obj);
14604 ibf_dump_write_small_value(dump, len);
14605 for (i=0; i<len; i++) {
14606 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
14607 ibf_dump_write_small_value(dump, index);
14608 }
14609}
14610
14611static VALUE
14612ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14613{
14614 ibf_offset_t reading_pos = offset;
14615
14616 const rb_len_t len = (rb_len_t)ibf_load_small_value(load, &reading_pos);
14617
14618 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
14619 int i;
14620
14621 for (i=0; i<len; i++) {
14622 const VALUE index = ibf_load_small_value(load, &reading_pos);
14623 rb_ary_push(ary, ibf_load_object(load, index));
14624 }
14625
14626 if (header->frozen) {
14627 rb_ary_freeze(ary);
14628 rb_ractor_make_shareable(ary); // TODO: check elements
14629 }
14630
14631 return ary;
14632}
14633
14634static int
14635ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14636{
14637 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14638
14639 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14640 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14641
14642 ibf_dump_write_small_value(dump, key_index);
14643 ibf_dump_write_small_value(dump, val_index);
14644 return ST_CONTINUE;
14645}
14646
14647static void
14648ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14649{
14650 long len = RHASH_SIZE(obj);
14651 ibf_dump_write_small_value(dump, (VALUE)len);
14652
14653 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14654}
14655
14656static VALUE
14657ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14658{
14659 long len = (long)ibf_load_small_value(load, &offset);
14660 VALUE obj = header->frozen ? rb_hash_alloc_fixed_size(rb_cHash, len) : rb_hash_new_capa(len);
14661 int i;
14662
14663 for (i = 0; i < len; i++) {
14664 VALUE key_index = ibf_load_small_value(load, &offset);
14665 VALUE val_index = ibf_load_small_value(load, &offset);
14666
14667 VALUE key = ibf_load_object(load, key_index);
14668 VALUE val = ibf_load_object(load, val_index);
14669 rb_hash_aset(obj, key, val);
14670 }
14671
14672 if (header->internal) rb_obj_hide(obj);
14673 if (header->frozen) {
14675 }
14676
14677 return obj;
14678}
14679
14680static int
14681ibf_dump_cdhash_i(st_data_t key, st_data_t val, st_data_t ptr)
14682{
14683 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14684
14685 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14686
14687 ibf_dump_write_small_value(dump, key_index);
14688 ibf_dump_write_small_value(dump, val);
14689 return ST_CONTINUE;
14690}
14691
14692static void
14693ibf_dump_object_imemo(struct ibf_dump *dump, VALUE obj)
14694{
14695 switch (imemo_type(obj)) {
14696 case imemo_cdhash: {
14697 st_table *tbl = rb_imemo_cdhash_tbl(obj);
14698
14699 long len = tbl->num_entries;
14700 ibf_dump_write_small_value(dump, (VALUE)len);
14701 if (len > 0) st_foreach(tbl, ibf_dump_cdhash_i, (VALUE)dump);
14702 break;
14703 }
14704 default:
14705 ibf_dump_object_unsupported(dump, obj);
14706 break;
14707 }
14708}
14709
14710static VALUE
14711ibf_load_object_imemo(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14712{
14713 long len = (long)ibf_load_small_value(load, &offset);
14714 VALUE obj = cdhash_new(len);
14715
14716 int i;
14717 for (i = 0; i < len; i++) {
14718 VALUE key_index = ibf_load_small_value(load, &offset);
14719 VALUE val = ibf_load_small_value(load, &offset);
14720
14721 VALUE key = ibf_load_object(load, key_index);
14722 cdhash_aset(obj, key, val);
14723 }
14724
14725 return obj;
14726}
14727
14728static void
14729ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14730{
14731 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14732 struct ibf_object_struct_range range;
14733 VALUE beg, end;
14734 IBF_ZERO(range);
14735 range.len = 3;
14736 range.class_index = 0;
14737
14738 rb_range_values(obj, &beg, &end, &range.excl);
14739 range.beg = (long)ibf_dump_object(dump, beg);
14740 range.end = (long)ibf_dump_object(dump, end);
14741
14742 IBF_W_ALIGN(struct ibf_object_struct_range);
14743 IBF_WV(range);
14744 }
14745 else {
14746 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14747 rb_class_name(CLASS_OF(obj)));
14748 }
14749}
14750
14751static VALUE
14752ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14753{
14754 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14755 VALUE beg = ibf_load_object(load, range->beg);
14756 VALUE end = ibf_load_object(load, range->end);
14757 VALUE obj = rb_range_new(beg, end, range->excl);
14758 if (header->internal) rb_obj_hide(obj);
14759 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14760 return obj;
14761}
14762
14763static void
14764ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14765{
14766 ssize_t len = BIGNUM_LEN(obj);
14767 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14768 BDIGIT *d = BIGNUM_DIGITS(obj);
14769
14770 (void)IBF_W(&slen, ssize_t, 1);
14771 IBF_WP(d, BDIGIT, len);
14772}
14773
14774static VALUE
14775ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14776{
14777 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14778 int sign = bignum->slen > 0;
14779 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14780 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14783 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14784 big_unpack_flags |
14785 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14786 if (header->internal) rb_obj_hide(obj);
14787 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14788 return obj;
14789}
14790
14791static void
14792ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14793{
14794 if (rb_data_is_encoding(obj)) {
14795 rb_encoding *enc = rb_to_encoding(obj);
14796 const char *name = rb_enc_name(enc);
14797 long len = strlen(name) + 1;
14798 long data[2];
14799 data[0] = IBF_OBJECT_DATA_ENCODING;
14800 data[1] = len;
14801 (void)IBF_W(data, long, 2);
14802 IBF_WP(name, char, len);
14803 }
14804 else {
14805 ibf_dump_object_unsupported(dump, obj);
14806 }
14807}
14808
14809static VALUE
14810ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14811{
14812 const long *body = IBF_OBJBODY(long, offset);
14813 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14814 /* const long len = body[1]; */
14815 const char *data = (const char *)&body[2];
14816
14817 switch (type) {
14818 case IBF_OBJECT_DATA_ENCODING:
14819 {
14820 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14821 return encobj;
14822 }
14823 }
14824
14825 return ibf_load_object_unsupported(load, header, offset);
14826}
14827
14828static void
14829ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14830{
14831 long data[2];
14832 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14833 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14834
14835 (void)IBF_W(data, long, 2);
14836}
14837
14838static VALUE
14839ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14840{
14841 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14842 VALUE a = ibf_load_object(load, nums->a);
14843 VALUE b = ibf_load_object(load, nums->b);
14844 VALUE obj = header->type == T_COMPLEX ?
14845 rb_complex_new(a, b) : rb_rational_new(a, b);
14846
14847 if (header->internal) rb_obj_hide(obj);
14848 if (header->frozen) rb_ractor_make_shareable(rb_obj_freeze(obj));
14849 return obj;
14850}
14851
14852static void
14853ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14854{
14855 ibf_dump_object_string(dump, rb_sym2str(obj));
14856}
14857
14858static VALUE
14859ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14860{
14861 ibf_offset_t reading_pos = offset;
14862
14863 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14864 const rb_len_t len = (rb_len_t)ibf_load_small_value(load, &reading_pos);
14865 const char *ptr = load->current_buffer->buff + reading_pos;
14866
14867 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14868 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14869 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14870 }
14871
14872 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14873 return ID2SYM(id);
14874}
14875
14876typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14877static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14878 ibf_dump_object_unsupported, /* T_NONE */
14879 ibf_dump_object_unsupported, /* T_OBJECT */
14880 ibf_dump_object_class, /* T_CLASS */
14881 ibf_dump_object_unsupported, /* T_MODULE */
14882 ibf_dump_object_float, /* T_FLOAT */
14883 ibf_dump_object_string, /* T_STRING */
14884 ibf_dump_object_regexp, /* T_REGEXP */
14885 ibf_dump_object_array, /* T_ARRAY */
14886 ibf_dump_object_hash, /* T_HASH */
14887 ibf_dump_object_struct, /* T_STRUCT */
14888 ibf_dump_object_bignum, /* T_BIGNUM */
14889 ibf_dump_object_unsupported, /* T_FILE */
14890 ibf_dump_object_data, /* T_DATA */
14891 ibf_dump_object_unsupported, /* T_MATCH */
14892 ibf_dump_object_complex_rational, /* T_COMPLEX */
14893 ibf_dump_object_complex_rational, /* T_RATIONAL */
14894 ibf_dump_object_unsupported, /* 0x10 */
14895 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14896 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14897 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14898 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14899 ibf_dump_object_unsupported, /* T_FIXNUM */
14900 ibf_dump_object_unsupported, /* T_UNDEF */
14901 ibf_dump_object_unsupported, /* 0x17 */
14902 ibf_dump_object_unsupported, /* 0x18 */
14903 ibf_dump_object_unsupported, /* 0x19 */
14904 ibf_dump_object_imemo, /* T_IMEMO 0x1a */
14905 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14906 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14907 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14908 ibf_dump_object_unsupported, /* 0x1e */
14909 ibf_dump_object_unsupported, /* 0x1f */
14910};
14911
14912static void
14913ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14914{
14915 unsigned char byte =
14916 (header.type << 0) |
14917 (header.special_const << 5) |
14918 (header.frozen << 6) |
14919 (header.internal << 7);
14920
14921 IBF_WV(byte);
14922}
14923
14924static struct ibf_object_header
14925ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14926{
14927 unsigned char byte = ibf_load_byte(load, offset);
14928
14929 struct ibf_object_header header;
14930 header.type = (byte >> 0) & 0x1f;
14931 header.special_const = (byte >> 5) & 0x01;
14932 header.frozen = (byte >> 6) & 0x01;
14933 header.internal = (byte >> 7) & 0x01;
14934
14935 return header;
14936}
14937
14938static ibf_offset_t
14939ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14940{
14941 struct ibf_object_header obj_header;
14942 ibf_offset_t current_offset;
14943 IBF_ZERO(obj_header);
14944 obj_header.type = TYPE(obj);
14945
14946 IBF_W_ALIGN(ibf_offset_t);
14947 current_offset = ibf_dump_pos(dump);
14948
14949 if (SPECIAL_CONST_P(obj) &&
14950 ! (SYMBOL_P(obj) ||
14951 RB_FLOAT_TYPE_P(obj))) {
14952 obj_header.special_const = TRUE;
14953 obj_header.frozen = TRUE;
14954 obj_header.internal = TRUE;
14955 ibf_dump_object_object_header(dump, obj_header);
14956 ibf_dump_write_small_value(dump, obj);
14957 }
14958 else {
14959 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14960 obj_header.special_const = FALSE;
14961 obj_header.frozen = OBJ_FROZEN(obj) ? TRUE : FALSE;
14962 ibf_dump_object_object_header(dump, obj_header);
14963 (*dump_object_functions[obj_header.type])(dump, obj);
14964 }
14965
14966 return current_offset;
14967}
14968
14969typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14970static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14971 ibf_load_object_unsupported, /* T_NONE */
14972 ibf_load_object_unsupported, /* T_OBJECT */
14973 ibf_load_object_class, /* T_CLASS */
14974 ibf_load_object_unsupported, /* T_MODULE */
14975 ibf_load_object_float, /* T_FLOAT */
14976 ibf_load_object_string, /* T_STRING */
14977 ibf_load_object_regexp, /* T_REGEXP */
14978 ibf_load_object_array, /* T_ARRAY */
14979 ibf_load_object_hash, /* T_HASH */
14980 ibf_load_object_struct, /* T_STRUCT */
14981 ibf_load_object_bignum, /* T_BIGNUM */
14982 ibf_load_object_unsupported, /* T_FILE */
14983 ibf_load_object_data, /* T_DATA */
14984 ibf_load_object_unsupported, /* T_MATCH */
14985 ibf_load_object_complex_rational, /* T_COMPLEX */
14986 ibf_load_object_complex_rational, /* T_RATIONAL */
14987 ibf_load_object_unsupported, /* 0x10 */
14988 ibf_load_object_unsupported, /* T_NIL */
14989 ibf_load_object_unsupported, /* T_TRUE */
14990 ibf_load_object_unsupported, /* T_FALSE */
14991 ibf_load_object_symbol,
14992 ibf_load_object_unsupported, /* T_FIXNUM */
14993 ibf_load_object_unsupported, /* T_UNDEF */
14994 ibf_load_object_unsupported, /* 0x17 */
14995 ibf_load_object_unsupported, /* 0x18 */
14996 ibf_load_object_unsupported, /* 0x19 */
14997 ibf_load_object_imemo, /* T_IMEMO 0x1a */
14998 ibf_load_object_unsupported, /* T_NODE 0x1b */
14999 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
15000 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
15001 ibf_load_object_unsupported, /* 0x1e */
15002 ibf_load_object_unsupported, /* 0x1f */
15003};
15004
15005static VALUE
15006ibf_load_object(const struct ibf_load *load, VALUE object_index)
15007{
15008 if (object_index == 0) {
15009 return Qnil;
15010 }
15011 else {
15012 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
15013 if (!obj) {
15014 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
15015 ibf_offset_t offset = offsets[object_index];
15016 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
15017
15018#if IBF_ISEQ_DEBUG
15019 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
15020 load->current_buffer->obj_list_offset, (void *)offsets, offset);
15021 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
15022 header.type, header.special_const, header.frozen, header.internal);
15023#endif
15024 if (offset >= load->current_buffer->size) {
15025 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
15026 }
15027
15028 if (header.special_const) {
15029 ibf_offset_t reading_pos = offset;
15030
15031 obj = ibf_load_small_value(load, &reading_pos);
15032 }
15033 else {
15034 obj = (*load_object_functions[header.type])(load, &header, offset);
15035 }
15036
15037 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
15038 }
15039#if IBF_ISEQ_DEBUG
15040 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
15041 object_index, obj);
15042#endif
15043 return obj;
15044 }
15045}
15046
15048{
15049 struct ibf_dump *dump;
15050 VALUE offset_list;
15051};
15052
15053static int
15054ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
15055{
15056 VALUE obj = (VALUE)key;
15057 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
15058
15059 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
15060 rb_ary_push(args->offset_list, UINT2NUM(offset));
15061
15062 return ST_CONTINUE;
15063}
15064
15065static void
15066ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
15067{
15068 st_table *obj_table = dump->current_buffer->obj_table;
15069 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
15070
15071 struct ibf_dump_object_list_arg args;
15072 args.dump = dump;
15073 args.offset_list = offset_list;
15074
15075 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
15076
15077 IBF_W_ALIGN(ibf_offset_t);
15078 *obj_list_offset = ibf_dump_pos(dump);
15079
15080 st_index_t size = obj_table->num_entries;
15081 st_index_t i;
15082
15083 for (i=0; i<size; i++) {
15084 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
15085 IBF_WV(offset);
15086 }
15087
15088 *obj_list_size = (unsigned int)size;
15089}
15090
15091static void
15092ibf_dump_mark(void *ptr)
15093{
15094 struct ibf_dump *dump = (struct ibf_dump *)ptr;
15095 rb_gc_mark(dump->global_buffer.str);
15096
15097 rb_mark_set(dump->global_buffer.obj_table);
15098 rb_mark_set(dump->iseq_table);
15099}
15100
15101static void
15102ibf_dump_free(void *ptr)
15103{
15104 struct ibf_dump *dump = (struct ibf_dump *)ptr;
15105 if (dump->global_buffer.obj_table) {
15106 st_free_table(dump->global_buffer.obj_table);
15107 dump->global_buffer.obj_table = 0;
15108 }
15109 if (dump->iseq_table) {
15110 st_free_table(dump->iseq_table);
15111 dump->iseq_table = 0;
15112 }
15113}
15114
15115static size_t
15116ibf_dump_memsize(const void *ptr)
15117{
15118 struct ibf_dump *dump = (struct ibf_dump *)ptr;
15119 size_t size = 0;
15120 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
15121 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
15122 return size;
15123}
15124
15125static const rb_data_type_t ibf_dump_type = {
15126 "ibf_dump",
15127 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
15128 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_EMBEDDABLE
15129};
15130
15131static void
15132ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
15133{
15134 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
15135 dump->iseq_table = NULL;
15136
15137 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
15138 dump->global_buffer.obj_table = ibf_dump_object_table_new();
15139 dump->iseq_table = st_init_numtable(); /* need free */
15140
15141 dump->current_buffer = &dump->global_buffer;
15142}
15143
15144static VALUE
15145iseq_ibf_dump_0(struct ibf_dump *dump, const rb_iseq_t *iseq, VALUE opt)
15146{
15147 struct ibf_header header = {{0}};
15148
15149 ibf_dump_write(dump, &header, sizeof(header));
15150 ibf_dump_iseq(dump, iseq);
15151
15152 header.magic[0] = 'Y'; /* YARB */
15153 header.magic[1] = 'A';
15154 header.magic[2] = 'R';
15155 header.magic[3] = 'B';
15156 header.major_version = IBF_MAJOR_VERSION;
15157 header.minor_version = IBF_MINOR_VERSION;
15158 header.endian = IBF_ENDIAN_MARK;
15159 header.wordsize = (uint8_t)SIZEOF_VALUE;
15160 ibf_dump_iseq_list(dump, &header);
15161 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
15162 header.size = ibf_dump_pos(dump);
15163
15164 if (RTEST(opt)) {
15165 VALUE opt_str = opt;
15166 const char *ptr = StringValuePtr(opt_str);
15167 header.extra_size = RSTRING_LENINT(opt_str);
15168 ibf_dump_write(dump, ptr, header.extra_size);
15169 }
15170 else {
15171 header.extra_size = 0;
15172 }
15173
15174 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
15175
15176 return dump->global_buffer.str;
15177}
15178
15179VALUE
15180rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
15181{
15182 struct ibf_dump *dump;
15183 VALUE dump_obj;
15184 VALUE str;
15185
15186 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
15187 ISEQ_BODY(iseq)->local_iseq != iseq) {
15188 rb_raise(rb_eRuntimeError, "should be top of iseq");
15189 }
15190 if (RTEST(ISEQ_COVERAGE(iseq))) {
15191 rb_raise(rb_eRuntimeError, "should not compile with coverage");
15192 }
15193
15194 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
15195 ibf_dump_setup(dump, dump_obj);
15196
15197 str = iseq_ibf_dump_0(dump, iseq, opt);
15198 RB_GC_GUARD(dump_obj);
15199 return str;
15200}
15201
15202static const ibf_offset_t *
15203ibf_iseq_list(const struct ibf_load *load)
15204{
15205 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
15206}
15207
15208void
15209rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
15210{
15211 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
15212 rb_iseq_t *prev_src_iseq = load->iseq;
15213 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
15214 load->iseq = iseq;
15215#if IBF_ISEQ_DEBUG
15216 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
15217 iseq->aux.loader.index, offset,
15218 load->header->size);
15219#endif
15220 ibf_load_iseq_each(load, iseq, offset);
15221 ISEQ_COMPILE_DATA_CLEAR(iseq);
15222 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
15223 rb_iseq_init_trace(iseq);
15224 load->iseq = prev_src_iseq;
15225}
15226
15227#if USE_LAZY_LOAD
15228const rb_iseq_t *
15229rb_iseq_complete(const rb_iseq_t *iseq)
15230{
15231 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
15232 return iseq;
15233}
15234#endif
15235
15236static rb_iseq_t *
15237ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
15238{
15239 int iseq_index = (int)(VALUE)index_iseq;
15240
15241#if IBF_ISEQ_DEBUG
15242 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
15243 (void *)index_iseq, (void *)load->iseq_list);
15244#endif
15245 if (iseq_index == -1) {
15246 return NULL;
15247 }
15248 else {
15249 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
15250
15251#if IBF_ISEQ_DEBUG
15252 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
15253#endif
15254 if (iseqv) {
15255 return (rb_iseq_t *)iseqv;
15256 }
15257 else {
15258 rb_iseq_t *iseq = iseq_imemo_alloc();
15259#if IBF_ISEQ_DEBUG
15260 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
15261#endif
15262 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
15263 RB_OBJ_WRITE((VALUE)iseq, &iseq->aux.loader.obj, load->loader_obj);
15264 iseq->aux.loader.index = iseq_index;
15265#if IBF_ISEQ_DEBUG
15266 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
15267 (void *)iseq, (void *)load->loader_obj, iseq_index);
15268#endif
15269 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
15270
15271 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
15272#if IBF_ISEQ_DEBUG
15273 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
15274#endif
15275 rb_ibf_load_iseq_complete(iseq);
15276 }
15277
15278#if IBF_ISEQ_DEBUG
15279 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
15280 (void *)iseq, (void *)load->iseq);
15281#endif
15282 return iseq;
15283 }
15284 }
15285}
15286
15287static void
15288ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
15289{
15290 struct ibf_header *header = (struct ibf_header *)bytes;
15291 load->loader_obj = loader_obj;
15292 load->global_buffer.buff = bytes;
15293 load->header = header;
15294 load->global_buffer.size = header->size;
15295 load->global_buffer.obj_list_offset = header->global_object_list_offset;
15296 load->global_buffer.obj_list_size = header->global_object_list_size;
15297 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
15298 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
15299 load->iseq = NULL;
15300
15301 load->current_buffer = &load->global_buffer;
15302
15303 if (size < header->size) {
15304 rb_raise(rb_eRuntimeError, "broken binary format");
15305 }
15306 if (strncmp(header->magic, "YARB", 4) != 0) {
15307 rb_raise(rb_eRuntimeError, "unknown binary format");
15308 }
15309 if (header->major_version != IBF_MAJOR_VERSION ||
15310 header->minor_version != IBF_MINOR_VERSION) {
15311 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
15312 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
15313 }
15314 if (header->endian != IBF_ENDIAN_MARK) {
15315 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
15316 }
15317 if (header->wordsize != SIZEOF_VALUE) {
15318 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
15319 }
15320 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
15321 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
15322 header->iseq_list_offset);
15323 }
15324 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
15325 rb_raise(rb_eArgError, "unaligned object list offset: %u",
15326 load->global_buffer.obj_list_offset);
15327 }
15328}
15329
15330static void
15331ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
15332{
15333 StringValue(str);
15334
15335 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
15336 rb_raise(rb_eRuntimeError, "broken binary format");
15337 }
15338
15339 if (USE_LAZY_LOAD) {
15340 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
15341 }
15342
15343 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
15344 RB_OBJ_WRITE(loader_obj, &load->str, str);
15345}
15346
15347static void
15348ibf_loader_mark(void *ptr)
15349{
15350 struct ibf_load *load = (struct ibf_load *)ptr;
15351 rb_gc_mark(load->str);
15352 rb_gc_mark(load->iseq_list);
15353 rb_gc_mark(load->global_buffer.obj_list);
15354}
15355
15356static void
15357ibf_loader_free(void *ptr)
15358{
15359 struct ibf_load *load = (struct ibf_load *)ptr;
15360 SIZED_FREE(load);
15361}
15362
15363static size_t
15364ibf_loader_memsize(const void *ptr)
15365{
15366 return sizeof(struct ibf_load);
15367}
15368
15369static const rb_data_type_t ibf_load_type = {
15370 "ibf_loader",
15371 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
15372 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_THREAD_SAFE_FREE
15373};
15374
15375const rb_iseq_t *
15376rb_iseq_ibf_load(VALUE str)
15377{
15378 struct ibf_load *load;
15379 rb_iseq_t *iseq;
15380 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15381
15382 ibf_load_setup(load, loader_obj, str);
15383 iseq = ibf_load_iseq(load, 0);
15384
15385 RB_GC_GUARD(loader_obj);
15386 return iseq;
15387}
15388
15389const rb_iseq_t *
15390rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
15391{
15392 struct ibf_load *load;
15393 rb_iseq_t *iseq;
15394 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15395
15396 ibf_load_setup_bytes(load, loader_obj, bytes, size);
15397 iseq = ibf_load_iseq(load, 0);
15398
15399 RB_GC_GUARD(loader_obj);
15400 return iseq;
15401}
15402
15403/* collect the iseq table into an array indexed by iseq-list index */
15404static int
15405ibf_dump_iseq_table_collect_i(st_data_t key, st_data_t val, st_data_t arg)
15406{
15407 const rb_iseq_t **srcs = (const rb_iseq_t **)arg;
15408 srcs[(int)val] = (const rb_iseq_t *)key;
15409 return ST_CONTINUE;
15410}
15411
15412/* pc2branchindex (branch coverage) is per-iseq, so pair each copy with its
15413 * source by list index */
15414static void
15415iseq_subtree_copy_pc2branchindex(const struct ibf_dump *dump, const struct ibf_load *load)
15416{
15417 unsigned int iseq_count = (unsigned int)dump->iseq_table->num_entries;
15418 VALUE srcs_buf;
15419 const rb_iseq_t **srcs = ALLOCV_N(const rb_iseq_t *, srcs_buf, iseq_count);
15420 st_foreach(dump->iseq_table, ibf_dump_iseq_table_collect_i, (st_data_t)srcs);
15421
15422 for (unsigned int i = 0; i < iseq_count; i++) {
15423 rb_iseq_t *copy = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)i);
15424 VALUE pc2branchindex = ISEQ_PC2BRANCHINDEX(srcs[i]);
15425 if (pc2branchindex != Qnil) {
15426 ISEQ_PC2BRANCHINDEX_SET(copy, pc2branchindex);
15427 }
15428 }
15429
15430 ALLOCV_END(srcs_buf);
15431}
15432
15433/* Deep-copy an iseq subtree with independent inline caches for Proc#refined */
15434const rb_iseq_t *
15435rb_iseq_dup_with_independent_caches(const rb_iseq_t *src_root)
15436{
15437 struct ibf_dump *dump;
15438 VALUE dump_obj;
15439 VALUE str;
15440
15441 /* --- dump the subtree --- */
15442 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
15443 ibf_dump_setup(dump, dump_obj);
15444
15445 str = iseq_ibf_dump_0(dump, src_root, Qnil);
15446
15447 /* --- load it back --- */
15448 struct ibf_load *load;
15449 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15450 ibf_load_setup(load, loader_obj, str);
15451
15452 /* What the loader could not reconstruct is the same for every iseq in
15453 * the subtree: the only absent parent is the top's, every absent
15454 * local_iseq is the source's local root (runtime walks compare it
15455 * against the original frames, so a copy must not stand in), and
15456 * pathobj/script_lines/coverage are per-file values. */
15457 const struct rb_iseq_constant_body *sb = ISEQ_BODY(src_root);
15458 unsigned int iseq_count = (unsigned int)dump->iseq_table->num_entries;
15459 const rb_iseq_t *result = NULL;
15460 for (unsigned int i = 0; i < iseq_count; i++) {
15461 rb_iseq_t *copy = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)i);
15462 /* force completion even under USE_LAZY_LOAD */
15463 if (FL_TEST((VALUE)copy, ISEQ_NOT_LOADED_YET)) {
15464 rb_ibf_load_iseq_complete(copy);
15465 }
15466
15467 FL_SET((VALUE)copy, ISEQ_REFINED_COPY);
15468
15469 struct rb_iseq_constant_body *cb = ISEQ_BODY(copy);
15470 if (!cb->local_iseq) RB_OBJ_WRITE(copy, &cb->local_iseq, sb->local_iseq);
15471 RB_OBJ_WRITE(copy, &cb->location.pathobj, sb->location.pathobj);
15472 cb->no_realpath = sb->no_realpath;
15473 VALUE sl = ISEQ_SCRIPT_LINES(src_root);
15474 VALUE cov = ISEQ_COVERAGE(src_root);
15475 if (!NIL_P(sl) || !NIL_P(cov)) {
15476 struct rb_iseq_variable *v = rb_iseq_variable_ensure(copy);
15477 RB_OBJ_WRITE(copy, &v->script_lines, sl);
15478 RB_OBJ_WRITE(copy, &v->coverage, cov);
15479 }
15480
15481 if (i == 0) {
15482 RB_OBJ_WRITE(copy, &cb->parent_iseq, sb->parent_iseq);
15483 result = copy;
15484 }
15485
15486 /* Shared across Ractors through the Proc#refined memo; the duplicated
15487 * subtree is self-contained, so mark each copy shareable. */
15489 }
15490
15491 if (ISEQ_PC2BRANCHINDEX(src_root) != Qnil) {
15492 iseq_subtree_copy_pc2branchindex(dump, load);
15493 }
15494
15495 RB_GC_GUARD(dump_obj);
15496 RB_GC_GUARD(loader_obj);
15497 return result;
15498}
15499
15500VALUE
15501rb_iseq_ibf_load_extra_data(VALUE str)
15502{
15503 struct ibf_load *load;
15504 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15505 VALUE extra_str;
15506
15507 ibf_load_setup(load, loader_obj, str);
15508 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
15509 RB_GC_GUARD(loader_obj);
15510 return extra_str;
15511}
15512
15513#include "prism_compile.c"
#define RUBY_ATOMIC_PTR_LOAD(var)
Identical to RUBY_ATOMIC_LOAD, except it expects its arguments are void*.
Definition atomic.h:348
#define LONG_LONG
Definition long_long.h:38
#define RUBY_ALIGNOF
Wraps (or simulates) alignof.
Definition stdalign.h:28
#define RUBY_EVENT_END
Encountered an end of a class clause.
Definition event.h:40
#define RUBY_EVENT_C_CALL
A method, written in C, is called.
Definition event.h:43
#define RUBY_EVENT_B_RETURN
Encountered a next statement.
Definition event.h:56
#define RUBY_EVENT_CLASS
Encountered a new class.
Definition event.h:39
#define RUBY_EVENT_NONE
No events.
Definition event.h:37
#define RUBY_EVENT_LINE
Encountered a new line.
Definition event.h:38
#define RUBY_EVENT_RETURN
Encountered a return statement.
Definition event.h:42
#define RUBY_EVENT_C_RETURN
Return from a method, written in C.
Definition event.h:44
#define RUBY_EVENT_B_CALL
Encountered an yield statement.
Definition event.h:55
uint32_t rb_event_flag_t
Represents event(s).
Definition event.h:108
#define RUBY_EVENT_CALL
A method, written in Ruby, is called.
Definition event.h:41
#define RUBY_EVENT_RESCUE
Encountered a rescue statement.
Definition event.h:61
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1700
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
Definition value_type.h:59
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define NUM2ULONG
Old name of RB_NUM2ULONG.
Definition long.h:52
#define NUM2LL
Old name of RB_NUM2LL.
Definition long_long.h:34
#define ALLOCV
Old name of RB_ALLOCV.
Definition memory.h:407
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
Definition fl_type.h:133
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1708
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define T_FLOAT
Old name of RUBY_T_FLOAT.
Definition value_type.h:64
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:131
#define ULONG2NUM
Old name of RB_ULONG2NUM.
Definition long.h:60
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:405
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define FIXABLE
Old name of RB_FIXABLE.
Definition fixnum.h:25
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition memory.h:404
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition assume.h:27
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition value_type.h:76
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:402
#define FL_SET
Old name of RB_FL_SET.
Definition fl_type.h:125
#define FLONUM_P
Old name of RB_FLONUM_P.
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:408
#define NUM2ULL
Old name of RB_NUM2ULL.
Definition long_long.h:35
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
#define FL_TEST
Old name of RB_FL_TEST.
Definition fl_type.h:127
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition fl_type.h:129
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:409
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define T_REGEXP
Old name of RUBY_T_REGEXP.
Definition value_type.h:77
#define ruby_debug
This variable controls whether the interpreter is in debug mode.
Definition error.h:487
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1467
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1454
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1457
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1470
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:691
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1455
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:464
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition error.c:1471
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1459
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1474
@ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
Warning is for checking unused block strictly.
Definition error.h:57
VALUE rb_obj_reveal(VALUE obj, VALUE klass)
Make a hidden object visible again.
Definition object.c:103
VALUE rb_cArray
Array class.
VALUE rb_cObject
Object class.
Definition object.c:60
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:94
VALUE rb_cHash
Hash class.
Definition hash.c:123
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:665
VALUE rb_cRange
Range class.
Definition range.c:35
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:902
VALUE rb_obj_freeze(VALUE obj)
Same as RB_OBJ_FREEZE(), but returns the given object.
Definition object.c:1305
#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:504
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:492
#define RBIMPL_ASSERT_OR_ASSUME(...)
This is either RUBY_ASSERT or RBIMPL_ASSUME, depending on RUBY_DEBUG.
Definition assert.h:311
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
#define RB_POSFIXABLE(_)
Checks if the passed value is in range of fixnum, assuming it is a positive number.
Definition fixnum.h:43
#define RBIMPL_ATTR_FORMAT(x, y, z)
Wraps (or simulates) __attribute__((format))
Definition format.h:33
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_reverse(VALUE ary)
Destructively reverses the passed array in-place.
VALUE rb_ary_resurrect(VALUE ary)
I guess there is no use case of this function in extension libraries, but this is a routine identical...
VALUE rb_ary_entry(VALUE ary, rb_len_t off)
Queries an element of an array.
VALUE rb_ary_new_capa(rb_len_t capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
void rb_ary_store(VALUE ary, rb_len_t key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_clear(VALUE ary)
Destructively removes everything form an array.
VALUE rb_ary_hidden_new(rb_len_t capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
VALUE rb_ary_cat(VALUE ary, const VALUE *train, rb_len_t len)
Destructively appends multiple elements at the end of the array.
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
#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:550
#define INTEGER_PACK_NEGATIVE
Interprets the input as a signed negative number (unpack only).
Definition bignum.h:568
#define INTEGER_PACK_LSWORD_FIRST
Stores/interprets the least significant word as the first word.
Definition bignum.h:532
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1241
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1265
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c:1857
VALUE rb_range_new(VALUE beg, VALUE end, int excl)
Creates a new Range.
Definition range.c:77
VALUE rb_rational_new(VALUE num, VALUE den)
Constructs a Rational, with reduction.
Definition rational.c:2006
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
Definition re.c:5089
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:4005
VALUE rb_str_tmp_new(rb_len_t len)
Allocates a "temporary" string.
Definition string.c:1809
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4377
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1523
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4363
VALUE rb_str_cat(VALUE dst, const char *src, rb_len_t srclen)
Destructively appends the passed contents to the string.
Definition string.c:3773
VALUE rb_str_resurrect(VALUE str)
Like rb_str_dup(), but always create an instance of rb_cString regardless of the given object's class...
Definition string.c:2068
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:3971
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4449
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:4251
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3480
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1539
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:516
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:285
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
Definition symbol.c:1135
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:1154
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:1097
int len
Length of the buffer.
Definition io.h:8
#define RB_OBJ_SET_SHAREABLE(obj)
Wrapper of rb_obj_set_shareable().
Definition ractor.h:290
#define RB_OBJ_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
Definition ractor.h:255
static VALUE RB_OBJ_SET_FROZEN_SHAREABLE(VALUE obj)
Freezes and marks the object as shareable.
Definition ractor.h:301
VALUE rb_ractor_make_shareable(VALUE obj)
Destructively transforms the passed object so that multiple Ractors can share it.
Definition ractor.c:2018
#define DECIMAL_SIZE_OF(expr)
An approximation of decimal representation size.
Definition util.h:48
void ruby_qsort(void *, const size_t, const size_t, int(*)(const void *, const void *, void *), void *)
Reentrant implementation of quick sort.
#define rb_long2int
Just another name of rb_long2int_inline.
Definition long.h:62
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:375
#define ALLOCA_N(type, n)
Definition memory.h:295
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:363
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:170
#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:307
VALUE type(ANYARGS)
ANYARGS-ed function type.
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
#define RBIMPL_ATTR_NORETURN()
Wraps (or simulates) [[noreturn]]
Definition noreturn.h:38
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:50
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:280
#define RARRAY_AREF(a, i)
References an object in an array.
Definition rarray.h:421
static void RARRAY_ASET(VALUE ary, rb_len_t i, VALUE v)
Assigns an object in an array.
Definition rarray.h:385
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:51
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition rbasic.h:166
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition rdata.h:56
void(* RUBY_DATA_FUNC)(void *)
This is the type of callbacks registered to RData.
Definition rdata.h:69
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition rhash.h:57
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
Definition rregexp.h:93
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:76
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition rstring.h:438
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RTYPEDDATA_DATA(v)
Convenient getter macro.
Definition rtypeddata.h:106
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:773
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:557
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:604
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9271
static bool RB_SPECIAL_CONST_P(VALUE obj)
Checks if the given object is of enum ruby_special_consts.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
Definition proc.c:31
Internal header for Complex.
Definition complex.h:13
Internal header for Rational.
Definition rational.h:16
Definition iseq.h:360
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
Definition vm_core.h:289
Definition vm_core.h:292
Definition iseq.h:334
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:242
const char * wrap_struct_name
Name of structs of this kind.
Definition rtypeddata.h:249
Definition st.h:79
Definition vm_core.h:301
long rb_len_t
A signed integer type for lengths and indices of objects such as String and Array.
Definition value.h:142
unsigned long rb_ulen_t
An unsigned integer type that has the same width with rb_len_t.
Definition value.h:145
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
#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
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool rb_integer_type_p(VALUE obj)
Queries if the object is an instance of rb_cInteger.
Definition value_type.h:204
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
Bitmask of ruby_value_type.
Definition value_type.h:145