Ruby 4.1.0dev (2026-11-12 revision e6e232d5facd495b6a7f143cf6e9c7960392ca25)
compile.c (e6e232d5facd495b6a7f143cf6e9c7960392ca25)
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 /* The keyword rest local may have been reassigned to any
10391 * object, so it is never merged into in place. hash_merge_ptr
10392 * converts it with to_hash (nil being empty) and copies it into
10393 * a hash allocated at its final size. */
10394 if (local_body->param.flags.has_kwrest) {
10395 int idx = local_body->local_table_size - local_kwd->rest_start;
10396 RUBY_ASSERT(local_kwd->num > 0);
10397 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10398 ADD_GETLOCAL(args, node, idx, lvar_level);
10399 }
10400 for (i = 0; i < local_kwd->num; ++i) {
10401 ID id = local_kwd->table[i];
10402 int idx = local_size - get_local_var_idx(liseq, id);
10403 ADD_INSN1(args, node, putobject, ID2SYM(id));
10404 ADD_GETLOCAL(args, node, idx, lvar_level);
10405 }
10406 if (local_body->param.flags.has_kwrest) {
10407 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
10408 }
10409 else {
10410 ADD_INSN1(args, node, newhash, INT2FIX(i * 2));
10411 }
10412 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
10413 }
10414 else if (local_body->param.flags.has_kwrest) {
10415 int idx = local_body->local_table_size - local_kwd->rest_start;
10416 ADD_GETLOCAL(args, node, idx, lvar_level);
10417 argc++;
10418 flag |= VM_CALL_KW_SPLAT;
10419 }
10420 }
10421
10422 if (use_block && parent_block == NULL) {
10423 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10424 }
10425
10426 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
10427 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
10428 ADD_INSN(ret, node, putself);
10429 ADD_SEQ(ret, args);
10430
10431 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
10432
10433 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
10434 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
10435 }
10436 else {
10437 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
10438 }
10439
10440 if (popped) {
10441 ADD_INSN(ret, node, pop);
10442 }
10443 return COMPILE_OK;
10444}
10445
10446static int
10447compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10448{
10449 DECL_ANCHOR(args);
10450 VALUE argc;
10451 unsigned int flag = 0;
10452 struct rb_callinfo_kwarg *keywords = NULL;
10453
10454 INIT_ANCHOR(args);
10455
10456 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
10457 case ISEQ_TYPE_TOP:
10458 case ISEQ_TYPE_MAIN:
10459 case ISEQ_TYPE_CLASS:
10460 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
10461 return COMPILE_NG;
10462 default: /* valid */;
10463 }
10464
10465 if (RNODE_YIELD(node)->nd_head) {
10466 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
10467 CHECK(!NIL_P(argc));
10468 }
10469 else {
10470 argc = INT2FIX(0);
10471 }
10472
10473 ADD_SEQ(ret, args);
10474 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
10475 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10476
10477 if (popped) {
10478 ADD_INSN(ret, node, pop);
10479 }
10480
10481 int level = 0;
10482 const rb_iseq_t *tmp_iseq = iseq;
10483 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
10484 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
10485 }
10486 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
10487
10488 return COMPILE_OK;
10489}
10490
10491static int
10492compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10493{
10494 DECL_ANCHOR(recv);
10495 DECL_ANCHOR(val);
10496
10497 INIT_ANCHOR(recv);
10498 INIT_ANCHOR(val);
10499 switch ((int)type) {
10500 case NODE_MATCH:
10501 {
10502 VALUE re = rb_node_regx_string_val(node);
10504 ADD_INSN1(recv, node, putobject, re);
10505 ADD_INSN2(val, node, getspecial, INT2FIX(0),
10506 INT2FIX(0));
10507 }
10508 break;
10509 case NODE_MATCH2:
10510 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
10511 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
10512 break;
10513 case NODE_MATCH3:
10514 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
10515 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
10516 break;
10517 }
10518
10519 ADD_SEQ(ret, recv);
10520 ADD_SEQ(ret, val);
10521 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
10522
10523 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10524 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10525 }
10526
10527 if (popped) {
10528 ADD_INSN(ret, node, pop);
10529 }
10530 return COMPILE_OK;
10531}
10532
10533static int
10534compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10535{
10536 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10537 /* constant */
10538 VALUE segments;
10539 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10540 (segments = collect_const_segments(iseq, node))) {
10541 ISEQ_BODY(iseq)->ic_size++;
10542 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10543 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10544 }
10545 else {
10546 /* constant */
10547 DECL_ANCHOR(pref);
10548 DECL_ANCHOR(body);
10549
10550 INIT_ANCHOR(pref);
10551 INIT_ANCHOR(body);
10552 CHECK(compile_const_prefix(iseq, node, pref, body));
10553 if (LIST_INSN_SIZE_ZERO(pref)) {
10554 ADD_INSN(ret, node, putnil);
10555 ADD_SEQ(ret, body);
10556 }
10557 else {
10558 ADD_SEQ(ret, pref);
10559 ADD_SEQ(ret, body);
10560 }
10561 }
10562 }
10563 else {
10564 /* function call */
10565 ADD_CALL_RECEIVER(ret, node);
10566 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10567 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10568 }
10569 if (popped) {
10570 ADD_INSN(ret, node, pop);
10571 }
10572 return COMPILE_OK;
10573}
10574
10575static int
10576compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10577{
10578 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10579
10580 /* add cache insn */
10581 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10582 ISEQ_BODY(iseq)->ic_size++;
10583 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10585 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10586 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10587 }
10588 else {
10589 ADD_INSN1(ret, node, putobject, rb_cObject);
10590 ADD_INSN1(ret, node, putobject, Qtrue);
10591 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10592 }
10593
10594 if (popped) {
10595 ADD_INSN(ret, node, pop);
10596 }
10597 return COMPILE_OK;
10598}
10599
10600static int
10601compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10602{
10603 VALUE flag = INT2FIX(excl);
10604 const NODE *b = RNODE_DOT2(node)->nd_beg;
10605 const NODE *e = RNODE_DOT2(node)->nd_end;
10606
10607 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10608 if (!popped) {
10609 VALUE bv = optimized_range_item(b);
10610 VALUE ev = optimized_range_item(e);
10611 VALUE val = rb_range_new(bv, ev, excl);
10613 ADD_INSN1(ret, node, putobject, val);
10614 RB_OBJ_WRITTEN(iseq, Qundef, val);
10615 }
10616 }
10617 else {
10618 CHECK(COMPILE_(ret, "min", b, popped));
10619 CHECK(COMPILE_(ret, "max", e, popped));
10620 if (!popped) {
10621 ADD_INSN1(ret, node, newrange, flag);
10622 }
10623 }
10624 return COMPILE_OK;
10625}
10626
10627static int
10628compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10629{
10630 if (!popped) {
10631 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10632 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10633 }
10634 else {
10635 const rb_iseq_t *ip = iseq;
10636 int level = 0;
10637 while (ip) {
10638 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10639 break;
10640 }
10641 ip = ISEQ_BODY(ip)->parent_iseq;
10642 level++;
10643 }
10644 if (ip) {
10645 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10646 }
10647 else {
10648 ADD_INSN(ret, node, putnil);
10649 }
10650 }
10651 }
10652 return COMPILE_OK;
10653}
10654
10655static int
10656compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10657{
10658 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10659 LABEL *end_label = NEW_LABEL(nd_line(node));
10660 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10661
10662 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10663 /* required argument. do nothing */
10664 COMPILE_ERROR(ERROR_ARGS "unreachable");
10665 return COMPILE_NG;
10666 }
10667 else if (nd_type_p(default_value, NODE_SYM) ||
10668 nd_type_p(default_value, NODE_REGX) ||
10669 nd_type_p(default_value, NODE_LINE) ||
10670 nd_type_p(default_value, NODE_INTEGER) ||
10671 nd_type_p(default_value, NODE_FLOAT) ||
10672 nd_type_p(default_value, NODE_RATIONAL) ||
10673 nd_type_p(default_value, NODE_IMAGINARY) ||
10674 nd_type_p(default_value, NODE_NIL) ||
10675 nd_type_p(default_value, NODE_TRUE) ||
10676 nd_type_p(default_value, NODE_FALSE)) {
10677 COMPILE_ERROR(ERROR_ARGS "unreachable");
10678 return COMPILE_NG;
10679 }
10680 else {
10681 /* if keywordcheck(_kw_bits, nth_keyword)
10682 * kw = default_value
10683 * end
10684 */
10685 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10686 int keyword_idx = body->param.keyword->num;
10687
10688 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10689 ADD_INSNL(ret, node, branchif, end_label);
10690 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10691 ADD_LABEL(ret, end_label);
10692 }
10693 return COMPILE_OK;
10694}
10695
10696static int
10697compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10698{
10699 DECL_ANCHOR(recv);
10700 DECL_ANCHOR(args);
10701 unsigned int flag = 0;
10702 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10703 VALUE argc;
10704 LABEL *else_label = NULL;
10705 VALUE branches = Qfalse;
10706
10707 INIT_ANCHOR(recv);
10708 INIT_ANCHOR(args);
10709 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10710 CHECK(!NIL_P(argc));
10711
10712 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10713 CHECK(asgnflag != -1);
10714 flag |= (unsigned int)asgnflag;
10715
10716 debugp_param("argc", argc);
10717 debugp_param("nd_mid", ID2SYM(mid));
10718
10719 if (!rb_is_attrset_id(mid)) {
10720 /* safe nav attr */
10721 mid = rb_id_attrset(mid);
10722 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10723 }
10724 if (!popped) {
10725 ADD_INSN(ret, node, putnil);
10726 ADD_SEQ(ret, recv);
10727 ADD_SEQ(ret, args);
10728
10729 if (flag & VM_CALL_ARGS_SPLAT) {
10730 ADD_INSN(ret, node, dup);
10731 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10732 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10733 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10734 ADD_INSN (ret, node, pop);
10735 }
10736 else {
10737 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10738 }
10739 }
10740 else {
10741 ADD_SEQ(ret, recv);
10742 ADD_SEQ(ret, args);
10743 }
10744 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10745 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10746 ADD_INSN(ret, node, pop);
10747 return COMPILE_OK;
10748}
10749
10750static int
10751compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10752{
10753 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10754 ADD_SEQ(ret, sub);
10755
10756 if (copy) {
10757 /*
10758 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10759 * NEW_LIST(value, loc), loc);
10760 */
10761 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10762 }
10763 else {
10764 /*
10765 * NEW_CALL(fcore, rb_intern("make_shareable"),
10766 * NEW_LIST(value, loc), loc);
10767 */
10768 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10769 }
10770
10771 return COMPILE_OK;
10772}
10773
10774static VALUE
10775node_const_decl_val(const NODE *node)
10776{
10777 VALUE path;
10778 switch (nd_type(node)) {
10779 case NODE_CDECL:
10780 if (RNODE_CDECL(node)->nd_vid) {
10781 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10782 goto end;
10783 }
10784 else {
10785 node = RNODE_CDECL(node)->nd_else;
10786 }
10787 break;
10788 case NODE_COLON2:
10789 break;
10790 case NODE_COLON3:
10791 // ::Const
10792 path = rb_str_new_cstr("::");
10793 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10794 goto end;
10795 default:
10796 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10798 }
10799
10800 path = rb_ary_new();
10801 if (node) {
10802 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10803 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10804 }
10805 if (node && nd_type_p(node, NODE_CONST)) {
10806 // Const::Name
10807 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10808 }
10809 else if (node && nd_type_p(node, NODE_COLON3)) {
10810 // ::Const::Name
10811 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10812 rb_ary_push(path, rb_str_new(0, 0));
10813 }
10814 else {
10815 // expression::Name
10816 rb_ary_push(path, rb_str_new_cstr("..."));
10817 }
10818 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10819 }
10820 end:
10821 path = rb_fstring(path);
10822 return path;
10823}
10824
10825static VALUE
10826const_decl_path(NODE *dest)
10827{
10828 VALUE path = Qnil;
10829 if (!nd_type_p(dest, NODE_CALL)) {
10830 path = node_const_decl_val(dest);
10831 }
10832 return path;
10833}
10834
10835static int
10836compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10837{
10838 /*
10839 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10840 */
10841 VALUE path = const_decl_path(dest);
10842 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10843 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10844 ADD_INSN1(ret, value, putobject, path);
10845 RB_OBJ_WRITTEN(iseq, Qundef, path);
10846 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10847
10848 return COMPILE_OK;
10849}
10850
10851#ifndef SHAREABLE_BARE_EXPRESSION
10852#define SHAREABLE_BARE_EXPRESSION 1
10853#endif
10854
10855static int
10856compile_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)
10857{
10858# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10859 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10860 VALUE lit = Qnil;
10861 DECL_ANCHOR(anchor);
10862
10863 enum node_type type = node ? nd_type(node) : NODE_NIL;
10864 switch (type) {
10865 case NODE_TRUE:
10866 *value_p = Qtrue;
10867 goto compile;
10868 case NODE_FALSE:
10869 *value_p = Qfalse;
10870 goto compile;
10871 case NODE_NIL:
10872 *value_p = Qnil;
10873 goto compile;
10874 case NODE_SYM:
10875 *value_p = rb_node_sym_string_val(node);
10876 goto compile;
10877 case NODE_REGX:
10878 *value_p = rb_node_regx_string_val(node);
10879 goto compile;
10880 case NODE_LINE:
10881 *value_p = rb_node_line_lineno_val(node);
10882 goto compile;
10883 case NODE_INTEGER:
10884 *value_p = rb_node_integer_literal_val(node);
10885 goto compile;
10886 case NODE_FLOAT:
10887 *value_p = rb_node_float_literal_val(node);
10888 goto compile;
10889 case NODE_RATIONAL:
10890 *value_p = rb_node_rational_literal_val(node);
10891 goto compile;
10892 case NODE_IMAGINARY:
10893 *value_p = rb_node_imaginary_literal_val(node);
10894 goto compile;
10895 case NODE_ENCODING:
10896 *value_p = rb_node_encoding_val(node);
10897
10898 compile:
10899 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10900 *shareable_literal_p = 1;
10901 return COMPILE_OK;
10902
10903 case NODE_DSTR:
10904 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10905 if (shareable == rb_parser_shareable_literal) {
10906 /*
10907 * NEW_CALL(node, idUMinus, 0, loc);
10908 *
10909 * -"#{var}"
10910 */
10911 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10912 }
10913 *value_p = Qundef;
10914 *shareable_literal_p = 1;
10915 return COMPILE_OK;
10916
10917 case NODE_STR:{
10918 VALUE lit = rb_node_str_string_val(node);
10919 ADD_INSN1(ret, node, putobject, lit);
10920 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10921 *value_p = lit;
10922 *shareable_literal_p = 1;
10923
10924 return COMPILE_OK;
10925 }
10926
10927 case NODE_FILE:{
10928 VALUE lit = rb_node_file_path_val(node);
10929 ADD_INSN1(ret, node, putobject, lit);
10930 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10931 *value_p = lit;
10932 *shareable_literal_p = 1;
10933
10934 return COMPILE_OK;
10935 }
10936
10937 case NODE_ZLIST:{
10938 VALUE lit = rb_ary_new();
10939 OBJ_FREEZE(lit);
10940 ADD_INSN1(ret, node, putobject, lit);
10941 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10942 *value_p = lit;
10943 *shareable_literal_p = 1;
10944
10945 return COMPILE_OK;
10946 }
10947
10948 case NODE_LIST:{
10949 INIT_ANCHOR(anchor);
10950 lit = rb_ary_new();
10951 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10952 VALUE val;
10953 int shareable_literal_p2;
10954 NODE *elt = RNODE_LIST(n)->nd_head;
10955 if (elt) {
10956 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10957 if (shareable_literal_p2) {
10958 /* noop */
10959 }
10960 else if (RTEST(lit)) {
10961 rb_ary_clear(lit);
10962 lit = Qfalse;
10963 }
10964 }
10965 if (RTEST(lit)) {
10966 if (!UNDEF_P(val)) {
10967 rb_ary_push(lit, val);
10968 }
10969 else {
10970 rb_ary_clear(lit);
10971 lit = Qnil; /* make shareable at runtime */
10972 }
10973 }
10974 }
10975 break;
10976 }
10977 case NODE_HASH:{
10978 if (!RNODE_HASH(node)->nd_brace) {
10979 *value_p = Qundef;
10980 *shareable_literal_p = 0;
10981 return COMPILE_OK;
10982 }
10983 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10984 if (!RNODE_LIST(n)->nd_head) {
10985 // If the hash node have a keyword splat, fall back to the default case.
10986 goto compile_shareable;
10987 }
10988 }
10989
10990 INIT_ANCHOR(anchor);
10991 lit = rb_hash_new();
10992 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10993 VALUE key_val = 0;
10994 VALUE value_val = 0;
10995 int shareable_literal_p2;
10996 NODE *key = RNODE_LIST(n)->nd_head;
10997 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10998 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10999 if (shareable_literal_p2) {
11000 /* noop */
11001 }
11002 else if (RTEST(lit)) {
11003 rb_hash_clear(lit);
11004 lit = Qfalse;
11005 }
11006 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
11007 if (shareable_literal_p2) {
11008 /* noop */
11009 }
11010 else if (RTEST(lit)) {
11011 rb_hash_clear(lit);
11012 lit = Qfalse;
11013 }
11014 if (RTEST(lit)) {
11015 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
11016 rb_hash_aset(lit, key_val, value_val);
11017 }
11018 else {
11019 rb_hash_clear(lit);
11020 lit = Qnil; /* make shareable at runtime */
11021 }
11022 }
11023 }
11024 break;
11025 }
11026
11027 default:
11028
11029 compile_shareable:
11030 if (shareable == rb_parser_shareable_literal &&
11031 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
11032 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
11033 *value_p = Qundef;
11034 *shareable_literal_p = 1;
11035 return COMPILE_OK;
11036 }
11037 CHECK(COMPILE(ret, "shareable_literal_constant", node));
11038 *value_p = Qundef;
11039 *shareable_literal_p = 0;
11040 return COMPILE_OK;
11041 }
11042
11043 /* Array or Hash that does not have keyword splat */
11044 if (!lit) {
11045 if (nd_type(node) == NODE_LIST) {
11046 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
11047 }
11048 else if (nd_type(node) == NODE_HASH) {
11049 long len = RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
11052 ADD_INSN1(anchor, node, newhash, LONG2FIX(len));
11053 }
11054 *value_p = Qundef;
11055 *shareable_literal_p = 0;
11056 ADD_SEQ(ret, anchor);
11057 return COMPILE_OK;
11058 }
11059 if (NIL_P(lit)) {
11060 // if shareable_literal, all elements should have been ensured
11061 // as shareable
11062 if (nd_type(node) == NODE_LIST) {
11063 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
11064 }
11065 else if (nd_type(node) == NODE_HASH) {
11066 long len = RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
11069 ADD_INSN1(anchor, node, newhash, LONG2FIX(len));
11070 }
11071 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
11072 *value_p = Qundef;
11073 *shareable_literal_p = 1;
11074 }
11075 else {
11077 ADD_INSN1(ret, node, putobject, val);
11078 RB_OBJ_WRITTEN(iseq, Qundef, val);
11079 *value_p = val;
11080 *shareable_literal_p = 1;
11081 }
11082
11083 return COMPILE_OK;
11084}
11085
11086static int
11087compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
11088{
11089 int literal_p = 0;
11090 VALUE val;
11091 DECL_ANCHOR(anchor);
11092 INIT_ANCHOR(anchor);
11093
11094 switch (shareable) {
11095 case rb_parser_shareable_none:
11096 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
11097 return COMPILE_OK;
11098
11099 case rb_parser_shareable_literal:
11100 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
11101 ADD_SEQ(ret, anchor);
11102 return COMPILE_OK;
11103
11104 case rb_parser_shareable_copy:
11105 case rb_parser_shareable_everything:
11106 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
11107 if (!literal_p) {
11108 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
11109 }
11110 else {
11111 ADD_SEQ(ret, anchor);
11112 }
11113 return COMPILE_OK;
11114 default:
11115 rb_bug("unexpected rb_parser_shareability: %d", shareable);
11116 }
11117}
11118
11119static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
11127static int
11128iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
11129{
11130 if (node == 0) {
11131 if (!popped) {
11132 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
11133 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
11134 debugs("node: NODE_NIL(implicit)\n");
11135 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
11136 }
11137 return COMPILE_OK;
11138 }
11139 return iseq_compile_each0(iseq, ret, node, popped);
11140}
11141
11142static int
11143iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
11144{
11145 const int line = (int)nd_line(node);
11146 const enum node_type type = nd_type(node);
11147 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
11148
11149 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
11150 /* ignore */
11151 }
11152 else {
11153 if (nd_fl_newline(node)) {
11154 int event = RUBY_EVENT_LINE;
11155 ISEQ_COMPILE_DATA(iseq)->last_line = line;
11156 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
11157 event |= RUBY_EVENT_COVERAGE_LINE;
11158 }
11159 ADD_TRACE(ret, event);
11160 }
11161 }
11162
11163 debug_node_start(node);
11164#undef BEFORE_RETURN
11165#define BEFORE_RETURN debug_node_end()
11166
11167 switch (type) {
11168 case NODE_BLOCK:
11169 CHECK(compile_block(iseq, ret, node, popped));
11170 break;
11171 case NODE_IF:
11172 case NODE_UNLESS:
11173 CHECK(compile_if(iseq, ret, node, popped, type));
11174 break;
11175 case NODE_CASE:
11176 CHECK(compile_case(iseq, ret, node, popped));
11177 break;
11178 case NODE_CASE2:
11179 CHECK(compile_case2(iseq, ret, node, popped));
11180 break;
11181 case NODE_CASE3:
11182 CHECK(compile_case3(iseq, ret, node, popped));
11183 break;
11184 case NODE_WHILE:
11185 case NODE_UNTIL:
11186 CHECK(compile_loop(iseq, ret, node, popped, type));
11187 break;
11188 case NODE_FOR:
11189 case NODE_ITER:
11190 CHECK(compile_iter(iseq, ret, node, popped));
11191 break;
11192 case NODE_FOR_MASGN:
11193 CHECK(compile_for_masgn(iseq, ret, node, popped));
11194 break;
11195 case NODE_BREAK:
11196 CHECK(compile_break(iseq, ret, node, popped));
11197 break;
11198 case NODE_NEXT:
11199 CHECK(compile_next(iseq, ret, node, popped));
11200 break;
11201 case NODE_REDO:
11202 CHECK(compile_redo(iseq, ret, node, popped));
11203 break;
11204 case NODE_RETRY:
11205 CHECK(compile_retry(iseq, ret, node, popped));
11206 break;
11207 case NODE_BEGIN:{
11208 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
11209 break;
11210 }
11211 case NODE_RESCUE:
11212 CHECK(compile_rescue(iseq, ret, node, popped));
11213 break;
11214 case NODE_RESBODY:
11215 CHECK(compile_resbody(iseq, ret, node, popped));
11216 break;
11217 case NODE_ENSURE:
11218 CHECK(compile_ensure(iseq, ret, node, popped));
11219 break;
11220
11221 case NODE_AND:
11222 case NODE_OR:{
11223 LABEL *end_label = NEW_LABEL(line);
11224 const NODE *cond = node;
11225 /* Compile a chain of the same operator (`a && b && ...`) against one
11226 * shared end label, so every branch targets it directly. Compiling
11227 * nd_2nd recursively would instead give each operator its own label,
11228 * and the peephole optimizer would rewrite that chain in quadratic
11229 * time. */
11230 while (1) {
11231 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(cond)->nd_1st));
11232 if (!popped) {
11233 ADD_INSN(ret, cond, dup);
11234 }
11235 if (type == NODE_AND) {
11236 ADD_INSNL(ret, cond, branchunless, end_label);
11237 }
11238 else {
11239 ADD_INSNL(ret, cond, branchif, end_label);
11240 }
11241 if (!popped) {
11242 ADD_INSN(ret, cond, pop);
11243 }
11244 const NODE *rest = RNODE_OR(cond)->nd_2nd;
11245 if (nd_type_p(rest, type)) {
11246 cond = rest;
11247 continue;
11248 }
11249 CHECK(COMPILE_(ret, "nd_2nd", rest, popped));
11250 break;
11251 }
11252 ADD_LABEL(ret, end_label);
11253 break;
11254 }
11255
11256 case NODE_MASGN:{
11257 compile_massign(iseq, ret, node, popped);
11258 break;
11259 }
11260
11261 case NODE_LASGN:{
11262 ID id = RNODE_LASGN(node)->nd_vid;
11263 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
11264
11265 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
11266 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
11267
11268 if (!popped) {
11269 ADD_INSN(ret, node, dup);
11270 }
11271 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
11272 break;
11273 }
11274 case NODE_DASGN: {
11275 int idx, lv, ls;
11276 ID id = RNODE_DASGN(node)->nd_vid;
11277 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
11278 debugi("dassn id", rb_id2str(id) ? id : '*');
11279
11280 if (!popped) {
11281 ADD_INSN(ret, node, dup);
11282 }
11283
11284 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
11285
11286 if (idx < 0) {
11287 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
11288 rb_id2str(id));
11289 goto ng;
11290 }
11291 ADD_SETLOCAL(ret, node, ls - idx, lv);
11292 break;
11293 }
11294 case NODE_GASGN:{
11295 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
11296
11297 if (!popped) {
11298 ADD_INSN(ret, node, dup);
11299 }
11300 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
11301 break;
11302 }
11303 case NODE_IASGN:{
11304 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
11305 if (!popped) {
11306 ADD_INSN(ret, node, dup);
11307 }
11308 ADD_INSN2(ret, node, setinstancevariable,
11309 ID2SYM(RNODE_IASGN(node)->nd_vid),
11310 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
11311 break;
11312 }
11313 case NODE_CDECL:{
11314 if (RNODE_CDECL(node)->nd_vid) {
11315 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11316
11317 if (!popped) {
11318 ADD_INSN(ret, node, dup);
11319 }
11320
11321 ADD_INSN1(ret, node, putspecialobject,
11322 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
11323 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
11324 }
11325 else {
11326 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
11327 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11328 ADD_INSN(ret, node, swap);
11329
11330 if (!popped) {
11331 ADD_INSN1(ret, node, topn, INT2FIX(1));
11332 ADD_INSN(ret, node, swap);
11333 }
11334
11335 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
11336 }
11337 break;
11338 }
11339 case NODE_CVASGN:{
11340 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
11341 if (!popped) {
11342 ADD_INSN(ret, node, dup);
11343 }
11344 ADD_INSN2(ret, node, setclassvariable,
11345 ID2SYM(RNODE_CVASGN(node)->nd_vid),
11346 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
11347 break;
11348 }
11349 case NODE_OP_ASGN1:
11350 CHECK(compile_op_asgn1(iseq, ret, node, popped));
11351 break;
11352 case NODE_OP_ASGN2:
11353 CHECK(compile_op_asgn2(iseq, ret, node, popped));
11354 break;
11355 case NODE_OP_CDECL:
11356 CHECK(compile_op_cdecl(iseq, ret, node, popped));
11357 break;
11358 case NODE_OP_ASGN_AND:
11359 case NODE_OP_ASGN_OR:
11360 CHECK(compile_op_log(iseq, ret, node, popped, type));
11361 break;
11362 case NODE_CALL: /* obj.foo */
11363 case NODE_OPCALL: /* foo[] */
11364 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
11365 break;
11366 }
11367 case NODE_QCALL: /* obj&.foo */
11368 case NODE_FCALL: /* foo() */
11369 case NODE_VCALL: /* foo (variable or call) */
11370 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
11371 goto ng;
11372 }
11373 break;
11374 case NODE_SUPER:
11375 case NODE_ZSUPER:
11376 CHECK(compile_super(iseq, ret, node, popped, type));
11377 break;
11378 case NODE_LIST:{
11379 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
11380 break;
11381 }
11382 case NODE_ZLIST:{
11383 if (!popped) {
11384 ADD_INSN1(ret, node, newarray, INT2FIX(0));
11385 }
11386 break;
11387 }
11388 case NODE_HASH:
11389 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
11390 break;
11391 case NODE_RETURN:
11392 CHECK(compile_return(iseq, ret, node, popped));
11393 break;
11394 case NODE_YIELD:
11395 CHECK(compile_yield(iseq, ret, node, popped));
11396 break;
11397 case NODE_LVAR:{
11398 if (!popped) {
11399 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
11400 }
11401 break;
11402 }
11403 case NODE_DVAR:{
11404 int lv, idx, ls;
11405 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
11406 if (!popped) {
11407 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
11408 if (idx < 0) {
11409 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
11410 rb_id2str(RNODE_DVAR(node)->nd_vid));
11411 goto ng;
11412 }
11413 ADD_GETLOCAL(ret, node, ls - idx, lv);
11414 }
11415 break;
11416 }
11417 case NODE_GVAR:{
11418 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
11419 if (popped) {
11420 ADD_INSN(ret, node, pop);
11421 }
11422 break;
11423 }
11424 case NODE_IVAR:{
11425 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
11426 if (!popped) {
11427 ADD_INSN2(ret, node, getinstancevariable,
11428 ID2SYM(RNODE_IVAR(node)->nd_vid),
11429 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
11430 }
11431 break;
11432 }
11433 case NODE_CONST:{
11434 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
11435
11436 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
11437 body->ic_size++;
11438 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
11440 ADD_INSN1(ret, node, opt_getconstant_path, segments);
11441 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11442 }
11443 else {
11444 ADD_INSN(ret, node, putnil);
11445 ADD_INSN1(ret, node, putobject, Qtrue);
11446 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
11447 }
11448
11449 if (popped) {
11450 ADD_INSN(ret, node, pop);
11451 }
11452 break;
11453 }
11454 case NODE_CVAR:{
11455 if (!popped) {
11456 ADD_INSN2(ret, node, getclassvariable,
11457 ID2SYM(RNODE_CVAR(node)->nd_vid),
11458 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
11459 }
11460 break;
11461 }
11462 case NODE_NTH_REF:{
11463 if (!popped) {
11464 if (!RNODE_NTH_REF(node)->nd_nth) {
11465 ADD_INSN(ret, node, putnil);
11466 break;
11467 }
11468 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11469 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
11470 }
11471 break;
11472 }
11473 case NODE_BACK_REF:{
11474 if (!popped) {
11475 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11476 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
11477 }
11478 break;
11479 }
11480 case NODE_MATCH:
11481 case NODE_MATCH2:
11482 case NODE_MATCH3:
11483 CHECK(compile_match(iseq, ret, node, popped, type));
11484 break;
11485 case NODE_SYM:{
11486 if (!popped) {
11487 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
11488 }
11489 break;
11490 }
11491 case NODE_LINE:{
11492 if (!popped) {
11493 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
11494 }
11495 break;
11496 }
11497 case NODE_ENCODING:{
11498 if (!popped) {
11499 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11500 }
11501 break;
11502 }
11503 case NODE_INTEGER:{
11504 VALUE lit = rb_node_integer_literal_val(node);
11505 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11506 debugp_param("integer", lit);
11507 if (!popped) {
11508 ADD_INSN1(ret, node, putobject, lit);
11509 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11510 }
11511 break;
11512 }
11513 case NODE_FLOAT:{
11514 VALUE lit = rb_node_float_literal_val(node);
11515 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11516 debugp_param("float", lit);
11517 if (!popped) {
11518 ADD_INSN1(ret, node, putobject, lit);
11519 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11520 }
11521 break;
11522 }
11523 case NODE_RATIONAL:{
11524 VALUE lit = rb_node_rational_literal_val(node);
11526 debugp_param("rational", lit);
11527 if (!popped) {
11528 ADD_INSN1(ret, node, putobject, lit);
11529 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11530 }
11531 break;
11532 }
11533 case NODE_IMAGINARY:{
11534 VALUE lit = rb_node_imaginary_literal_val(node);
11536 debugp_param("imaginary", lit);
11537 if (!popped) {
11538 ADD_INSN1(ret, node, putobject, lit);
11539 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11540 }
11541 break;
11542 }
11543 case NODE_FILE:
11544 case NODE_STR:{
11545 debugp_param("nd_lit", get_string_value(node));
11546 if (!popped) {
11547 VALUE lit = get_string_value(node);
11548 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11549 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11550 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11551 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11553 }
11554 switch (option->frozen_string_literal) {
11555 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11556 ADD_INSN1(ret, node, dupchilledstring, lit);
11557 break;
11558 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11559 ADD_INSN1(ret, node, dupstring, lit);
11560 break;
11561 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11562 ADD_INSN1(ret, node, putobject, lit);
11563 break;
11564 default:
11565 rb_bug("invalid frozen_string_literal");
11566 }
11567 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11568 }
11569 break;
11570 }
11571 case NODE_DSTR:{
11572 compile_dstr(iseq, ret, node);
11573
11574 if (popped) {
11575 ADD_INSN(ret, node, pop);
11576 }
11577 break;
11578 }
11579 case NODE_XSTR:{
11580 ADD_CALL_RECEIVER(ret, node);
11581 VALUE str = rb_node_str_string_val(node);
11582 ADD_INSN1(ret, node, putobject, str);
11583 RB_OBJ_WRITTEN(iseq, Qundef, str);
11584 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11585
11586 if (popped) {
11587 ADD_INSN(ret, node, pop);
11588 }
11589 break;
11590 }
11591 case NODE_DXSTR:{
11592 ADD_CALL_RECEIVER(ret, node);
11593 compile_dstr(iseq, ret, node);
11594 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11595
11596 if (popped) {
11597 ADD_INSN(ret, node, pop);
11598 }
11599 break;
11600 }
11601 case NODE_EVSTR:
11602 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11603 break;
11604 case NODE_REGX:{
11605 if (!popped) {
11606 VALUE lit = rb_node_regx_string_val(node);
11608 ADD_INSN1(ret, node, putobject, lit);
11609 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11610 }
11611 break;
11612 }
11613 case NODE_DREGX:
11614 compile_dregx(iseq, ret, node, popped);
11615 break;
11616 case NODE_ONCE:{
11617 int ic_index = body->ise_size++;
11618 const rb_iseq_t *block_iseq;
11619 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11620
11621 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11622 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11623
11624 if (popped) {
11625 ADD_INSN(ret, node, pop);
11626 }
11627 break;
11628 }
11629 case NODE_ARGSCAT:{
11630 if (popped) {
11631 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11632 ADD_INSN1(ret, node, splatarray, Qfalse);
11633 ADD_INSN(ret, node, pop);
11634 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11635 ADD_INSN1(ret, node, splatarray, Qfalse);
11636 ADD_INSN(ret, node, pop);
11637 }
11638 else {
11639 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11640 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11641 if (nd_type_p(body_node, NODE_LIST)) {
11642 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11643 }
11644 else {
11645 CHECK(COMPILE(ret, "argscat body", body_node));
11646 ADD_INSN(ret, node, concattoarray);
11647 }
11648 }
11649 break;
11650 }
11651 case NODE_ARGSPUSH:{
11652 if (popped) {
11653 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11654 ADD_INSN1(ret, node, splatarray, Qfalse);
11655 ADD_INSN(ret, node, pop);
11656 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11657 }
11658 else {
11659 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11660 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11661 if (keyword_node_p(body_node)) {
11662 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11663 ADD_INSN(ret, node, pushtoarraykwsplat);
11664 }
11665 else if (static_literal_node_p(body_node, iseq, false)) {
11666 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11667 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11668 }
11669 else {
11670 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11671 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11672 }
11673 }
11674 break;
11675 }
11676 case NODE_SPLAT:{
11677 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11678 ADD_INSN1(ret, node, splatarray, Qtrue);
11679
11680 if (popped) {
11681 ADD_INSN(ret, node, pop);
11682 }
11683 break;
11684 }
11685 case NODE_DEFN:{
11686 ID mid = RNODE_DEFN(node)->nd_mid;
11687 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11688 rb_id2str(mid),
11689 ISEQ_TYPE_METHOD, line);
11690
11691 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11692 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11693 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11694
11695 if (!popped) {
11696 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11697 }
11698
11699 break;
11700 }
11701 case NODE_DEFS:{
11702 ID mid = RNODE_DEFS(node)->nd_mid;
11703 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11704 rb_id2str(mid),
11705 ISEQ_TYPE_METHOD, line);
11706
11707 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11708 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11709 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11710 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11711
11712 if (!popped) {
11713 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11714 }
11715 break;
11716 }
11717 case NODE_ALIAS:{
11718 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11719 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11720 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11721 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11722 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11723
11724 if (popped) {
11725 ADD_INSN(ret, node, pop);
11726 }
11727 break;
11728 }
11729 case NODE_VALIAS:{
11730 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11731 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11732 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11733 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11734
11735 if (popped) {
11736 ADD_INSN(ret, node, pop);
11737 }
11738 break;
11739 }
11740 case NODE_UNDEF:{
11741 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11742
11743 for (long i = 0; i < ary->len; i++) {
11744 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11745 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11746 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11747 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11748
11749 if (i < ary->len - 1) {
11750 ADD_INSN(ret, node, pop);
11751 }
11752 }
11753
11754 if (popped) {
11755 ADD_INSN(ret, node, pop);
11756 }
11757 break;
11758 }
11759 case NODE_CLASS:{
11760 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11761 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11762 ISEQ_TYPE_CLASS, line);
11763 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11764 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11765 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11766
11767 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11768 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11769 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11770
11771 if (popped) {
11772 ADD_INSN(ret, node, pop);
11773 }
11774 break;
11775 }
11776 case NODE_MODULE:{
11777 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11778 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11779 ISEQ_TYPE_CLASS, line);
11780 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11781 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11782
11783 ADD_INSN (ret, node, putnil); /* dummy */
11784 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11785 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11786
11787 if (popped) {
11788 ADD_INSN(ret, node, pop);
11789 }
11790 break;
11791 }
11792 case NODE_SCLASS:{
11793 ID singletonclass;
11794 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11795 ISEQ_TYPE_CLASS, line);
11796
11797 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11798 ADD_INSN (ret, node, putnil);
11799 CONST_ID(singletonclass, "singletonclass");
11800
11801 /* `class << self` in a class body and `class << Foo` (constant
11802 receiver) are stable. All other forms are potentially dynamic. */
11803 int sclass_flags = VM_DEFINECLASS_TYPE_SINGLETON_CLASS;
11804 const NODE *recv = RNODE_SCLASS(node)->nd_recv;
11805 if (!(nd_type_p(recv, NODE_SELF) &&
11806 ISEQ_BODY(iseq)->type == ISEQ_TYPE_CLASS) &&
11807 !cpath_const_p(recv)) {
11808 sclass_flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF;
11809 }
11810
11811 ADD_INSN3(ret, node, defineclass,
11812 ID2SYM(singletonclass), singleton_class,
11813 INT2FIX(sclass_flags));
11814 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11815
11816 if (popped) {
11817 ADD_INSN(ret, node, pop);
11818 }
11819 break;
11820 }
11821 case NODE_COLON2:
11822 CHECK(compile_colon2(iseq, ret, node, popped));
11823 break;
11824 case NODE_COLON3:
11825 CHECK(compile_colon3(iseq, ret, node, popped));
11826 break;
11827 case NODE_DOT2:
11828 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11829 break;
11830 case NODE_DOT3:
11831 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11832 break;
11833 case NODE_FLIP2:
11834 case NODE_FLIP3:{
11835 LABEL *lend = NEW_LABEL(line);
11836 LABEL *ltrue = NEW_LABEL(line);
11837 LABEL *lfalse = NEW_LABEL(line);
11838 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11839 ltrue, lfalse));
11840 ADD_LABEL(ret, ltrue);
11841 ADD_INSN1(ret, node, putobject, Qtrue);
11842 ADD_INSNL(ret, node, jump, lend);
11843 ADD_LABEL(ret, lfalse);
11844 ADD_INSN1(ret, node, putobject, Qfalse);
11845 ADD_LABEL(ret, lend);
11846 break;
11847 }
11848 case NODE_SELF:{
11849 if (!popped) {
11850 ADD_INSN(ret, node, putself);
11851 }
11852 break;
11853 }
11854 case NODE_NIL:{
11855 if (!popped) {
11856 ADD_INSN(ret, node, putnil);
11857 }
11858 break;
11859 }
11860 case NODE_TRUE:{
11861 if (!popped) {
11862 ADD_INSN1(ret, node, putobject, Qtrue);
11863 }
11864 break;
11865 }
11866 case NODE_FALSE:{
11867 if (!popped) {
11868 ADD_INSN1(ret, node, putobject, Qfalse);
11869 }
11870 break;
11871 }
11872 case NODE_ERRINFO:
11873 CHECK(compile_errinfo(iseq, ret, node, popped));
11874 break;
11875 case NODE_DEFINED:
11876 if (!popped) {
11877 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11878 }
11879 break;
11880 case NODE_POSTEXE:{
11881 /* compiled to:
11882 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11883 */
11884 int is_index = body->ise_size++;
11886 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11887 const rb_iseq_t *once_iseq =
11888 NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc, rb_fstring(make_name_for_block(iseq)), ISEQ_TYPE_BLOCK, line);
11889
11890 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11891 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11892
11893 if (popped) {
11894 ADD_INSN(ret, node, pop);
11895 }
11896 break;
11897 }
11898 case NODE_KW_ARG:
11899 CHECK(compile_kw_arg(iseq, ret, node, popped));
11900 break;
11901 case NODE_DSYM:{
11902 compile_dstr(iseq, ret, node);
11903 if (!popped) {
11904 ADD_INSN(ret, node, intern);
11905 }
11906 else {
11907 ADD_INSN(ret, node, pop);
11908 }
11909 break;
11910 }
11911 case NODE_ATTRASGN:
11912 CHECK(compile_attrasgn(iseq, ret, node, popped));
11913 break;
11914 case NODE_LAMBDA:{
11915 /* compile same as lambda{...} */
11916 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11917 VALUE argc = INT2FIX(0);
11918
11919 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11920 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11921 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11922
11923 if (popped) {
11924 ADD_INSN(ret, node, pop);
11925 }
11926 break;
11927 }
11928 default:
11929 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11930 ng:
11931 debug_node_end();
11932 return COMPILE_NG;
11933 }
11934
11935 debug_node_end();
11936 return COMPILE_OK;
11937}
11938
11939/***************************/
11940/* instruction information */
11941/***************************/
11942
11943static int
11944insn_data_length(INSN *iobj)
11945{
11946 return insn_len(iobj->insn_id);
11947}
11948
11949static int
11950calc_sp_depth(int depth, INSN *insn)
11951{
11952 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11953}
11954
11955static VALUE
11956opobj_inspect(VALUE obj)
11957{
11958 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11959 switch (BUILTIN_TYPE(obj)) {
11960 case T_STRING:
11961 obj = rb_str_resurrect(obj);
11962 break;
11963 case T_ARRAY:
11964 obj = rb_ary_resurrect(obj);
11965 break;
11966 default:
11967 break;
11968 }
11969 }
11970 return rb_inspect(obj);
11971}
11972
11973
11974
11975static VALUE
11976insn_data_to_s_detail(INSN *iobj)
11977{
11978 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11979
11980 if (iobj->operands) {
11981 const char *types = insn_op_types(iobj->insn_id);
11982 int j;
11983
11984 for (j = 0; types[j]; j++) {
11985 char type = types[j];
11986
11987 switch (type) {
11988 case TS_OFFSET: /* label(destination position) */
11989 {
11990 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11991 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11992 break;
11993 }
11994 break;
11995 case TS_ISEQ: /* iseq */
11996 {
11997 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11998 VALUE val = Qnil;
11999 if (0 && iseq) { /* TODO: invalidate now */
12000 val = (VALUE)iseq;
12001 }
12002 rb_str_concat(str, opobj_inspect(val));
12003 }
12004 break;
12005 case TS_LINDEX:
12006 case TS_NUM: /* ulong */
12007 case TS_VALUE: /* VALUE */
12008 {
12009 VALUE v = OPERAND_AT(iobj, j);
12010 if (!CLASS_OF(v))
12011 rb_str_cat2(str, "<hidden>");
12012 else {
12013 rb_str_concat(str, opobj_inspect(v));
12014 }
12015 break;
12016 }
12017 case TS_ID: /* ID */
12018 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
12019 break;
12020 case TS_IC: /* inline cache */
12021 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
12022 break;
12023 case TS_IVC: /* inline ivar cache */
12024 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
12025 break;
12026 case TS_ICVARC: /* inline cvar cache */
12027 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
12028 break;
12029 case TS_ISE: /* inline storage entry */
12030 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
12031 break;
12032 case TS_CALLDATA: /* we store these as call infos at compile time */
12033 {
12034 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
12035 rb_str_cat2(str, "<calldata:");
12036 if (vm_ci_mid(ci)) rb_str_append(str, rb_id2str(vm_ci_mid(ci)));
12037 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
12038 break;
12039 }
12040 case TS_CDHASH: /* case/when condition cache */
12041 rb_str_cat2(str, "<ch>");
12042 break;
12043 case TS_FUNCPTR:
12044 {
12045 void *func = (void *)OPERAND_AT(iobj, j);
12046#ifdef HAVE_DLADDR
12047 Dl_info info;
12048 if (dladdr(func, &info) && info.dli_sname) {
12049 rb_str_cat2(str, info.dli_sname);
12050 break;
12051 }
12052#endif
12053 rb_str_catf(str, "<%p>", func);
12054 }
12055 break;
12056 case TS_BUILTIN:
12057 rb_str_cat2(str, "<TS_BUILTIN>");
12058 break;
12059 default:{
12060 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
12061 }
12062 }
12063 if (types[j + 1]) {
12064 rb_str_cat2(str, ", ");
12065 }
12066 }
12067 }
12068 return str;
12069}
12070
12071static void
12072dump_disasm_list(const LINK_ELEMENT *link)
12073{
12074 dump_disasm_list_with_cursor(link, NULL, NULL);
12075}
12076
12077static void
12078dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
12079{
12080 int pos = 0;
12081 INSN *iobj;
12082 LABEL *lobj;
12083 VALUE str;
12084
12085 printf("-- raw disasm--------\n");
12086
12087 while (link) {
12088 if (curr) printf(curr == link ? "*" : " ");
12089 switch (link->type) {
12090 case ISEQ_ELEMENT_INSN:
12091 {
12092 iobj = (INSN *)link;
12093 str = insn_data_to_s_detail(iobj);
12094 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
12095 pos += insn_data_length(iobj);
12096 break;
12097 }
12098 case ISEQ_ELEMENT_LABEL:
12099 {
12100 lobj = (LABEL *)link;
12101 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
12102 dest == lobj ? " <---" : "");
12103 break;
12104 }
12105 case ISEQ_ELEMENT_TRACE:
12106 {
12107 TRACE *trace = (TRACE *)link;
12108 printf(" trace: %0x\n", trace->event);
12109 break;
12110 }
12111 case ISEQ_ELEMENT_ADJUST:
12112 {
12113 ADJUST *adjust = (ADJUST *)link;
12114 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
12115 break;
12116 }
12117 default:
12118 /* ignore */
12119 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
12120 }
12121 link = link->next;
12122 }
12123 printf("---------------------\n");
12124 fflush(stdout);
12125}
12126
12127int
12128rb_insn_len(VALUE insn)
12129{
12130 return insn_len(insn);
12131}
12132
12133const char *
12134rb_insns_name(int i)
12135{
12136 return insn_name(i);
12137}
12138
12139VALUE
12140rb_insns_name_array(void)
12141{
12142 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
12143 int i;
12144 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
12145 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
12146 }
12147 return rb_ary_freeze(ary);
12148}
12149
12150static LABEL *
12151register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
12152{
12153 LABEL *label = 0;
12154 st_data_t tmp;
12155 obj = rb_to_symbol_type(obj);
12156
12157 if (st_lookup(labels_table, obj, &tmp) == 0) {
12158 label = NEW_LABEL(0);
12159 st_insert(labels_table, obj, (st_data_t)label);
12160 }
12161 else {
12162 label = (LABEL *)tmp;
12163 }
12164 LABEL_REF(label);
12165 return label;
12166}
12167
12168static VALUE
12169get_exception_sym2type(VALUE sym)
12170{
12171 static VALUE symRescue, symEnsure, symRetry;
12172 static VALUE symBreak, symRedo, symNext;
12173
12174 if (symRescue == 0) {
12175 symRescue = ID2SYM(rb_intern_const("rescue"));
12176 symEnsure = ID2SYM(rb_intern_const("ensure"));
12177 symRetry = ID2SYM(rb_intern_const("retry"));
12178 symBreak = ID2SYM(rb_intern_const("break"));
12179 symRedo = ID2SYM(rb_intern_const("redo"));
12180 symNext = ID2SYM(rb_intern_const("next"));
12181 }
12182
12183 if (sym == symRescue) return CATCH_TYPE_RESCUE;
12184 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
12185 if (sym == symRetry) return CATCH_TYPE_RETRY;
12186 if (sym == symBreak) return CATCH_TYPE_BREAK;
12187 if (sym == symRedo) return CATCH_TYPE_REDO;
12188 if (sym == symNext) return CATCH_TYPE_NEXT;
12189 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
12190 return 0;
12191}
12192
12193static int
12194iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
12195 VALUE exception)
12196{
12197 int i;
12198
12199 for (i=0; i<RARRAY_LEN(exception); i++) {
12200 const rb_iseq_t *eiseq;
12201 VALUE v, type;
12202 LABEL *lstart, *lend, *lcont;
12203 unsigned int sp;
12204
12205 v = rb_to_array_type(RARRAY_AREF(exception, i));
12206 if (RARRAY_LEN(v) != 6) {
12207 rb_raise(rb_eSyntaxError, "wrong exception entry");
12208 }
12209 type = get_exception_sym2type(RARRAY_AREF(v, 0));
12210 if (NIL_P(RARRAY_AREF(v, 1))) {
12211 eiseq = NULL;
12212 }
12213 else {
12214 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
12215 }
12216
12217 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
12218 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
12219 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
12220 sp = NUM2UINT(RARRAY_AREF(v, 5));
12221
12222 /* TODO: Dirty Hack! Fix me */
12223 if (type == CATCH_TYPE_RESCUE ||
12224 type == CATCH_TYPE_BREAK ||
12225 type == CATCH_TYPE_NEXT) {
12226 ++sp;
12227 }
12228
12229 lcont->sp = sp;
12230
12231 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
12232
12233 RB_GC_GUARD(v);
12234 }
12235 return COMPILE_OK;
12236}
12237
12238static struct st_table *
12239insn_make_insn_table(void)
12240{
12241 struct st_table *table;
12242 int i;
12243 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
12244
12245 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
12246 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
12247 }
12248
12249 return table;
12250}
12251
12252static const rb_iseq_t *
12253iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
12254{
12255 VALUE iseqw;
12256 const rb_iseq_t *loaded_iseq;
12257
12258 if (RB_TYPE_P(op, T_ARRAY)) {
12259 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
12260 }
12261 else if (CLASS_OF(op) == rb_cISeq) {
12262 iseqw = op;
12263 }
12264 else {
12265 rb_raise(rb_eSyntaxError, "ISEQ is required");
12266 }
12267
12268 loaded_iseq = rb_iseqw_to_iseq(iseqw);
12269 return loaded_iseq;
12270}
12271
12272static VALUE
12273iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
12274{
12275 ID mid = 0;
12276 int orig_argc = 0;
12277 unsigned int flag = 0;
12278 struct rb_callinfo_kwarg *kw_arg = 0;
12279
12280 if (!NIL_P(op)) {
12281 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
12282 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
12283 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
12284 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
12285
12286 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
12287 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
12288 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
12289
12290 if (!NIL_P(vkw_arg)) {
12291 int i;
12292 int len = RARRAY_LENINT(vkw_arg);
12293 size_t n = rb_callinfo_kwarg_bytes(len);
12294
12295 kw_arg = xmalloc(n);
12296 kw_arg->references = 0;
12297 kw_arg->keyword_len = len;
12298 for (i = 0; i < len; i++) {
12299 VALUE kw = RARRAY_AREF(vkw_arg, i);
12300 SYM2ID(kw); /* make immortal */
12301 kw_arg->keywords[i] = kw;
12302 }
12303 }
12304 }
12305
12306 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
12307 RB_OBJ_WRITTEN(iseq, Qundef, ci);
12308 return (VALUE)ci;
12309}
12310
12311static rb_event_flag_t
12312event_name_to_flag(VALUE sym)
12313{
12314#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
12315 CHECK_EVENT(RUBY_EVENT_LINE);
12316 CHECK_EVENT(RUBY_EVENT_CLASS);
12317 CHECK_EVENT(RUBY_EVENT_END);
12318 CHECK_EVENT(RUBY_EVENT_CALL);
12319 CHECK_EVENT(RUBY_EVENT_RETURN);
12320 CHECK_EVENT(RUBY_EVENT_B_CALL);
12321 CHECK_EVENT(RUBY_EVENT_B_RETURN);
12322 CHECK_EVENT(RUBY_EVENT_RESCUE);
12323#undef CHECK_EVENT
12324 return RUBY_EVENT_NONE;
12325}
12326
12327static int
12328iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
12329 VALUE body, VALUE node_ids, VALUE labels_wrapper)
12330{
12331 /* TODO: body should be frozen */
12332 rb_len_t i, len = RARRAY_LEN(body);
12333 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
12334 int j;
12335 int line_no = 0, node_id = -1, insn_idx = 0;
12336 int ret = COMPILE_OK;
12337
12338 /*
12339 * index -> LABEL *label
12340 */
12341 static struct st_table *insn_table;
12342
12343 if (insn_table == 0) {
12344 insn_table = insn_make_insn_table();
12345 }
12346
12347 for (i=0; i<len; i++) {
12348 VALUE obj = RARRAY_AREF(body, i);
12349
12350 if (SYMBOL_P(obj)) {
12351 rb_event_flag_t event;
12352 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
12353 ADD_TRACE(anchor, event);
12354 }
12355 else {
12356 LABEL *label = register_label(iseq, labels_table, obj);
12357 ADD_LABEL(anchor, label);
12358 }
12359 }
12360 else if (FIXNUM_P(obj)) {
12361 line_no = NUM2INT(obj);
12362 }
12363 else if (RB_TYPE_P(obj, T_ARRAY)) {
12364 VALUE *argv = 0;
12365 int argc = RARRAY_LENINT(obj) - 1;
12366 st_data_t insn_id;
12367 VALUE insn;
12368
12369 if (node_ids) {
12370 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
12371 }
12372
12373 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
12374 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
12375 /* TODO: exception */
12376 COMPILE_ERROR(iseq, line_no,
12377 "unknown instruction: %+"PRIsVALUE, insn);
12378 ret = COMPILE_NG;
12379 break;
12380 }
12381
12382 if (argc != insn_len((VALUE)insn_id)-1) {
12383 COMPILE_ERROR(iseq, line_no,
12384 "operand size mismatch");
12385 ret = COMPILE_NG;
12386 break;
12387 }
12388
12389 if (argc > 0) {
12390 argv = compile_data_calloc2_type(iseq, VALUE, argc);
12391
12392 // add element before operand setup to make GC root
12393 ADD_ELEM(anchor,
12394 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12395 (enum ruby_vminsn_type)insn_id, argc, argv));
12396
12397 for (j=0; j<argc; j++) {
12398 VALUE op = rb_ary_entry(obj, j+1);
12399 switch (insn_op_type((VALUE)insn_id, j)) {
12400 case TS_OFFSET: {
12401 LABEL *label = register_label(iseq, labels_table, op);
12402 argv[j] = (VALUE)label;
12403 break;
12404 }
12405 case TS_LINDEX:
12406 case TS_NUM:
12407 (void)NUM2INT(op);
12408 argv[j] = op;
12409 break;
12410 case TS_VALUE:
12411 argv[j] = op;
12412 RB_OBJ_WRITTEN(iseq, Qundef, op);
12413 break;
12414 case TS_ISEQ:
12415 {
12416 if (op != Qnil) {
12417 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
12418 argv[j] = v;
12419 RB_OBJ_WRITTEN(iseq, Qundef, v);
12420 }
12421 else {
12422 argv[j] = 0;
12423 }
12424 }
12425 break;
12426 case TS_ISE:
12427 argv[j] = op;
12428 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
12429 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
12430 }
12431 break;
12432 case TS_IC:
12433 {
12434 VALUE segments = rb_ary_new();
12435 op = rb_to_array_type(op);
12436
12437 for (int i = 0; i < RARRAY_LEN(op); i++) {
12438 VALUE sym = RARRAY_AREF(op, i);
12439 sym = rb_to_symbol_type(sym);
12440 rb_ary_push(segments, sym);
12441 }
12442
12443 RB_GC_GUARD(op);
12444 argv[j] = segments;
12445 RB_OBJ_WRITTEN(iseq, Qundef, segments);
12446 ISEQ_BODY(iseq)->ic_size++;
12447 }
12448 break;
12449 case TS_IVC: /* inline ivar cache */
12450 argv[j] = op;
12451 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
12452 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
12453 }
12454 break;
12455 case TS_ICVARC: /* inline cvar cache */
12456 argv[j] = op;
12457 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
12458 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
12459 }
12460 break;
12461 case TS_CALLDATA:
12462 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
12463 break;
12464 case TS_ID:
12465 argv[j] = rb_to_symbol_type(op);
12466 break;
12467 case TS_CDHASH:
12468 {
12469 int i;
12470 VALUE map = cdhash_new(RARRAY_LEN(op) / 2);
12471
12472 op = rb_to_array_type(op);
12473 for (i=0; i<RARRAY_LEN(op); i+=2) {
12474 VALUE key = RARRAY_AREF(op, i);
12475 VALUE sym = RARRAY_AREF(op, i+1);
12476 LABEL *label =
12477 register_label(iseq, labels_table, sym);
12478 cdhash_aset(map, key, (VALUE)label);
12479 }
12480 RB_GC_GUARD(op);
12481 RB_OBJ_SET_SHAREABLE(map); // allow mutation while compiling
12482 argv[j] = map;
12483 RB_OBJ_WRITTEN(iseq, Qundef, map);
12484 }
12485 break;
12486 case TS_FUNCPTR:
12487 {
12488#if SIZEOF_VALUE <= SIZEOF_LONG
12489 long funcptr = NUM2LONG(op);
12490#else
12491 LONG_LONG funcptr = NUM2LL(op);
12492#endif
12493 argv[j] = (VALUE)funcptr;
12494 }
12495 break;
12496 default:
12497 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
12498 }
12499 }
12500 }
12501 else {
12502 ADD_ELEM(anchor,
12503 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12504 (enum ruby_vminsn_type)insn_id, argc, NULL));
12505 }
12506 }
12507 else {
12508 rb_raise(rb_eTypeError, "unexpected object for instruction");
12509 }
12510 }
12511 RTYPEDDATA_DATA(labels_wrapper) = 0;
12512 RB_GC_GUARD(labels_wrapper);
12513 validate_labels(iseq, labels_table);
12514 if (!ret) return ret;
12515 return iseq_setup(iseq, anchor);
12516}
12517
12518#define CHECK_ARRAY(v) rb_to_array_type(v)
12519#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12520
12521static int
12522int_param(int *dst, VALUE param, VALUE sym)
12523{
12524 VALUE val = rb_hash_aref(param, sym);
12525 if (FIXNUM_P(val)) {
12526 *dst = FIX2INT(val);
12527 return TRUE;
12528 }
12529 else if (!NIL_P(val)) {
12530 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
12531 sym, val);
12532 }
12533 return FALSE;
12534}
12535
12536static const struct rb_iseq_param_keyword *
12537iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12538{
12539 int i, j;
12540 int len = RARRAY_LENINT(keywords);
12541 int default_len;
12542 VALUE key, sym, default_val;
12543 VALUE *dvs;
12544 ID *ids;
12545 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12546
12547 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12548
12549 keyword->num = len;
12550#define SYM(s) ID2SYM(rb_intern_const(#s))
12551 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12552 i = keyword->bits_start - keyword->num;
12553 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12554#undef SYM
12555
12556 /* required args */
12557 for (i = 0; i < len; i++) {
12558 VALUE val = RARRAY_AREF(keywords, i);
12559
12560 if (!SYMBOL_P(val)) {
12561 goto default_values;
12562 }
12563 ids[i] = SYM2ID(val);
12564 keyword->required_num++;
12565 }
12566
12567 default_values: /* note: we intentionally preserve `i' from previous loop */
12568 default_len = len - i;
12569 if (default_len == 0) {
12570 keyword->table = ids;
12571 return keyword;
12572 }
12573 else if (default_len < 0) {
12575 }
12576
12577 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12578
12579 for (j = 0; i < len; i++, j++) {
12580 key = RARRAY_AREF(keywords, i);
12581 CHECK_ARRAY(key);
12582
12583 switch (RARRAY_LEN(key)) {
12584 case 1:
12585 sym = RARRAY_AREF(key, 0);
12586 default_val = Qundef;
12587 break;
12588 case 2:
12589 sym = RARRAY_AREF(key, 0);
12590 default_val = RARRAY_AREF(key, 1);
12591 break;
12592 default:
12593 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12594 }
12595 ids[i] = SYM2ID(sym);
12596 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12597 }
12598
12599 keyword->table = ids;
12600 keyword->default_values = dvs;
12601
12602 return keyword;
12603}
12604
12605static void
12606iseq_insn_each_object_mark_and_move(VALUE * obj, VALUE _)
12607{
12608 rb_gc_mark_and_move(obj);
12609}
12610
12611void
12612rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
12613{
12614 INSN *iobj = 0;
12615 size_t size = sizeof(INSN);
12616 size_t align = ALIGNMENT_SIZE_OF(INSN);
12617 unsigned int pos = 0;
12618
12619 while (storage) {
12620 size_t padding = calc_padding((void *)&storage->buff[pos], align);
12621 size_t offset = pos + size + padding;
12622 if (offset > storage->size || offset > storage->pos) {
12623 pos = 0;
12624 storage = storage->next;
12625 }
12626 else {
12627 pos += (int)padding;
12628
12629 iobj = (INSN *)&storage->buff[pos];
12630
12631 if (iobj->operands) {
12632 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (VALUE)0);
12633 }
12634 pos += (int)size;
12635 }
12636 }
12637}
12638
12639static const rb_data_type_t labels_wrapper_type = {
12640 .wrap_struct_name = "compiler/labels_wrapper",
12641 .function = {
12642 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12643 .dfree = (RUBY_DATA_FUNC)st_free_table,
12644 },
12645 .flags = RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED,
12646};
12647
12648void
12649rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12650 VALUE exception, VALUE body)
12651{
12652#define SYM(s) ID2SYM(rb_intern_const(#s))
12653 int i, len;
12654 unsigned int arg_size, local_size, stack_max;
12655 ID *tbl;
12656 struct st_table *labels_table = st_init_numtable();
12657 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12658 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12659 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12660 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12661 DECL_ANCHOR(anchor);
12662 INIT_ANCHOR(anchor);
12663
12664 len = RARRAY_LENINT(locals);
12665 ISEQ_BODY(iseq)->local_table_size = len;
12666 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12667
12668 for (i = 0; i < len; i++) {
12669 VALUE lv = RARRAY_AREF(locals, i);
12670
12671 if (sym_arg_rest == lv) {
12672 tbl[i] = 0;
12673 }
12674 else {
12675 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12676 }
12677 }
12678
12679#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12680 if (INT_PARAM(lead_num)) {
12681 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12682 }
12683 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12684 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12685 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12686 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12687#undef INT_PARAM
12688 {
12689#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12690 int x;
12691 INT_PARAM(arg_size);
12692 INT_PARAM(local_size);
12693 INT_PARAM(stack_max);
12694#undef INT_PARAM
12695 }
12696
12697 VALUE source_hash = rb_hash_aref(misc, ID2SYM(rb_intern("source_hash")));
12698 if (!NIL_P(source_hash)) {
12699 ISEQ_BODY(iseq)->source_hash = NUM2ULL(source_hash);
12700 }
12701
12702 VALUE node_ids = Qfalse;
12703#ifdef USE_ISEQ_NODE_ID
12704 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12705 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12706 rb_raise(rb_eTypeError, "node_ids is not an array");
12707 }
12708#endif
12709
12710 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12711 len = RARRAY_LENINT(arg_opt_labels);
12712 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12713
12714 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12715 VALUE *opt_table = ALLOC_N(VALUE, len);
12716
12717 for (i = 0; i < len; i++) {
12718 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12719 LABEL *label = register_label(iseq, labels_table, ent);
12720 opt_table[i] = (VALUE)label;
12721 }
12722
12723 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12724 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12725 }
12726 }
12727 else if (!NIL_P(arg_opt_labels)) {
12728 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12729 arg_opt_labels);
12730 }
12731
12732 if (RB_TYPE_P(keywords, T_ARRAY)) {
12733 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12734 }
12735 else if (!NIL_P(keywords)) {
12736 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12737 keywords);
12738 }
12739
12740 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12741 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12742 }
12743
12744 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12745 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12746 }
12747
12748 if (int_param(&i, params, SYM(kwrest))) {
12749 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12750 if (keyword == NULL) {
12751 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12752 }
12753 keyword->rest_start = i;
12754 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12755 }
12756#undef SYM
12757 iseq_calc_param_size(iseq);
12758
12759 /* exception */
12760 iseq_build_from_ary_exception(iseq, labels_table, exception);
12761
12762 /* body */
12763 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12764
12765 ISEQ_BODY(iseq)->param.size = arg_size;
12766 ISEQ_BODY(iseq)->local_table_size = local_size;
12767 ISEQ_BODY(iseq)->stack_max = stack_max;
12768}
12769
12770/* for parser */
12771
12772int
12773rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12774{
12775 if (iseq) {
12776 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12777 while (body->type == ISEQ_TYPE_BLOCK ||
12778 body->type == ISEQ_TYPE_RESCUE ||
12779 body->type == ISEQ_TYPE_ENSURE ||
12780 body->type == ISEQ_TYPE_EVAL ||
12781 body->type == ISEQ_TYPE_MAIN
12782 ) {
12783 unsigned int i;
12784
12785 for (i = 0; i < body->local_table_size; i++) {
12786 if (body->local_table[i] == id) {
12787 return 1;
12788 }
12789 }
12790 iseq = body->parent_iseq;
12791 body = ISEQ_BODY(iseq);
12792 }
12793 }
12794 return 0;
12795}
12796
12797int
12798rb_local_defined(ID id, const rb_iseq_t *iseq)
12799{
12800 if (iseq) {
12801 unsigned int i;
12802 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12803
12804 for (i=0; i<body->local_table_size; i++) {
12805 if (body->local_table[i] == id) {
12806 return 1;
12807 }
12808 }
12809 }
12810 return 0;
12811}
12812
12813/* ISeq binary format */
12814
12815#ifndef IBF_ISEQ_DEBUG
12816#define IBF_ISEQ_DEBUG 0
12817#endif
12818
12819#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12820#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12821#endif
12822
12823typedef uint32_t ibf_offset_t;
12824#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12825
12826#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12827#ifdef RUBY_DEVEL
12828#define IBF_DEVEL_VERSION 12
12829#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12830#else
12831#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12832#endif
12833
12834static const char IBF_ENDIAN_MARK =
12835#ifdef WORDS_BIGENDIAN
12836 'b'
12837#else
12838 'l'
12839#endif
12840 ;
12841
12843 char magic[4]; /* YARB */
12844 uint32_t major_version;
12845 uint32_t minor_version;
12846 uint32_t size;
12847 uint32_t extra_size;
12848
12849 uint32_t iseq_list_size;
12850 uint32_t global_object_list_size;
12851 ibf_offset_t iseq_list_offset;
12852 ibf_offset_t global_object_list_offset;
12853 uint8_t endian;
12854 uint8_t wordsize; /* assume no 2048-bit CPU */
12855};
12856
12858 VALUE str;
12859 st_table *obj_table; /* obj -> obj number */
12860};
12861
12862struct ibf_dump {
12863 st_table *iseq_table; /* iseq -> iseq number */
12864 struct ibf_dump_buffer global_buffer;
12865 struct ibf_dump_buffer *current_buffer;
12866};
12867
12869 const char *buff;
12870 ibf_offset_t size;
12871
12872 VALUE obj_list; /* [obj0, ...] */
12873 unsigned int obj_list_size;
12874 ibf_offset_t obj_list_offset;
12875};
12876
12877struct ibf_load {
12878 const struct ibf_header *header;
12879 VALUE iseq_list; /* [iseq0, ...] */
12880 struct ibf_load_buffer global_buffer;
12881 VALUE loader_obj;
12882 rb_iseq_t *iseq;
12883 VALUE str;
12884 struct ibf_load_buffer *current_buffer;
12885};
12886
12888 long size;
12889 VALUE buffer[1];
12890};
12891
12892static void
12893pinned_list_mark(void *ptr)
12894{
12895 long i;
12896 struct pinned_list *list = (struct pinned_list *)ptr;
12897 for (i = 0; i < list->size; i++) {
12898 if (list->buffer[i]) {
12899 rb_gc_mark(list->buffer[i]);
12900 }
12901 }
12902}
12903
12904static const rb_data_type_t pinned_list_type = {
12905 "pinned_list",
12906 {
12907 pinned_list_mark,
12909 NULL, // No external memory to report,
12910 },
12911 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_EMBEDDABLE
12912};
12913
12914static VALUE
12915pinned_list_fetch(VALUE list, long offset)
12916{
12917 struct pinned_list * ptr;
12918
12919 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12920
12921 if (offset < 0 || offset >= ptr->size) {
12922 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12923 }
12924
12925 return ptr->buffer[offset];
12926}
12927
12928static void
12929pinned_list_store(VALUE list, long offset, VALUE object)
12930{
12931 struct pinned_list * ptr;
12932
12933 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12934
12935 if (offset < 0 || offset >= ptr->size) {
12936 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12937 }
12938
12939 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12940}
12941
12942static VALUE
12943pinned_list_new(long size)
12944{
12945 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12946 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12947 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12948 ptr->size = size;
12949 return obj_list;
12950}
12951
12952static ibf_offset_t
12953ibf_dump_pos(struct ibf_dump *dump)
12954{
12955 rb_len_t pos = RSTRING_LEN(dump->current_buffer->str);
12956#if SIZEOF_RB_LEN_T > SIZEOF_INT
12957 if (pos >= UINT_MAX) {
12958 rb_raise(rb_eRuntimeError, "dump size exceeds");
12959 }
12960#endif
12961 return (unsigned int)pos;
12962}
12963
12964static void
12965ibf_dump_align(struct ibf_dump *dump, size_t align)
12966{
12967 ibf_offset_t pos = ibf_dump_pos(dump);
12968 if (pos % align) {
12969 static const char padding[sizeof(VALUE)];
12970 size_t size = align - ((size_t)pos % align);
12971#if SIZEOF_RB_LEN_T > SIZEOF_INT
12972 if (pos + size >= UINT_MAX) {
12973 rb_raise(rb_eRuntimeError, "dump size exceeds");
12974 }
12975#endif
12976 for (; size > sizeof(padding); size -= sizeof(padding)) {
12977 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12978 }
12979 rb_str_cat(dump->current_buffer->str, padding, size);
12980 }
12981}
12982
12983static ibf_offset_t
12984ibf_dump_write(struct ibf_dump *dump, const void *buff, size_t size)
12985{
12986 ibf_offset_t pos = ibf_dump_pos(dump);
12987#if SIZEOF_RB_LEN_T > SIZEOF_INT
12988 /* ensure the resulting dump does not exceed UINT_MAX */
12989 if (size >= UINT_MAX || pos + size >= UINT_MAX) {
12990 rb_raise(rb_eRuntimeError, "dump size exceeds");
12991 }
12992#endif
12993 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12994 return pos;
12995}
12996
12997static ibf_offset_t
12998ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12999{
13000 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
13001}
13002
13003static void
13004ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, rb_len_t offset)
13005{
13006 VALUE str = dump->current_buffer->str;
13007 char *ptr = RSTRING_PTR(str);
13008 if ((rb_ulen_t)(size + offset) > (rb_ulen_t)RSTRING_LEN(str))
13009 rb_bug("ibf_dump_overwrite: overflow");
13010 memcpy(ptr + offset, buff, size);
13011}
13012
13013static const void *
13014ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
13015{
13016 ibf_offset_t beg = *offset;
13017 *offset += size;
13018 return load->current_buffer->buff + beg;
13019}
13020
13021static void *
13022ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
13023{
13024 void *buff = ruby_xmalloc2(x, y);
13025 size_t size = x * y;
13026 memcpy(buff, load->current_buffer->buff + offset, size);
13027 return buff;
13028}
13029
13030#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
13031
13032#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
13033#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
13034#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
13035#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
13036#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
13037
13038static int
13039ibf_table_lookup(struct st_table *table, st_data_t key)
13040{
13041 st_data_t val;
13042
13043 if (st_lookup(table, key, &val)) {
13044 return (int)val;
13045 }
13046 else {
13047 return -1;
13048 }
13049}
13050
13051static int
13052ibf_table_find_or_insert(struct st_table *table, st_data_t key)
13053{
13054 int index = ibf_table_lookup(table, key);
13055
13056 if (index < 0) { /* not found */
13057 index = (int)table->num_entries;
13058 st_insert(table, key, (st_data_t)index);
13059 }
13060
13061 return index;
13062}
13063
13064/* dump/load generic */
13065
13066static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
13067
13068static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
13069static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
13070
13071static st_table *
13072ibf_dump_object_table_new(void)
13073{
13074 st_table *obj_table = st_init_numtable(); /* need free */
13075 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
13076
13077 return obj_table;
13078}
13079
13080static VALUE
13081ibf_dump_object(struct ibf_dump *dump, VALUE obj)
13082{
13083 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
13084}
13085
13086static VALUE
13087ibf_dump_id(struct ibf_dump *dump, ID id)
13088{
13089 if (id == 0 || rb_id2name(id) == NULL) {
13090 return 0;
13091 }
13092 return ibf_dump_object(dump, rb_id2sym(id));
13093}
13094
13095static ID
13096ibf_load_id(const struct ibf_load *load, const ID id_index)
13097{
13098 if (id_index == 0) {
13099 return 0;
13100 }
13101 VALUE sym = ibf_load_object(load, id_index);
13102 if (rb_integer_type_p(sym)) {
13103 /* Load hidden local variables as indexes */
13104 return NUM2ULONG(sym);
13105 }
13106 return rb_sym2id(sym);
13107}
13108
13109/* dump/load: code */
13110
13111static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
13112
13113static int
13114ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
13115{
13116 if (iseq == NULL) {
13117 return -1;
13118 }
13119 else {
13120 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
13121 }
13122}
13123
13124static unsigned char
13125ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
13126{
13127 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
13128 return (unsigned char)load->current_buffer->buff[(*offset)++];
13129}
13130
13131/*
13132 * Small uint serialization
13133 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
13134 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
13135 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
13136 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
13137 * ...
13138 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
13139 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
13140 */
13141static void
13142ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
13143{
13144 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
13145 ibf_dump_write(dump, &x, sizeof(VALUE));
13146 return;
13147 }
13148
13149 enum { max_byte_length = sizeof(VALUE) + 1 };
13150
13151 unsigned char bytes[max_byte_length];
13152 ibf_offset_t n;
13153
13154 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
13155 bytes[max_byte_length - 1 - n] = (unsigned char)x;
13156 }
13157
13158 x <<= 1;
13159 x |= 1;
13160 x <<= n;
13161 bytes[max_byte_length - 1 - n] = (unsigned char)x;
13162 n++;
13163
13164 ibf_dump_write(dump, bytes + max_byte_length - n, n);
13165}
13166
13167static VALUE
13168ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
13169{
13170 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
13171 union { char s[sizeof(VALUE)]; VALUE v; } x;
13172
13173 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
13174 *offset += sizeof(VALUE);
13175
13176 return x.v;
13177 }
13178
13179 enum { max_byte_length = sizeof(VALUE) + 1 };
13180
13181 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
13182 const unsigned char c = buffer[*offset];
13183
13184 ibf_offset_t n =
13185 c & 1 ? 1 :
13186 c == 0 ? 9 : ntz_int32(c) + 1;
13187 VALUE x = (VALUE)c >> n;
13188
13189 if (*offset + n > load->current_buffer->size) {
13190 rb_raise(rb_eRuntimeError, "invalid byte sequence");
13191 }
13192
13193 ibf_offset_t i;
13194 for (i = 1; i < n; i++) {
13195 x <<= 8;
13196 x |= (VALUE)buffer[*offset + i];
13197 }
13198
13199 *offset += n;
13200 return x;
13201}
13202
13203static void
13204ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
13205{
13206 // short: index
13207 // short: name.length
13208 // bytes: name
13209 // // omit argc (only verify with name)
13210 ibf_dump_write_small_value(dump, (VALUE)bf->index);
13211
13212 size_t len = strlen(bf->name);
13213 ibf_dump_write_small_value(dump, (VALUE)len);
13214 ibf_dump_write(dump, bf->name, len);
13215}
13216
13217static const struct rb_builtin_function *
13218ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
13219{
13220 int i = (int)ibf_load_small_value(load, offset);
13221 int len = (int)ibf_load_small_value(load, offset);
13222 const char *name = (char *)ibf_load_ptr(load, offset, len);
13223
13224 if (0) {
13225 fprintf(stderr, "%.*s!!\n", len, name);
13226 }
13227
13228 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
13229 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
13230 if (strncmp(table[i].name, name, len) != 0) {
13231 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %.*s but %s)",
13232 i, len, name, table[i].name);
13233 }
13234 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
13235
13236 return &table[i];
13237}
13238
13239static ibf_offset_t
13240ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
13241{
13242 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13243 const int iseq_size = body->iseq_size;
13244 int code_index;
13245 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
13246
13247 ibf_offset_t offset = ibf_dump_pos(dump);
13248
13249 for (code_index=0; code_index<iseq_size;) {
13250 const VALUE insn = orig_code[code_index++];
13251 const char *types = insn_op_types(insn);
13252 int op_index;
13253
13254 /* opcode */
13255 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
13256 ibf_dump_write_small_value(dump, insn);
13257
13258 /* operands */
13259 for (op_index=0; types[op_index]; op_index++, code_index++) {
13260 VALUE op = orig_code[code_index];
13261 VALUE wv;
13262
13263 switch (types[op_index]) {
13264 case TS_CDHASH:
13265 case TS_VALUE:
13266 wv = ibf_dump_object(dump, op);
13267 break;
13268 case TS_ISEQ:
13269 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
13270 break;
13271 case TS_IC:
13272 {
13273 IC ic = (IC)op;
13274 VALUE arr = idlist_to_array(ic->segments);
13275 wv = ibf_dump_object(dump, arr);
13276 }
13277 break;
13278 case TS_ISE:
13279 case TS_IVC:
13280 case TS_ICVARC:
13281 {
13283 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
13284 }
13285 break;
13286 case TS_CALLDATA:
13287 {
13288 goto skip_wv;
13289 }
13290 case TS_ID:
13291 wv = ibf_dump_id(dump, (ID)op);
13292 break;
13293 case TS_FUNCPTR:
13294 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13295 goto skip_wv;
13296 case TS_BUILTIN:
13297 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
13298 goto skip_wv;
13299 default:
13300 wv = op;
13301 break;
13302 }
13303 ibf_dump_write_small_value(dump, wv);
13304 skip_wv:;
13305 }
13306 RUBY_ASSERT(insn_len(insn) == op_index+1);
13307 }
13308
13309 return offset;
13310}
13311
13312static VALUE *
13313ibf_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)
13314{
13315 VALUE iseqv = (VALUE)iseq;
13316 unsigned int code_index;
13317 ibf_offset_t reading_pos = bytecode_offset;
13318 VALUE *code = ZALLOC_N(VALUE, iseq_size);
13319
13320 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
13321 struct rb_call_data *cd_entries = load_body->call_data;
13322 int ic_index = 0;
13323
13324 load_body->iseq_encoded = code;
13325 load_body->iseq_size = iseq_size;
13326
13327 iseq_bits_t * mark_offset_bits;
13328 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
13329 load_body->mark_bits.single = 0;
13330 mark_offset_bits = &load_body->mark_bits.single;
13331 }
13332 else {
13333 load_body->mark_bits.list = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
13334 mark_offset_bits = load_body->mark_bits.list;
13335 }
13336 bool needs_bitmap = false;
13337
13338 for (code_index=0; code_index<iseq_size;) {
13339 /* opcode */
13340 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
13341 const char *types = insn_op_types(insn);
13342 int op_index;
13343
13344 code_index++;
13345
13346 /* operands */
13347 for (op_index=0; types[op_index]; op_index++, code_index++) {
13348 const char operand_type = types[op_index];
13349 switch (operand_type) {
13350 case TS_VALUE:
13351 {
13352 VALUE op = ibf_load_small_value(load, &reading_pos);
13353 VALUE v = ibf_load_object(load, op);
13354 code[code_index] = v;
13355 if (!SPECIAL_CONST_P(v)) {
13356 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13357 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13358 needs_bitmap = true;
13359 }
13360 break;
13361 }
13362 case TS_CDHASH:
13363 {
13364 VALUE op = ibf_load_small_value(load, &reading_pos);
13365 VALUE v = ibf_load_object(load, op);
13366
13367 // Overwrite the existing hash in the object list. This
13368 // is to keep the object alive during load time.
13369 // [Bug #17984] [ruby-core:104259]
13370 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
13371
13372 code[code_index] = v;
13373 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13374 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13375 needs_bitmap = true;
13376 break;
13377 }
13378 case TS_ISEQ:
13379 {
13380 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
13381 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
13382 code[code_index] = v;
13383 if (!SPECIAL_CONST_P(v)) {
13384 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13385 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13386 needs_bitmap = true;
13387 }
13388 break;
13389 }
13390 case TS_IC:
13391 {
13392 VALUE op = ibf_load_small_value(load, &reading_pos);
13393 VALUE arr = ibf_load_object(load, op);
13394
13395 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
13396 ic->segments = array_to_idlist(arr);
13397
13398 code[code_index] = (VALUE)ic;
13399 }
13400 break;
13401 case TS_ISE:
13402 case TS_ICVARC:
13403 case TS_IVC:
13404 {
13405 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
13406
13407 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
13408 code[code_index] = (VALUE)ic;
13409
13410 if (operand_type == TS_IVC) {
13411 IVC cache = (IVC)ic;
13412
13413 if (insn == BIN(setinstancevariable)) {
13414 ID iv_name = (ID)code[code_index - 1];
13415 cache->iv_set_name = iv_name;
13416 cache->value = IVAR_CACHE_INIT;
13417 }
13418 else {
13419 cache->iv_set_name = 0;
13420 cache->value = rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET);
13421 }
13422 }
13423
13424 }
13425 break;
13426 case TS_CALLDATA:
13427 {
13428 code[code_index] = (VALUE)cd_entries++;
13429 }
13430 break;
13431 case TS_ID:
13432 {
13433 VALUE op = ibf_load_small_value(load, &reading_pos);
13434 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
13435 }
13436 break;
13437 case TS_FUNCPTR:
13438 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13439 break;
13440 case TS_BUILTIN:
13441 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
13442 break;
13443 default:
13444 code[code_index] = ibf_load_small_value(load, &reading_pos);
13445 continue;
13446 }
13447 }
13448 if (insn_len(insn) != op_index+1) {
13449 rb_raise(rb_eRuntimeError, "operand size mismatch");
13450 }
13451 }
13452
13453 if (!needs_bitmap) {
13454 SIZED_FREE_N(load_body->mark_bits.list, ISEQ_MBITS_BUFLEN(iseq_size));
13455 load_body->mark_bits.list = NULL;
13456 }
13457
13458 RUBY_ASSERT(code_index == iseq_size);
13459 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
13460 return code;
13461}
13462
13463static ibf_offset_t
13464ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13465{
13466 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
13467
13468 if (opt_num > 0) {
13469 IBF_W_ALIGN(VALUE);
13470 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
13471 }
13472 else {
13473 return ibf_dump_pos(dump);
13474 }
13475}
13476
13477static VALUE *
13478ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
13479{
13480 if (opt_num > 0) {
13481 VALUE *table = ALLOC_N(VALUE, opt_num+1);
13482 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
13483 return table;
13484 }
13485 else {
13486 return NULL;
13487 }
13488}
13489
13490static ibf_offset_t
13491ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
13492{
13493 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
13494
13495 if (kw) {
13496 struct rb_iseq_param_keyword dump_kw = *kw;
13497 int dv_num = kw->num - kw->required_num;
13498 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
13499 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
13500 int i;
13501
13502 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
13503 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
13504
13505 dump_kw.table = IBF_W(ids, ID, kw->num);
13506 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
13507 IBF_W_ALIGN(struct rb_iseq_param_keyword);
13508 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
13509 }
13510 else {
13511 return 0;
13512 }
13513}
13514
13515static const struct rb_iseq_param_keyword *
13516ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13517{
13518 if (param_keyword_offset) {
13519 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
13520 int dv_num = kw->num - kw->required_num;
13521 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
13522
13523 int i;
13524 for (i=0; i<dv_num; i++) {
13525 dvs[i] = ibf_load_object(load, dvs[i]);
13526 }
13527
13528 // Will be set once the local table is loaded.
13529 kw->table = NULL;
13530
13531 kw->default_values = dvs;
13532 return kw;
13533 }
13534 else {
13535 return NULL;
13536 }
13537}
13538
13539static ibf_offset_t
13540ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13541{
13542 ibf_offset_t offset = ibf_dump_pos(dump);
13543 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13544 const struct iseq_insn_info_entry *entries = body->insns_info.body;
13545
13546#ifdef USE_ISEQ_NODE_ID
13547 ibf_dump_write_small_value(dump, body->insns_info.node_ids_size);
13548#endif
13549 unsigned int i;
13550 for (i = 0; i < body->insns_info.size; i++) {
13551 ibf_dump_write_small_value(dump, entries[i].line_no);
13552 ibf_dump_write_small_value(dump, entries[i].events);
13553 }
13554#ifdef USE_ISEQ_NODE_ID
13555 if (body->insns_info.node_ids_size > 0) {
13556 ibf_dump_write(dump, body->insns_info.node_ids, body->insns_info.node_ids_size);
13557 }
13558#endif
13559
13560 return offset;
13561}
13562
13563static void
13564ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size,
13565 struct rb_iseq_constant_body *load_body)
13566{
13567 ibf_offset_t reading_pos = body_offset;
13568 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13569
13570#ifdef USE_ISEQ_NODE_ID
13571 const unsigned int node_ids_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13572#endif
13573 unsigned int i;
13574 for (i = 0; i < size; i++) {
13575 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13576 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13577 }
13578#ifdef USE_ISEQ_NODE_ID
13579 if (node_ids_size > 0) {
13580 if (node_ids_size > load->current_buffer->size - reading_pos) {
13581 rb_raise(rb_eRuntimeError, "invalid byte sequence");
13582 }
13583 uint8_t *node_ids = ALLOC_N(uint8_t, node_ids_size);
13584 memcpy(node_ids, load->current_buffer->buff + reading_pos, node_ids_size);
13585 load_body->insns_info.node_ids = node_ids;
13586 load_body->insns_info.node_ids_size = node_ids_size;
13587 }
13588#endif
13589 load_body->insns_info.body = entries;
13590}
13591
13592static ibf_offset_t
13593ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13594{
13595 ibf_offset_t offset = ibf_dump_pos(dump);
13596
13597 unsigned int last = 0;
13598 unsigned int i;
13599 for (i = 0; i < size; i++) {
13600 ibf_dump_write_small_value(dump, positions[i] - last);
13601 last = positions[i];
13602 }
13603
13604 return offset;
13605}
13606
13607static unsigned int *
13608ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13609{
13610 ibf_offset_t reading_pos = positions_offset;
13611 unsigned int *positions = ALLOC_N(unsigned int, size);
13612
13613 unsigned int last = 0;
13614 unsigned int i;
13615 for (i = 0; i < size; i++) {
13616 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13617 last = positions[i];
13618 }
13619
13620 return positions;
13621}
13622
13623static ibf_offset_t
13624ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13625{
13626 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13627 const int size = body->local_table_size;
13628 ID *table = ALLOCA_N(ID, size);
13629 int i;
13630
13631 for (i=0; i<size; i++) {
13632 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13633 if (v == 0) {
13634 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13635 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13636 }
13637 table[i] = v;
13638 }
13639
13640 IBF_W_ALIGN(ID);
13641 return ibf_dump_write(dump, table, sizeof(ID) * size);
13642}
13643
13644static const ID *
13645ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13646{
13647 if (size > 0) {
13648 ID *table = IBF_R(local_table_offset, ID, size);
13649 int i;
13650
13651 for (i=0; i<size; i++) {
13652 table[i] = ibf_load_id(load, table[i]);
13653 }
13654
13655 if (size == 1 && table[0] == idERROR_INFO) {
13656 ruby_xfree_sized(table, sizeof(ID) * size);
13657 return rb_iseq_shared_exc_local_tbl;
13658 }
13659 else {
13660 return table;
13661 }
13662 }
13663 else {
13664 return NULL;
13665 }
13666}
13667
13668static ibf_offset_t
13669ibf_dump_lvar_states(struct ibf_dump *dump, const rb_iseq_t *iseq)
13670{
13671 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13672 const int size = ISEQ_LVAR_STATES_BUFLEN(body->local_table_size);
13673 IBF_W_ALIGN(uint8_t);
13674 if (iseq_has_lvar_states_p(body)) {
13675 return ibf_dump_write(dump, iseq_lvar_states(body), sizeof(uint8_t) * size);
13676 }
13677 else {
13678 return ibf_dump_write(dump, NULL, 0);
13679 }
13680}
13681
13682static void
13683ibf_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)
13684{
13685 if (local_table == rb_iseq_shared_exc_local_tbl ||
13686 size <= 0) {
13687 load_body->lvar_states.list = NULL;
13688 }
13689 else if (ISEQ_LVAR_STATES_EMBED_P((unsigned int)size)) {
13690 ibf_offset_t pos = lvar_states_offset;
13691 const int len = sizeof(uint8_t) * ISEQ_LVAR_STATES_BUFLEN(size);
13692 memcpy(load_body->lvar_states.single, ibf_load_ptr(load, &pos, len), len);
13693 }
13694 else {
13695 load_body->lvar_states.list = IBF_R(lvar_states_offset, uint8_t, ISEQ_LVAR_STATES_BUFLEN(size));
13696 }
13697}
13698
13699static ibf_offset_t
13700ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13701{
13702 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13703
13704 if (table) {
13705 int *iseq_indices = ALLOCA_N(int, table->size);
13706 unsigned int i;
13707
13708 for (i=0; i<table->size; i++) {
13709 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13710 }
13711
13712 const ibf_offset_t offset = ibf_dump_pos(dump);
13713
13714 for (i=0; i<table->size; i++) {
13715 ibf_dump_write_small_value(dump, iseq_indices[i]);
13716 ibf_dump_write_small_value(dump, table->entries[i].type);
13717 ibf_dump_write_small_value(dump, table->entries[i].start);
13718 ibf_dump_write_small_value(dump, table->entries[i].end);
13719 ibf_dump_write_small_value(dump, table->entries[i].cont);
13720 ibf_dump_write_small_value(dump, table->entries[i].sp);
13721 }
13722 return offset;
13723 }
13724 else {
13725 return ibf_dump_pos(dump);
13726 }
13727}
13728
13729static void
13730ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size, const rb_iseq_t *parent_iseq)
13731{
13732 if (size) {
13733 struct iseq_catch_table *table = ruby_xcalloc(1, iseq_catch_table_bytes(size));
13734 table->size = size;
13735 ISEQ_BODY(parent_iseq)->catch_table = table;
13736
13737 ibf_offset_t reading_pos = catch_table_offset;
13738
13739 unsigned int i;
13740 for (i=0; i<table->size; i++) {
13741 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13742 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13743 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13744 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13745 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13746 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13747
13748 rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13749 RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
13750 }
13751 }
13752 else {
13753 ISEQ_BODY(parent_iseq)->catch_table = NULL;
13754 }
13755}
13756
13757static ibf_offset_t
13758ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13759{
13760 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13761 const unsigned int ci_size = body->ci_size;
13762 const struct rb_call_data *cds = body->call_data;
13763
13764 ibf_offset_t offset = ibf_dump_pos(dump);
13765
13766 unsigned int i;
13767
13768 for (i = 0; i < ci_size; i++) {
13769 const struct rb_callinfo *ci = cds[i].ci;
13770 if (ci != NULL) {
13771 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13772 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13773 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13774
13775 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13776 if (kwarg) {
13777 int len = kwarg->keyword_len;
13778 ibf_dump_write_small_value(dump, len);
13779 for (int j=0; j<len; j++) {
13780 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13781 ibf_dump_write_small_value(dump, keyword);
13782 }
13783 }
13784 else {
13785 ibf_dump_write_small_value(dump, 0);
13786 }
13787 }
13788 else {
13789 // TODO: truncate NULL ci from call_data.
13790 ibf_dump_write_small_value(dump, (VALUE)-1);
13791 }
13792 }
13793
13794 return offset;
13795}
13796
13798 ID id;
13799 VALUE name;
13800 VALUE val;
13801};
13802
13804 size_t num;
13805 struct outer_variable_pair pairs[1];
13806};
13807
13808static enum rb_id_table_iterator_result
13809store_outer_variable(ID id, VALUE val, void *dump)
13810{
13811 struct outer_variable_list *ovlist = dump;
13812 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13813 pair->id = id;
13814 pair->name = rb_id2str(id);
13815 pair->val = val;
13816 return ID_TABLE_CONTINUE;
13817}
13818
13819static int
13820outer_variable_cmp(const void *a, const void *b, void *arg)
13821{
13822 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13823 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13824
13825 if (!ap->name) {
13826 return -1;
13827 }
13828 else if (!bp->name) {
13829 return 1;
13830 }
13831
13832 return rb_str_cmp(ap->name, bp->name);
13833}
13834
13835static ibf_offset_t
13836ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13837{
13838 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13839
13840 ibf_offset_t offset = ibf_dump_pos(dump);
13841
13842 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13843 ibf_dump_write_small_value(dump, (VALUE)size);
13844 if (size > 0) {
13845 VALUE buff;
13846 size_t buffsize =
13847 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13848 offsetof(struct outer_variable_list, pairs),
13849 rb_eArgError);
13850 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13851 ovlist->num = 0;
13852 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13853 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13854 for (size_t i = 0; i < size; ++i) {
13855 ID id = ovlist->pairs[i].id;
13856 ID val = ovlist->pairs[i].val;
13857 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13858 ibf_dump_write_small_value(dump, val);
13859 }
13860 ALLOCV_END(buff);
13861 }
13862
13863 return offset;
13864}
13865
13866/* note that we dump out rb_call_info but load back rb_call_data */
13867static void
13868ibf_load_ci_entries(const struct ibf_load *load,
13869 ibf_offset_t ci_entries_offset,
13870 unsigned int ci_size,
13871 struct rb_call_data **cd_ptr)
13872{
13873 if (!ci_size) {
13874 *cd_ptr = NULL;
13875 return;
13876 }
13877
13878 ibf_offset_t reading_pos = ci_entries_offset;
13879
13880 unsigned int i;
13881
13882 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13883 *cd_ptr = cds;
13884
13885 for (i = 0; i < ci_size; i++) {
13886 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13887 if (mid_index != (VALUE)-1) {
13888 ID mid = ibf_load_id(load, mid_index);
13889 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13890 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13891
13892 struct rb_callinfo_kwarg *kwarg = NULL;
13893 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13894 if (kwlen > 0) {
13895 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13896 kwarg->references = 0;
13897 kwarg->keyword_len = kwlen;
13898 for (int j=0; j<kwlen; j++) {
13899 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13900 kwarg->keywords[j] = ibf_load_object(load, keyword);
13901 }
13902 }
13903
13904 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13905 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13906 cds[i].cc = vm_cc_empty();
13907 }
13908 else {
13909 // NULL ci
13910 cds[i].ci = NULL;
13911 cds[i].cc = NULL;
13912 }
13913 }
13914}
13915
13916static struct rb_id_table *
13917ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13918{
13919 ibf_offset_t reading_pos = outer_variables_offset;
13920
13921 struct rb_id_table *tbl = NULL;
13922
13923 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13924
13925 if (table_size > 0) {
13926 tbl = rb_id_table_create(table_size);
13927 }
13928
13929 for (size_t i = 0; i < table_size; i++) {
13930 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13931 VALUE value = ibf_load_small_value(load, &reading_pos);
13932 if (!key) key = rb_make_temporary_id(i);
13933 rb_id_table_insert(tbl, key, value);
13934 }
13935
13936 return tbl;
13937}
13938
13939static ibf_offset_t
13940ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13941{
13942 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13943
13944 unsigned int *positions;
13945
13946 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13947
13948 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13949 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13950
13951#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13952 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13953
13954 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13955 struct ibf_dump_buffer buffer;
13956 buffer.str = rb_str_new(0, 0);
13957 buffer.obj_table = ibf_dump_object_table_new();
13958 dump->current_buffer = &buffer;
13959#endif
13960
13961 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13962 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13963 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13964 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13965 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13966
13967 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13968 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13969 SIZED_FREE_N(positions, ISEQ_BODY(iseq)->insns_info.size);
13970
13971 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13972 const ibf_offset_t lvar_states_offset = ibf_dump_lvar_states(dump, iseq);
13973 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13974 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13975 /* a NULL parent (persisted root) and references outside a Proc#refined subtree dump come out absent (-1) */
13976 const int parent_iseq_index = ibf_table_lookup(dump->iseq_table, (st_data_t)ISEQ_BODY(iseq)->parent_iseq);
13977 const int local_iseq_index = ibf_table_lookup(dump->iseq_table, (st_data_t)ISEQ_BODY(iseq)->local_iseq);
13978 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13979 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13980 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13981
13982#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13983 ibf_offset_t local_obj_list_offset;
13984 unsigned int local_obj_list_size;
13985
13986 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13987#endif
13988
13989 ibf_offset_t body_offset = ibf_dump_pos(dump);
13990
13991 /* dump the constant body */
13992 unsigned int param_flags =
13993 (body->param.flags.has_lead << 0) |
13994 (body->param.flags.has_opt << 1) |
13995 (body->param.flags.has_rest << 2) |
13996 (body->param.flags.has_post << 3) |
13997 (body->param.flags.has_kw << 4) |
13998 (body->param.flags.has_kwrest << 5) |
13999 (body->param.flags.has_block << 6) |
14000 (body->param.flags.ambiguous_param0 << 7) |
14001 (body->param.flags.accepts_no_kwarg << 8) |
14002 (body->param.flags.ruby2_keywords << 9) |
14003 (body->param.flags.anon_rest << 10) |
14004 (body->param.flags.anon_kwrest << 11) |
14005 (body->param.flags.use_block << 12) |
14006 (body->param.flags.forwardable << 13) |
14007 (body->param.flags.accepts_no_block << 14);
14008
14009#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14010# define IBF_BODY_OFFSET(x) (x)
14011#else
14012# define IBF_BODY_OFFSET(x) (body_offset - (x))
14013#endif
14014
14015 ibf_dump_write_small_value(dump, body->type);
14016 ibf_dump_write_small_value(dump, body->iseq_size);
14017 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
14018 ibf_dump_write_small_value(dump, bytecode_size);
14019 ibf_dump_write_small_value(dump, param_flags);
14020 ibf_dump_write_small_value(dump, body->param.size);
14021 ibf_dump_write_small_value(dump, body->param.lead_num);
14022 ibf_dump_write_small_value(dump, body->param.opt_num);
14023 ibf_dump_write_small_value(dump, body->param.rest_start);
14024 ibf_dump_write_small_value(dump, body->param.post_start);
14025 ibf_dump_write_small_value(dump, body->param.post_num);
14026 ibf_dump_write_small_value(dump, body->param.block_start);
14027 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
14028 ibf_dump_write_small_value(dump, param_keyword_offset);
14029 ibf_dump_write_small_value(dump, location_pathobj_index);
14030 ibf_dump_write_small_value(dump, body->no_realpath);
14031 ibf_dump_write_small_value(dump, location_label_index);
14032 ibf_dump_write_small_value(dump, body->location.first_lineno);
14033 ibf_dump_write_small_value(dump, body->location.node_id);
14034 /* Dump the source hash (0 if unavailable) in two 32-bit halves, because
14035 * VALUE may be 32 bits wide. */
14036 ibf_dump_write_small_value(dump, (VALUE)(uint32_t)(body->source_hash >> 32));
14037 ibf_dump_write_small_value(dump, (VALUE)(uint32_t)body->source_hash);
14038 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
14039 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
14040 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
14041 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
14042 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
14043 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
14044 ibf_dump_write_small_value(dump, body->insns_info.size);
14045 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
14046 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(lvar_states_offset));
14047 ibf_dump_write_small_value(dump, catch_table_size);
14048 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
14049 ibf_dump_write_small_value(dump, parent_iseq_index);
14050 ibf_dump_write_small_value(dump, local_iseq_index);
14051 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
14052 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
14053 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
14054 ibf_dump_write_small_value(dump, ISEQ_FLIP_CNT(iseq));
14055 ibf_dump_write_small_value(dump, body->local_table_size);
14056 ibf_dump_write_small_value(dump, body->ivc_size);
14057 ibf_dump_write_small_value(dump, body->icvarc_size);
14058 ibf_dump_write_small_value(dump, body->ise_size);
14059 ibf_dump_write_small_value(dump, body->ic_size);
14060 ibf_dump_write_small_value(dump, body->ci_size);
14061 ibf_dump_write_small_value(dump, body->stack_max);
14062 ibf_dump_write_small_value(dump, body->builtin_attrs);
14063 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
14064
14065#undef IBF_BODY_OFFSET
14066
14067#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14068 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
14069
14070 dump->current_buffer = saved_buffer;
14071 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
14072
14073 ibf_offset_t offset = ibf_dump_pos(dump);
14074 ibf_dump_write_small_value(dump, iseq_start);
14075 ibf_dump_write_small_value(dump, iseq_length_bytes);
14076 ibf_dump_write_small_value(dump, body_offset);
14077
14078 ibf_dump_write_small_value(dump, local_obj_list_offset);
14079 ibf_dump_write_small_value(dump, local_obj_list_size);
14080
14081 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
14082
14083 return offset;
14084#else
14085 return body_offset;
14086#endif
14087}
14088
14089static VALUE
14090ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
14091{
14092 VALUE str = ibf_load_object(load, str_index);
14093 if (str != Qnil) {
14094 str = rb_fstring(str);
14095 }
14096 return str;
14097}
14098
14099static void
14100ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
14101{
14102 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
14103
14104 ibf_offset_t reading_pos = offset;
14105
14106#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14107 struct ibf_load_buffer *saved_buffer = load->current_buffer;
14108 load->current_buffer = &load->global_buffer;
14109
14110 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14111 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14112 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14113
14114 struct ibf_load_buffer buffer;
14115 buffer.buff = load->global_buffer.buff + iseq_start;
14116 buffer.size = iseq_length_bytes;
14117 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14118 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14119 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
14120
14121 load->current_buffer = &buffer;
14122 reading_pos = body_offset;
14123#endif
14124
14125#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14126# define IBF_BODY_OFFSET(x) (x)
14127#else
14128# define IBF_BODY_OFFSET(x) (offset - (x))
14129#endif
14130
14131 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
14132 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14133 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14134 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14135 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
14136 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14137 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
14138 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
14139 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
14140 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
14141 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
14142 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
14143 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14144 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14145 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
14146 const bool no_realpath = (bool)ibf_load_small_value(load, &reading_pos);
14147 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
14148 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
14149 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
14150 const uint64_t source_hash_hi = (uint64_t)ibf_load_small_value(load, &reading_pos);
14151 const uint64_t source_hash_lo = (uint64_t)ibf_load_small_value(load, &reading_pos);
14152 const uint64_t source_hash = (source_hash_hi << 32) | (uint32_t)source_hash_lo;
14153 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
14154 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
14155 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
14156 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
14157 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14158 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14159 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14160 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14161 const ibf_offset_t lvar_states_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14162 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14163 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14164 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
14165 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
14166 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
14167 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14168 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14169 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
14170 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14171
14172 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14173 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14174 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14175 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14176
14177 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14178 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
14179 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
14180 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
14181
14182 // setup fname and dummy frame
14183 VALUE path = ibf_load_object(load, location_pathobj_index);
14184 {
14185 VALUE realpath = Qnil;
14186
14187 if (RB_TYPE_P(path, T_STRING)) {
14188 path = rb_fstring(path);
14189 realpath = no_realpath ? Qnil : path;
14190 }
14191 else if (RB_TYPE_P(path, T_ARRAY)) {
14192 VALUE pathobj = path;
14193 if (RARRAY_LEN(pathobj) != 2) {
14194 rb_raise(rb_eRuntimeError, "path object size mismatch");
14195 }
14196 path = rb_fstring(RARRAY_AREF(pathobj, 0));
14197 realpath = RARRAY_AREF(pathobj, 1);
14198 if (!NIL_P(realpath)) {
14199 if (!RB_TYPE_P(realpath, T_STRING)) {
14200 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
14201 "(%x), path=%+"PRIsVALUE,
14202 realpath, TYPE(realpath), path);
14203 }
14204 realpath = rb_fstring(realpath);
14205 }
14206 }
14207 else {
14208 rb_raise(rb_eRuntimeError, "unexpected path object");
14209 }
14210 rb_iseq_pathobj_set(iseq, path, realpath);
14211 }
14212
14213 // push dummy frame
14214 rb_execution_context_t *ec = GET_EC();
14215 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
14216
14217#undef IBF_BODY_OFFSET
14218
14219 load_body->type = type;
14220 load_body->stack_max = stack_max;
14221 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
14222 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
14223 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
14224 load_body->param.flags.has_post = (param_flags >> 3) & 1;
14225 load_body->param.flags.has_kw = FALSE;
14226 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
14227 load_body->param.flags.has_block = (param_flags >> 6) & 1;
14228 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
14229 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
14230 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
14231 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
14232 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
14233 load_body->param.flags.use_block = (param_flags >> 12) & 1;
14234 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
14235 load_body->param.flags.accepts_no_block = (param_flags >> 14) & 1;
14236 load_body->param.size = param_size;
14237 load_body->param.lead_num = param_lead_num;
14238 load_body->param.opt_num = param_opt_num;
14239 load_body->param.rest_start = param_rest_start;
14240 load_body->param.post_start = param_post_start;
14241 load_body->param.post_num = param_post_num;
14242 load_body->param.block_start = param_block_start;
14243 load_body->local_table_size = local_table_size;
14244 load_body->ci_size = ci_size;
14245 load_body->insns_info.size = insns_info_size;
14246
14247 // variable is NULL from ZALLOC; only allocate if flip_count is non-zero.
14248 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
14249 if (variable_flip_count) {
14250 struct rb_iseq_variable *v = rb_iseq_variable_ensure(iseq);
14251 v->flip_count = variable_flip_count;
14252 }
14253
14254 load_body->location.first_lineno = location_first_lineno;
14255 load_body->location.node_id = location_node_id;
14256 load_body->source_hash = source_hash;
14257 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
14258 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
14259 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
14260 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
14261 load_body->builtin_attrs = builtin_attrs;
14262 load_body->prism = prism;
14263
14264 load_body->ivc_size = ivc_size;
14265 load_body->icvarc_size = icvarc_size;
14266 load_body->ise_size = ise_size;
14267 load_body->ic_size = ic_size;
14268
14269 if (ISEQ_IS_SIZE(load_body)) {
14270 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
14271 }
14272 else {
14273 load_body->is_entries = NULL;
14274 }
14275 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
14276 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
14277 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
14278 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
14279 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
14280 ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size, load_body);
14281 load_body->insns_info.positions_or_succ_index_table.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
14282 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
14283 ibf_load_lvar_states(load, load_body, lvar_states_offset, local_table_size, load_body->local_table);
14284 ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
14285
14286 const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
14287 const rb_iseq_t *local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
14288 const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
14289
14290 RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
14291 RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
14292 RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
14293
14294 // This must be done after the local table is loaded.
14295 if (load_body->param.keyword != NULL) {
14296 RUBY_ASSERT(load_body->local_table);
14297 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
14298 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
14299 }
14300
14301 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
14302#if VM_INSN_INFO_TABLE_IMPL == 2
14303 rb_iseq_insns_info_encode_positions(iseq);
14304#endif
14305
14306 rb_iseq_translate_threaded_code(iseq);
14307
14308#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14309 load->current_buffer = &load->global_buffer;
14310#endif
14311
14312 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
14313
14314#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14315 load->current_buffer = saved_buffer;
14316#endif
14317 verify_call_cache(iseq);
14318
14319 RB_GC_GUARD(dummy_frame);
14320 rb_vm_pop_frame_no_int(ec);
14321}
14322
14324{
14325 struct ibf_dump *dump;
14326 VALUE offset_list;
14327};
14328
14329static int
14330ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14331{
14332 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
14333 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
14334
14335 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
14336 rb_ary_push(args->offset_list, UINT2NUM(offset));
14337
14338 return ST_CONTINUE;
14339}
14340
14341static void
14342ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
14343{
14344 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
14345
14346 struct ibf_dump_iseq_list_arg args;
14347 args.dump = dump;
14348 args.offset_list = offset_list;
14349
14350 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
14351
14352 st_index_t i;
14353 st_index_t size = dump->iseq_table->num_entries;
14354 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
14355
14356 for (i = 0; i < size; i++) {
14357 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
14358 }
14359
14360 ibf_dump_align(dump, sizeof(ibf_offset_t));
14361 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
14362 header->iseq_list_size = (unsigned int)size;
14363}
14364
14365/*
14366 * Binary format
14367 * - ibf_object_header
14368 * - ibf_object_xxx (xxx is type)
14369 */
14370
14372 unsigned int type: 5;
14373 unsigned int special_const: 1;
14374 unsigned int frozen: 1;
14375 unsigned int internal: 1;
14376};
14377
14378enum ibf_object_class_index {
14379 IBF_OBJECT_CLASS_OBJECT,
14380 IBF_OBJECT_CLASS_ARRAY,
14381 IBF_OBJECT_CLASS_STANDARD_ERROR,
14382 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
14383 IBF_OBJECT_CLASS_TYPE_ERROR,
14384 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
14385};
14386
14388 long srcstr;
14389 char option;
14390};
14391
14393 long len;
14394 long keyval[FLEX_ARY_LEN];
14395};
14396
14398 long class_index;
14399 long len;
14400 long beg;
14401 long end;
14402 int excl;
14403};
14404
14406 ssize_t slen;
14407 BDIGIT digits[FLEX_ARY_LEN];
14408};
14409
14410enum ibf_object_data_type {
14411 IBF_OBJECT_DATA_ENCODING,
14412};
14413
14415 long a, b;
14416};
14417
14419 long str;
14420};
14421
14422#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
14423 ((((offset) - 1) / (align) + 1) * (align))
14424/* No cast, since it's UB to create an unaligned pointer.
14425 * Leave as void* for use with memcpy in those cases.
14426 * We align the offset, but the buffer pointer is only VALUE aligned,
14427 * so the returned pointer may be unaligned for `type` .*/
14428#define IBF_OBJBODY(type, offset) \
14429 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
14430
14431static const void *
14432ibf_load_check_offset(const struct ibf_load *load, size_t offset)
14433{
14434 if (offset >= load->current_buffer->size) {
14435 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
14436 }
14437 return load->current_buffer->buff + offset;
14438}
14439
14440NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
14441
14442static void
14443ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
14444{
14445 char buff[0x100];
14446 rb_raw_obj_info(buff, sizeof(buff), obj);
14447 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
14448}
14449
14450NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
14451
14452static VALUE
14453ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14454{
14455 rb_raise(rb_eArgError, "unsupported");
14457}
14458
14459static void
14460ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
14461{
14462 enum ibf_object_class_index cindex;
14463 if (obj == rb_cObject) {
14464 cindex = IBF_OBJECT_CLASS_OBJECT;
14465 }
14466 else if (obj == rb_cArray) {
14467 cindex = IBF_OBJECT_CLASS_ARRAY;
14468 }
14469 else if (obj == rb_eStandardError) {
14470 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
14471 }
14472 else if (obj == rb_eNoMatchingPatternError) {
14473 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
14474 }
14475 else if (obj == rb_eTypeError) {
14476 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
14477 }
14478 else if (obj == rb_eNoMatchingPatternKeyError) {
14479 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
14480 }
14481 else {
14482 rb_obj_info_dump(obj);
14483 rb_p(obj);
14484 rb_bug("unsupported class");
14485 }
14486 ibf_dump_write_small_value(dump, (VALUE)cindex);
14487}
14488
14489static VALUE
14490ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14491{
14492 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
14493
14494 switch (cindex) {
14495 case IBF_OBJECT_CLASS_OBJECT:
14496 return rb_cObject;
14497 case IBF_OBJECT_CLASS_ARRAY:
14498 return rb_cArray;
14499 case IBF_OBJECT_CLASS_STANDARD_ERROR:
14500 return rb_eStandardError;
14501 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
14503 case IBF_OBJECT_CLASS_TYPE_ERROR:
14504 return rb_eTypeError;
14505 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
14507 }
14508
14509 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
14510}
14511
14512
14513static void
14514ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
14515{
14516 double dbl = RFLOAT_VALUE(obj);
14517 (void)IBF_W(&dbl, double, 1);
14518}
14519
14520static VALUE
14521ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14522{
14523 double d;
14524 /* Avoid unaligned VFP load on ARMv7; IBF payload may be unaligned (C99 6.3.2.3 p7). */
14525 memcpy(&d, IBF_OBJBODY(double, offset), sizeof(d));
14526 VALUE f = DBL2NUM(d);
14527 if (!FLONUM_P(f)) RB_OBJ_SET_SHAREABLE(f);
14528 return f;
14529}
14530
14531static void
14532ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
14533{
14534 long encindex = (long)rb_enc_get_index(obj);
14535 rb_len_t len = RSTRING_LEN(obj);
14536 const char *ptr = RSTRING_PTR(obj);
14537
14538 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14539 rb_encoding *enc = rb_enc_from_index((int)encindex);
14540 const char *enc_name = rb_enc_name(enc);
14541 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
14542 }
14543
14544 ibf_dump_write_small_value(dump, encindex);
14545 ibf_dump_write_small_value(dump, len);
14546 IBF_WP(ptr, char, len);
14547}
14548
14549static VALUE
14550ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14551{
14552 ibf_offset_t reading_pos = offset;
14553
14554 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14555 const rb_len_t len = (rb_len_t)ibf_load_small_value(load, &reading_pos);
14556 const char *ptr = load->current_buffer->buff + reading_pos;
14557
14558 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14559 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14560 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14561 }
14562
14563 VALUE str;
14564 if (header->frozen && !header->internal) {
14565 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
14566 }
14567 else {
14568 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
14569
14570 if (header->internal) rb_obj_hide(str);
14571 if (header->frozen) str = rb_fstring(str);
14572 }
14573 return str;
14574}
14575
14576static void
14577ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
14578{
14579 VALUE srcstr = RREGEXP_SRC(obj);
14580 struct ibf_object_regexp regexp;
14581 regexp.option = (char)rb_reg_options(obj);
14582 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
14583
14584 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
14585 ibf_dump_write_small_value(dump, regexp.srcstr);
14586}
14587
14588static VALUE
14589ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14590{
14591 struct ibf_object_regexp regexp;
14592 regexp.option = ibf_load_byte(load, &offset);
14593 regexp.srcstr = ibf_load_small_value(load, &offset);
14594
14595 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14596 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
14597
14598 if (header->internal) rb_obj_hide(reg);
14599 if (header->frozen) RB_OBJ_SET_SHAREABLE(rb_obj_freeze(reg));
14600
14601 return reg;
14602}
14603
14604static void
14605ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
14606{
14607 rb_len_t i, len = RARRAY_LEN(obj);
14608 ibf_dump_write_small_value(dump, len);
14609 for (i=0; i<len; i++) {
14610 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
14611 ibf_dump_write_small_value(dump, index);
14612 }
14613}
14614
14615static VALUE
14616ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14617{
14618 ibf_offset_t reading_pos = offset;
14619
14620 const rb_len_t len = (rb_len_t)ibf_load_small_value(load, &reading_pos);
14621
14622 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
14623 int i;
14624
14625 for (i=0; i<len; i++) {
14626 const VALUE index = ibf_load_small_value(load, &reading_pos);
14627 rb_ary_push(ary, ibf_load_object(load, index));
14628 }
14629
14630 if (header->frozen) {
14631 rb_ary_freeze(ary);
14632 rb_ractor_make_shareable(ary); // TODO: check elements
14633 }
14634
14635 return ary;
14636}
14637
14638static int
14639ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14640{
14641 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14642
14643 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14644 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14645
14646 ibf_dump_write_small_value(dump, key_index);
14647 ibf_dump_write_small_value(dump, val_index);
14648 return ST_CONTINUE;
14649}
14650
14651static void
14652ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14653{
14654 long len = RHASH_SIZE(obj);
14655 ibf_dump_write_small_value(dump, (VALUE)len);
14656
14657 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14658}
14659
14660static VALUE
14661ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14662{
14663 long len = (long)ibf_load_small_value(load, &offset);
14664 VALUE obj = header->frozen ? rb_hash_alloc_fixed_size(rb_cHash, len) : rb_hash_new_capa(len);
14665 int i;
14666
14667 for (i = 0; i < len; i++) {
14668 VALUE key_index = ibf_load_small_value(load, &offset);
14669 VALUE val_index = ibf_load_small_value(load, &offset);
14670
14671 VALUE key = ibf_load_object(load, key_index);
14672 VALUE val = ibf_load_object(load, val_index);
14673 rb_hash_aset(obj, key, val);
14674 }
14675
14676 if (header->internal) rb_obj_hide(obj);
14677 if (header->frozen) {
14679 }
14680
14681 return obj;
14682}
14683
14684static int
14685ibf_dump_cdhash_i(st_data_t key, st_data_t val, st_data_t ptr)
14686{
14687 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14688
14689 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14690
14691 ibf_dump_write_small_value(dump, key_index);
14692 ibf_dump_write_small_value(dump, val);
14693 return ST_CONTINUE;
14694}
14695
14696static void
14697ibf_dump_object_imemo(struct ibf_dump *dump, VALUE obj)
14698{
14699 switch (imemo_type(obj)) {
14700 case imemo_cdhash: {
14701 st_table *tbl = rb_imemo_cdhash_tbl(obj);
14702
14703 long len = tbl->num_entries;
14704 ibf_dump_write_small_value(dump, (VALUE)len);
14705 if (len > 0) st_foreach(tbl, ibf_dump_cdhash_i, (VALUE)dump);
14706 break;
14707 }
14708 default:
14709 ibf_dump_object_unsupported(dump, obj);
14710 break;
14711 }
14712}
14713
14714static VALUE
14715ibf_load_object_imemo(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14716{
14717 long len = (long)ibf_load_small_value(load, &offset);
14718 VALUE obj = cdhash_new(len);
14719
14720 int i;
14721 for (i = 0; i < len; i++) {
14722 VALUE key_index = ibf_load_small_value(load, &offset);
14723 VALUE val = ibf_load_small_value(load, &offset);
14724
14725 VALUE key = ibf_load_object(load, key_index);
14726 cdhash_aset(obj, key, val);
14727 }
14728
14729 return obj;
14730}
14731
14732static void
14733ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14734{
14735 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14736 struct ibf_object_struct_range range;
14737 VALUE beg, end;
14738 IBF_ZERO(range);
14739 range.len = 3;
14740 range.class_index = 0;
14741
14742 rb_range_values(obj, &beg, &end, &range.excl);
14743 range.beg = (long)ibf_dump_object(dump, beg);
14744 range.end = (long)ibf_dump_object(dump, end);
14745
14746 IBF_W_ALIGN(struct ibf_object_struct_range);
14747 IBF_WV(range);
14748 }
14749 else {
14750 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14751 rb_class_name(CLASS_OF(obj)));
14752 }
14753}
14754
14755static VALUE
14756ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14757{
14758 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14759 VALUE beg = ibf_load_object(load, range->beg);
14760 VALUE end = ibf_load_object(load, range->end);
14761 VALUE obj = rb_range_new(beg, end, range->excl);
14762 if (header->internal) rb_obj_hide(obj);
14763 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14764 return obj;
14765}
14766
14767static void
14768ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14769{
14770 ssize_t len = BIGNUM_LEN(obj);
14771 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14772 BDIGIT *d = BIGNUM_DIGITS(obj);
14773
14774 (void)IBF_W(&slen, ssize_t, 1);
14775 IBF_WP(d, BDIGIT, len);
14776}
14777
14778static VALUE
14779ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14780{
14781 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14782 int sign = bignum->slen > 0;
14783 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14784 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14787 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14788 big_unpack_flags |
14789 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14790 if (header->internal) rb_obj_hide(obj);
14791 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14792 return obj;
14793}
14794
14795static void
14796ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14797{
14798 if (rb_data_is_encoding(obj)) {
14799 rb_encoding *enc = rb_to_encoding(obj);
14800 const char *name = rb_enc_name(enc);
14801 long len = strlen(name) + 1;
14802 long data[2];
14803 data[0] = IBF_OBJECT_DATA_ENCODING;
14804 data[1] = len;
14805 (void)IBF_W(data, long, 2);
14806 IBF_WP(name, char, len);
14807 }
14808 else {
14809 ibf_dump_object_unsupported(dump, obj);
14810 }
14811}
14812
14813static VALUE
14814ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14815{
14816 const long *body = IBF_OBJBODY(long, offset);
14817 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14818 /* const long len = body[1]; */
14819 const char *data = (const char *)&body[2];
14820
14821 switch (type) {
14822 case IBF_OBJECT_DATA_ENCODING:
14823 {
14824 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14825 return encobj;
14826 }
14827 }
14828
14829 return ibf_load_object_unsupported(load, header, offset);
14830}
14831
14832static void
14833ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14834{
14835 long data[2];
14836 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14837 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14838
14839 (void)IBF_W(data, long, 2);
14840}
14841
14842static VALUE
14843ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14844{
14845 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14846 VALUE a = ibf_load_object(load, nums->a);
14847 VALUE b = ibf_load_object(load, nums->b);
14848 VALUE obj = header->type == T_COMPLEX ?
14849 rb_complex_new(a, b) : rb_rational_new(a, b);
14850
14851 if (header->internal) rb_obj_hide(obj);
14852 if (header->frozen) rb_ractor_make_shareable(rb_obj_freeze(obj));
14853 return obj;
14854}
14855
14856static void
14857ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14858{
14859 ibf_dump_object_string(dump, rb_sym2str(obj));
14860}
14861
14862static VALUE
14863ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14864{
14865 ibf_offset_t reading_pos = offset;
14866
14867 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14868 const rb_len_t len = (rb_len_t)ibf_load_small_value(load, &reading_pos);
14869 const char *ptr = load->current_buffer->buff + reading_pos;
14870
14871 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14872 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14873 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14874 }
14875
14876 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14877 return ID2SYM(id);
14878}
14879
14880typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14881static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14882 ibf_dump_object_unsupported, /* T_NONE */
14883 ibf_dump_object_unsupported, /* T_OBJECT */
14884 ibf_dump_object_class, /* T_CLASS */
14885 ibf_dump_object_unsupported, /* T_MODULE */
14886 ibf_dump_object_float, /* T_FLOAT */
14887 ibf_dump_object_string, /* T_STRING */
14888 ibf_dump_object_regexp, /* T_REGEXP */
14889 ibf_dump_object_array, /* T_ARRAY */
14890 ibf_dump_object_hash, /* T_HASH */
14891 ibf_dump_object_struct, /* T_STRUCT */
14892 ibf_dump_object_bignum, /* T_BIGNUM */
14893 ibf_dump_object_unsupported, /* T_FILE */
14894 ibf_dump_object_data, /* T_DATA */
14895 ibf_dump_object_unsupported, /* T_MATCH */
14896 ibf_dump_object_complex_rational, /* T_COMPLEX */
14897 ibf_dump_object_complex_rational, /* T_RATIONAL */
14898 ibf_dump_object_unsupported, /* 0x10 */
14899 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14900 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14901 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14902 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14903 ibf_dump_object_unsupported, /* T_FIXNUM */
14904 ibf_dump_object_unsupported, /* T_UNDEF */
14905 ibf_dump_object_unsupported, /* 0x17 */
14906 ibf_dump_object_unsupported, /* 0x18 */
14907 ibf_dump_object_unsupported, /* 0x19 */
14908 ibf_dump_object_imemo, /* T_IMEMO 0x1a */
14909 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14910 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14911 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14912 ibf_dump_object_unsupported, /* 0x1e */
14913 ibf_dump_object_unsupported, /* 0x1f */
14914};
14915
14916static void
14917ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14918{
14919 unsigned char byte =
14920 (header.type << 0) |
14921 (header.special_const << 5) |
14922 (header.frozen << 6) |
14923 (header.internal << 7);
14924
14925 IBF_WV(byte);
14926}
14927
14928static struct ibf_object_header
14929ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14930{
14931 unsigned char byte = ibf_load_byte(load, offset);
14932
14933 struct ibf_object_header header;
14934 header.type = (byte >> 0) & 0x1f;
14935 header.special_const = (byte >> 5) & 0x01;
14936 header.frozen = (byte >> 6) & 0x01;
14937 header.internal = (byte >> 7) & 0x01;
14938
14939 return header;
14940}
14941
14942static ibf_offset_t
14943ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14944{
14945 struct ibf_object_header obj_header;
14946 ibf_offset_t current_offset;
14947 IBF_ZERO(obj_header);
14948 obj_header.type = TYPE(obj);
14949
14950 IBF_W_ALIGN(ibf_offset_t);
14951 current_offset = ibf_dump_pos(dump);
14952
14953 if (SPECIAL_CONST_P(obj) &&
14954 ! (SYMBOL_P(obj) ||
14955 RB_FLOAT_TYPE_P(obj))) {
14956 obj_header.special_const = TRUE;
14957 obj_header.frozen = TRUE;
14958 obj_header.internal = TRUE;
14959 ibf_dump_object_object_header(dump, obj_header);
14960 ibf_dump_write_small_value(dump, obj);
14961 }
14962 else {
14963 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14964 obj_header.special_const = FALSE;
14965 obj_header.frozen = OBJ_FROZEN(obj) ? TRUE : FALSE;
14966 ibf_dump_object_object_header(dump, obj_header);
14967 (*dump_object_functions[obj_header.type])(dump, obj);
14968 }
14969
14970 return current_offset;
14971}
14972
14973typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14974static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14975 ibf_load_object_unsupported, /* T_NONE */
14976 ibf_load_object_unsupported, /* T_OBJECT */
14977 ibf_load_object_class, /* T_CLASS */
14978 ibf_load_object_unsupported, /* T_MODULE */
14979 ibf_load_object_float, /* T_FLOAT */
14980 ibf_load_object_string, /* T_STRING */
14981 ibf_load_object_regexp, /* T_REGEXP */
14982 ibf_load_object_array, /* T_ARRAY */
14983 ibf_load_object_hash, /* T_HASH */
14984 ibf_load_object_struct, /* T_STRUCT */
14985 ibf_load_object_bignum, /* T_BIGNUM */
14986 ibf_load_object_unsupported, /* T_FILE */
14987 ibf_load_object_data, /* T_DATA */
14988 ibf_load_object_unsupported, /* T_MATCH */
14989 ibf_load_object_complex_rational, /* T_COMPLEX */
14990 ibf_load_object_complex_rational, /* T_RATIONAL */
14991 ibf_load_object_unsupported, /* 0x10 */
14992 ibf_load_object_unsupported, /* T_NIL */
14993 ibf_load_object_unsupported, /* T_TRUE */
14994 ibf_load_object_unsupported, /* T_FALSE */
14995 ibf_load_object_symbol,
14996 ibf_load_object_unsupported, /* T_FIXNUM */
14997 ibf_load_object_unsupported, /* T_UNDEF */
14998 ibf_load_object_unsupported, /* 0x17 */
14999 ibf_load_object_unsupported, /* 0x18 */
15000 ibf_load_object_unsupported, /* 0x19 */
15001 ibf_load_object_imemo, /* T_IMEMO 0x1a */
15002 ibf_load_object_unsupported, /* T_NODE 0x1b */
15003 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
15004 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
15005 ibf_load_object_unsupported, /* 0x1e */
15006 ibf_load_object_unsupported, /* 0x1f */
15007};
15008
15009static VALUE
15010ibf_load_object(const struct ibf_load *load, VALUE object_index)
15011{
15012 if (object_index == 0) {
15013 return Qnil;
15014 }
15015 else {
15016 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
15017 if (!obj) {
15018 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
15019 ibf_offset_t offset = offsets[object_index];
15020 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
15021
15022#if IBF_ISEQ_DEBUG
15023 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
15024 load->current_buffer->obj_list_offset, (void *)offsets, offset);
15025 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
15026 header.type, header.special_const, header.frozen, header.internal);
15027#endif
15028 if (offset >= load->current_buffer->size) {
15029 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
15030 }
15031
15032 if (header.special_const) {
15033 ibf_offset_t reading_pos = offset;
15034
15035 obj = ibf_load_small_value(load, &reading_pos);
15036 }
15037 else {
15038 obj = (*load_object_functions[header.type])(load, &header, offset);
15039 }
15040
15041 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
15042 }
15043#if IBF_ISEQ_DEBUG
15044 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
15045 object_index, obj);
15046#endif
15047 return obj;
15048 }
15049}
15050
15052{
15053 struct ibf_dump *dump;
15054 VALUE offset_list;
15055};
15056
15057static int
15058ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
15059{
15060 VALUE obj = (VALUE)key;
15061 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
15062
15063 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
15064 rb_ary_push(args->offset_list, UINT2NUM(offset));
15065
15066 return ST_CONTINUE;
15067}
15068
15069static void
15070ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
15071{
15072 st_table *obj_table = dump->current_buffer->obj_table;
15073 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
15074
15075 struct ibf_dump_object_list_arg args;
15076 args.dump = dump;
15077 args.offset_list = offset_list;
15078
15079 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
15080
15081 IBF_W_ALIGN(ibf_offset_t);
15082 *obj_list_offset = ibf_dump_pos(dump);
15083
15084 st_index_t size = obj_table->num_entries;
15085 st_index_t i;
15086
15087 for (i=0; i<size; i++) {
15088 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
15089 IBF_WV(offset);
15090 }
15091
15092 *obj_list_size = (unsigned int)size;
15093}
15094
15095static void
15096ibf_dump_mark(void *ptr)
15097{
15098 struct ibf_dump *dump = (struct ibf_dump *)ptr;
15099 rb_gc_mark(dump->global_buffer.str);
15100
15101 rb_mark_set(dump->global_buffer.obj_table);
15102 rb_mark_set(dump->iseq_table);
15103}
15104
15105static void
15106ibf_dump_free(void *ptr)
15107{
15108 struct ibf_dump *dump = (struct ibf_dump *)ptr;
15109 if (dump->global_buffer.obj_table) {
15110 st_free_table(dump->global_buffer.obj_table);
15111 dump->global_buffer.obj_table = 0;
15112 }
15113 if (dump->iseq_table) {
15114 st_free_table(dump->iseq_table);
15115 dump->iseq_table = 0;
15116 }
15117}
15118
15119static size_t
15120ibf_dump_memsize(const void *ptr)
15121{
15122 struct ibf_dump *dump = (struct ibf_dump *)ptr;
15123 size_t size = 0;
15124 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
15125 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
15126 return size;
15127}
15128
15129static const rb_data_type_t ibf_dump_type = {
15130 "ibf_dump",
15131 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
15132 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_EMBEDDABLE
15133};
15134
15135static void
15136ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
15137{
15138 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
15139 dump->iseq_table = NULL;
15140
15141 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
15142 dump->global_buffer.obj_table = ibf_dump_object_table_new();
15143 dump->iseq_table = st_init_numtable(); /* need free */
15144
15145 dump->current_buffer = &dump->global_buffer;
15146}
15147
15148static VALUE
15149iseq_ibf_dump_0(struct ibf_dump *dump, const rb_iseq_t *iseq, VALUE opt)
15150{
15151 struct ibf_header header = {{0}};
15152
15153 ibf_dump_write(dump, &header, sizeof(header));
15154 ibf_dump_iseq(dump, iseq);
15155
15156 header.magic[0] = 'Y'; /* YARB */
15157 header.magic[1] = 'A';
15158 header.magic[2] = 'R';
15159 header.magic[3] = 'B';
15160 header.major_version = IBF_MAJOR_VERSION;
15161 header.minor_version = IBF_MINOR_VERSION;
15162 header.endian = IBF_ENDIAN_MARK;
15163 header.wordsize = (uint8_t)SIZEOF_VALUE;
15164 ibf_dump_iseq_list(dump, &header);
15165 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
15166 header.size = ibf_dump_pos(dump);
15167
15168 if (RTEST(opt)) {
15169 VALUE opt_str = opt;
15170 const char *ptr = StringValuePtr(opt_str);
15171 header.extra_size = RSTRING_LENINT(opt_str);
15172 ibf_dump_write(dump, ptr, header.extra_size);
15173 }
15174 else {
15175 header.extra_size = 0;
15176 }
15177
15178 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
15179
15180 return dump->global_buffer.str;
15181}
15182
15183VALUE
15184rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
15185{
15186 struct ibf_dump *dump;
15187 VALUE dump_obj;
15188 VALUE str;
15189
15190 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
15191 ISEQ_BODY(iseq)->local_iseq != iseq) {
15192 rb_raise(rb_eRuntimeError, "should be top of iseq");
15193 }
15194 if (RTEST(ISEQ_COVERAGE(iseq))) {
15195 rb_raise(rb_eRuntimeError, "should not compile with coverage");
15196 }
15197
15198 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
15199 ibf_dump_setup(dump, dump_obj);
15200
15201 str = iseq_ibf_dump_0(dump, iseq, opt);
15202 RB_GC_GUARD(dump_obj);
15203 return str;
15204}
15205
15206static const ibf_offset_t *
15207ibf_iseq_list(const struct ibf_load *load)
15208{
15209 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
15210}
15211
15212void
15213rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
15214{
15215 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
15216 rb_iseq_t *prev_src_iseq = load->iseq;
15217 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
15218 load->iseq = iseq;
15219#if IBF_ISEQ_DEBUG
15220 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
15221 iseq->aux.loader.index, offset,
15222 load->header->size);
15223#endif
15224 ibf_load_iseq_each(load, iseq, offset);
15225 ISEQ_COMPILE_DATA_CLEAR(iseq);
15226 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
15227 rb_iseq_init_trace(iseq);
15228 load->iseq = prev_src_iseq;
15229}
15230
15231#if USE_LAZY_LOAD
15232const rb_iseq_t *
15233rb_iseq_complete(const rb_iseq_t *iseq)
15234{
15235 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
15236 return iseq;
15237}
15238#endif
15239
15240static rb_iseq_t *
15241ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
15242{
15243 int iseq_index = (int)(VALUE)index_iseq;
15244
15245#if IBF_ISEQ_DEBUG
15246 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
15247 (void *)index_iseq, (void *)load->iseq_list);
15248#endif
15249 if (iseq_index == -1) {
15250 return NULL;
15251 }
15252 else {
15253 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
15254
15255#if IBF_ISEQ_DEBUG
15256 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
15257#endif
15258 if (iseqv) {
15259 return (rb_iseq_t *)iseqv;
15260 }
15261 else {
15262 rb_iseq_t *iseq = iseq_imemo_alloc();
15263#if IBF_ISEQ_DEBUG
15264 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
15265#endif
15266 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
15267 RB_OBJ_WRITE((VALUE)iseq, &iseq->aux.loader.obj, load->loader_obj);
15268 iseq->aux.loader.index = iseq_index;
15269#if IBF_ISEQ_DEBUG
15270 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
15271 (void *)iseq, (void *)load->loader_obj, iseq_index);
15272#endif
15273 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
15274
15275 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
15276#if IBF_ISEQ_DEBUG
15277 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
15278#endif
15279 rb_ibf_load_iseq_complete(iseq);
15280 }
15281
15282#if IBF_ISEQ_DEBUG
15283 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
15284 (void *)iseq, (void *)load->iseq);
15285#endif
15286 return iseq;
15287 }
15288 }
15289}
15290
15291static void
15292ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
15293{
15294 struct ibf_header *header = (struct ibf_header *)bytes;
15295 load->loader_obj = loader_obj;
15296 load->global_buffer.buff = bytes;
15297 load->header = header;
15298 load->global_buffer.size = header->size;
15299 load->global_buffer.obj_list_offset = header->global_object_list_offset;
15300 load->global_buffer.obj_list_size = header->global_object_list_size;
15301 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
15302 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
15303 load->iseq = NULL;
15304
15305 load->current_buffer = &load->global_buffer;
15306
15307 if (size < header->size) {
15308 rb_raise(rb_eRuntimeError, "broken binary format");
15309 }
15310 if (strncmp(header->magic, "YARB", 4) != 0) {
15311 rb_raise(rb_eRuntimeError, "unknown binary format");
15312 }
15313 if (header->major_version != IBF_MAJOR_VERSION ||
15314 header->minor_version != IBF_MINOR_VERSION) {
15315 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
15316 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
15317 }
15318 if (header->endian != IBF_ENDIAN_MARK) {
15319 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
15320 }
15321 if (header->wordsize != SIZEOF_VALUE) {
15322 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
15323 }
15324 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
15325 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
15326 header->iseq_list_offset);
15327 }
15328 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
15329 rb_raise(rb_eArgError, "unaligned object list offset: %u",
15330 load->global_buffer.obj_list_offset);
15331 }
15332}
15333
15334static void
15335ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
15336{
15337 StringValue(str);
15338
15339 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
15340 rb_raise(rb_eRuntimeError, "broken binary format");
15341 }
15342
15343 if (USE_LAZY_LOAD) {
15344 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
15345 }
15346
15347 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
15348 RB_OBJ_WRITE(loader_obj, &load->str, str);
15349}
15350
15351static void
15352ibf_loader_mark(void *ptr)
15353{
15354 struct ibf_load *load = (struct ibf_load *)ptr;
15355 rb_gc_mark(load->str);
15356 rb_gc_mark(load->iseq_list);
15357 rb_gc_mark(load->global_buffer.obj_list);
15358}
15359
15360static void
15361ibf_loader_free(void *ptr)
15362{
15363 struct ibf_load *load = (struct ibf_load *)ptr;
15364 SIZED_FREE(load);
15365}
15366
15367static size_t
15368ibf_loader_memsize(const void *ptr)
15369{
15370 return sizeof(struct ibf_load);
15371}
15372
15373static const rb_data_type_t ibf_load_type = {
15374 "ibf_loader",
15375 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
15376 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_THREAD_SAFE_FREE
15377};
15378
15379const rb_iseq_t *
15380rb_iseq_ibf_load(VALUE str)
15381{
15382 struct ibf_load *load;
15383 rb_iseq_t *iseq;
15384 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15385
15386 ibf_load_setup(load, loader_obj, str);
15387 iseq = ibf_load_iseq(load, 0);
15388
15389 RB_GC_GUARD(loader_obj);
15390 return iseq;
15391}
15392
15393const rb_iseq_t *
15394rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
15395{
15396 struct ibf_load *load;
15397 rb_iseq_t *iseq;
15398 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15399
15400 ibf_load_setup_bytes(load, loader_obj, bytes, size);
15401 iseq = ibf_load_iseq(load, 0);
15402
15403 RB_GC_GUARD(loader_obj);
15404 return iseq;
15405}
15406
15407/* collect the iseq table into an array indexed by iseq-list index */
15408static int
15409ibf_dump_iseq_table_collect_i(st_data_t key, st_data_t val, st_data_t arg)
15410{
15411 const rb_iseq_t **srcs = (const rb_iseq_t **)arg;
15412 srcs[(int)val] = (const rb_iseq_t *)key;
15413 return ST_CONTINUE;
15414}
15415
15416/* pc2branchindex (branch coverage) is per-iseq, so pair each copy with its
15417 * source by list index */
15418static void
15419iseq_subtree_copy_pc2branchindex(const struct ibf_dump *dump, const struct ibf_load *load)
15420{
15421 unsigned int iseq_count = (unsigned int)dump->iseq_table->num_entries;
15422 VALUE srcs_buf;
15423 const rb_iseq_t **srcs = ALLOCV_N(const rb_iseq_t *, srcs_buf, iseq_count);
15424 st_foreach(dump->iseq_table, ibf_dump_iseq_table_collect_i, (st_data_t)srcs);
15425
15426 for (unsigned int i = 0; i < iseq_count; i++) {
15427 rb_iseq_t *copy = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)i);
15428 VALUE pc2branchindex = ISEQ_PC2BRANCHINDEX(srcs[i]);
15429 if (pc2branchindex != Qnil) {
15430 ISEQ_PC2BRANCHINDEX_SET(copy, pc2branchindex);
15431 }
15432 }
15433
15434 ALLOCV_END(srcs_buf);
15435}
15436
15437/* Deep-copy an iseq subtree with independent inline caches for Proc#refined */
15438const rb_iseq_t *
15439rb_iseq_dup_with_independent_caches(const rb_iseq_t *src_root)
15440{
15441 struct ibf_dump *dump;
15442 VALUE dump_obj;
15443 VALUE str;
15444
15445 /* --- dump the subtree --- */
15446 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
15447 ibf_dump_setup(dump, dump_obj);
15448
15449 str = iseq_ibf_dump_0(dump, src_root, Qnil);
15450
15451 /* --- load it back --- */
15452 struct ibf_load *load;
15453 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15454 ibf_load_setup(load, loader_obj, str);
15455
15456 /* What the loader could not reconstruct is the same for every iseq in
15457 * the subtree: the only absent parent is the top's, every absent
15458 * local_iseq is the source's local root (runtime walks compare it
15459 * against the original frames, so a copy must not stand in), and
15460 * pathobj/script_lines/coverage are per-file values. */
15461 const struct rb_iseq_constant_body *sb = ISEQ_BODY(src_root);
15462 unsigned int iseq_count = (unsigned int)dump->iseq_table->num_entries;
15463 const rb_iseq_t *result = NULL;
15464 for (unsigned int i = 0; i < iseq_count; i++) {
15465 rb_iseq_t *copy = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)i);
15466 /* force completion even under USE_LAZY_LOAD */
15467 if (FL_TEST((VALUE)copy, ISEQ_NOT_LOADED_YET)) {
15468 rb_ibf_load_iseq_complete(copy);
15469 }
15470
15471 FL_SET((VALUE)copy, ISEQ_REFINED_COPY);
15472
15473 struct rb_iseq_constant_body *cb = ISEQ_BODY(copy);
15474 if (!cb->local_iseq) RB_OBJ_WRITE(copy, &cb->local_iseq, sb->local_iseq);
15475 RB_OBJ_WRITE(copy, &cb->location.pathobj, sb->location.pathobj);
15476 cb->no_realpath = sb->no_realpath;
15477 VALUE sl = ISEQ_SCRIPT_LINES(src_root);
15478 VALUE cov = ISEQ_COVERAGE(src_root);
15479 if (!NIL_P(sl) || !NIL_P(cov)) {
15480 struct rb_iseq_variable *v = rb_iseq_variable_ensure(copy);
15481 RB_OBJ_WRITE(copy, &v->script_lines, sl);
15482 RB_OBJ_WRITE(copy, &v->coverage, cov);
15483 }
15484
15485 if (i == 0) {
15486 RB_OBJ_WRITE(copy, &cb->parent_iseq, sb->parent_iseq);
15487 result = copy;
15488 }
15489
15490 /* Shared across Ractors through the Proc#refined memo; the duplicated
15491 * subtree is self-contained, so mark each copy shareable. */
15493 }
15494
15495 if (ISEQ_PC2BRANCHINDEX(src_root) != Qnil) {
15496 iseq_subtree_copy_pc2branchindex(dump, load);
15497 }
15498
15499 RB_GC_GUARD(dump_obj);
15500 RB_GC_GUARD(loader_obj);
15501 return result;
15502}
15503
15504VALUE
15505rb_iseq_ibf_load_extra_data(VALUE str)
15506{
15507 struct ibf_load *load;
15508 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15509 VALUE extra_str;
15510
15511 ibf_load_setup(load, loader_obj, str);
15512 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
15513 RB_GC_GUARD(loader_obj);
15514 return extra_str;
15515}
15516
15517#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:1242
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1266
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:517
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:1155
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:2061
#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