Ruby 4.1.0dev (2026-10-06 revision 28da13e768d5a463bec19a874d54d351f41f306f)
compile.c (28da13e768d5a463bec19a874d54d351f41f306f)
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
2627static int
2628add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2629 int insns_info_index, int code_index, const INSN *iobj)
2630{
2631 if (insns_info_index == 0 ||
2632 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2633#ifdef USE_ISEQ_NODE_ID
2634 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2635#endif
2636 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2637 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2638#ifdef USE_ISEQ_NODE_ID
2639 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2640#endif
2641 insns_info[insns_info_index].events = iobj->insn_info.events;
2642 positions[insns_info_index] = code_index;
2643 return TRUE;
2644 }
2645 return FALSE;
2646}
2647
2648static int
2649add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2650 int insns_info_index, int code_index, const ADJUST *adjust)
2651{
2652 insns_info[insns_info_index].line_no = adjust->line_no;
2653 insns_info[insns_info_index].node_id = -1;
2654 insns_info[insns_info_index].events = 0;
2655 positions[insns_info_index] = code_index;
2656 return TRUE;
2657}
2658
2659static ID *
2660array_to_idlist(VALUE arr)
2661{
2663 long size = RARRAY_LEN(arr);
2664 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2665 for (long i = 0; i < size; i++) {
2666 VALUE sym = RARRAY_AREF(arr, i);
2667 ids[i] = SYM2ID(sym);
2668 }
2669 ids[size] = 0;
2670 return ids;
2671}
2672
2673static VALUE
2674idlist_to_array(const ID *ids)
2675{
2676 VALUE arr = rb_ary_new();
2677 while (*ids) {
2678 rb_ary_push(arr, ID2SYM(*ids++));
2679 }
2680 return arr;
2681}
2682
2686static int
2687iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2688{
2689 struct iseq_insn_info_entry *insns_info;
2690 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2691 unsigned int *positions;
2692 LINK_ELEMENT *list;
2693 VALUE *generated_iseq;
2694 rb_event_flag_t events = 0;
2695 long data = 0;
2696
2697 int insn_num, code_index, insns_info_index, sp = 0;
2698 int stack_max = fix_sp_depth(iseq, anchor);
2699
2700 if (stack_max < 0) return COMPILE_NG;
2701
2702 /* fix label position */
2703 insn_num = code_index = 0;
2704 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2705 switch (list->type) {
2706 case ISEQ_ELEMENT_INSN:
2707 {
2708 INSN *iobj = (INSN *)list;
2709 /* update sp */
2710 sp = calc_sp_depth(sp, iobj);
2711 insn_num++;
2712 events = iobj->insn_info.events |= events;
2713 if (ISEQ_COVERAGE(iseq)) {
2714 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2715 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2716 int line = iobj->insn_info.line_no - 1;
2717 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2718 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2719 }
2720 }
2721 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2722 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2723 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2724 }
2725 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2726 }
2727 }
2728 code_index += insn_data_length(iobj);
2729 events = 0;
2730 data = 0;
2731 break;
2732 }
2733 case ISEQ_ELEMENT_LABEL:
2734 {
2735 LABEL *lobj = (LABEL *)list;
2736 lobj->position = code_index;
2737 if (lobj->sp != sp) {
2738 VALUE path = rb_iseq_path(iseq);
2739 debugs("%.*s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2740 RSTRING_LENINT(path), RSTRING_PTR(path),
2741 lobj->label_no, lobj->sp, sp);
2742 }
2743 sp = lobj->sp;
2744 break;
2745 }
2746 case ISEQ_ELEMENT_TRACE:
2747 {
2748 TRACE *trace = (TRACE *)list;
2749 events |= trace->event;
2750 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2751 break;
2752 }
2753 case ISEQ_ELEMENT_ADJUST:
2754 {
2755 ADJUST *adjust = (ADJUST *)list;
2756 if (adjust->line_no != -1) {
2757 int orig_sp = sp;
2758 sp = adjust->label ? adjust->label->sp : 0;
2759 if (orig_sp - sp > 0) {
2760 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2761 code_index++; /* insn */
2762 insn_num++;
2763 }
2764 }
2765 break;
2766 }
2767 default: break;
2768 }
2769 }
2770
2771 /* make instruction sequence */
2772 const int generated_iseq_size = code_index;
2773 generated_iseq = ALLOC_N(VALUE, code_index);
2774
2775 const int insns_info_size = insn_num;
2776 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2777
2778 const int positions_size = insn_num;
2779 positions = ALLOC_N(unsigned int, insn_num);
2780 if (ISEQ_IS_SIZE(body)) {
2781 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2782 }
2783 else {
2784 body->is_entries = NULL;
2785 }
2786
2787 if (body->ci_size) {
2788 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2789 }
2790 else {
2791 body->call_data = NULL;
2792 }
2793 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2794
2795 // Calculate the bitmask buffer size.
2796 // Round the generated_iseq size up to the nearest multiple
2797 // of the number of bits in an unsigned long.
2798
2799 // Allocate enough room for the bitmask list
2800 iseq_bits_t * mark_offset_bits;
2801 int code_size = code_index;
2802
2803 bool needs_bitmap = false;
2804
2805 const size_t mark_offset_bits_size = ISEQ_MBITS_BUFLEN(code_index);
2806 if (mark_offset_bits_size == 1) {
2807 mark_offset_bits = &ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2808 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = true;
2809 }
2810 else {
2811 mark_offset_bits = ZALLOC_N(iseq_bits_t, mark_offset_bits_size);
2812 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = mark_offset_bits;
2813 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = false;
2814 }
2815
2816 ISEQ_COMPILE_DATA(iseq)->iseq_encoded = (void *)generated_iseq;
2817 ISEQ_COMPILE_DATA(iseq)->iseq_size = code_index;
2818
2819 list = FIRST_ELEMENT(anchor);
2820 insns_info_index = code_index = sp = 0;
2821
2822 while (list) {
2823 switch (list->type) {
2824 case ISEQ_ELEMENT_INSN:
2825 {
2826 int j, len, insn;
2827 const char *types;
2828 VALUE *operands;
2829 INSN *iobj = (INSN *)list;
2830
2831 /* update sp */
2832 sp = calc_sp_depth(sp, iobj);
2833 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2834 operands = iobj->operands;
2835 insn = iobj->insn_id;
2836 generated_iseq[code_index] = insn;
2837 types = insn_op_types(insn);
2838 len = insn_len(insn);
2839
2840 for (j = 0; types[j]; j++) {
2841 char type = types[j];
2842
2843 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2844 switch (type) {
2845 case TS_OFFSET:
2846 {
2847 /* label(destination position) */
2848 LABEL *lobj = (LABEL *)operands[j];
2849 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2850 break;
2851 }
2852 case TS_CDHASH:
2853 {
2854 VALUE map = operands[j];
2855 struct cdhash_set_label_struct data;
2856 data.hash = map;
2857 data.pos = code_index;
2858 data.len = len;
2859 st_foreach_with_replace(rb_imemo_cdhash_tbl(map), cdhash_set_label_check_i, cdhash_set_label_replace_i, (VALUE)&data);
2860
2861 generated_iseq[code_index + 1 + j] = map;
2862 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2863 RB_OBJ_WRITTEN(iseq, Qundef, map);
2864 needs_bitmap = true;
2865 break;
2866 }
2867 case TS_LINDEX:
2868 case TS_NUM: /* ulong */
2869 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2870 break;
2871 case TS_ISEQ: /* iseq */
2872 case TS_VALUE: /* VALUE */
2873 {
2874 VALUE v = operands[j];
2875 generated_iseq[code_index + 1 + j] = v;
2876 /* to mark ruby object */
2877 if (!SPECIAL_CONST_P(v)) {
2878 RB_OBJ_WRITTEN(iseq, Qundef, v);
2879 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2880 needs_bitmap = true;
2881 }
2882 break;
2883 }
2884 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2885 case TS_IC: /* inline cache: constants */
2886 {
2887 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2888 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2889 if (UNLIKELY(ic_index >= body->ic_size)) {
2890 BADINSN_DUMP(anchor, &iobj->link, 0);
2891 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2892 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2893 ic_index, ISEQ_IS_SIZE(body));
2894 }
2895
2896 ic->segments = array_to_idlist(operands[j]);
2897
2898 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2899 }
2900 break;
2901 case TS_IVC: /* inline ivar cache */
2902 {
2903 unsigned int ic_index = FIX2UINT(operands[j]);
2904
2905 IVC cache = ((IVC)&body->is_entries[ic_index]);
2906
2907 if (insn == BIN(setinstancevariable)) {
2908 cache->iv_set_name = SYM2ID(operands[j - 1]);
2909 cache->value = IVAR_CACHE_INIT;
2910 }
2911 else {
2912 cache->iv_set_name = 0;
2913 cache->value = rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET);
2914 }
2915 }
2916 case TS_ISE: /* inline storage entry: `once` insn */
2917 case TS_ICVARC: /* inline cvar cache */
2918 {
2919 unsigned int ic_index = FIX2UINT(operands[j]);
2920 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2921 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2922 BADINSN_DUMP(anchor, &iobj->link, 0);
2923 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2924 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2925 ic_index, ISEQ_IS_SIZE(body));
2926 }
2927 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2928
2929 break;
2930 }
2931 case TS_CALLDATA:
2932 {
2933 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2934 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2935 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2936 cd->ci = source_ci;
2937 cd->cc = vm_cc_empty();
2938 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2939 break;
2940 }
2941 case TS_ID: /* ID */
2942 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2943 break;
2944 case TS_FUNCPTR:
2945 generated_iseq[code_index + 1 + j] = operands[j];
2946 break;
2947 case TS_BUILTIN:
2948 generated_iseq[code_index + 1 + j] = operands[j];
2949 break;
2950 default:
2951 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2952 "unknown operand type: %c", type);
2953 return COMPILE_NG;
2954 }
2955 }
2956 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2957 code_index += len;
2958 break;
2959 }
2960 case ISEQ_ELEMENT_LABEL:
2961 {
2962 LABEL *lobj = (LABEL *)list;
2963 if (lobj->sp != sp) {
2964 VALUE path = rb_iseq_path(iseq);
2965 debugs("%.*s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2966 RSTRING_LENINT(path), RSTRING_PTR(path),
2967 lobj->label_no, lobj->sp, sp);
2968 }
2969 sp = lobj->sp;
2970 break;
2971 }
2972 case ISEQ_ELEMENT_ADJUST:
2973 {
2974 ADJUST *adjust = (ADJUST *)list;
2975 int orig_sp = sp;
2976
2977 if (adjust->label) {
2978 sp = adjust->label->sp;
2979 }
2980 else {
2981 sp = 0;
2982 }
2983
2984 if (adjust->line_no != -1) {
2985 const int diff = orig_sp - sp;
2986 if (diff > 0) {
2987 if (insns_info_index == 0) {
2988 COMPILE_ERROR(iseq, adjust->line_no,
2989 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2990 }
2991 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2992 }
2993 if (diff > 1) {
2994 generated_iseq[code_index++] = BIN(adjuststack);
2995 generated_iseq[code_index++] = orig_sp - sp;
2996 }
2997 else if (diff == 1) {
2998 generated_iseq[code_index++] = BIN(pop);
2999 }
3000 else if (diff < 0) {
3001 int label_no = adjust->label ? adjust->label->label_no : -1;
3002 SIZED_FREE_N(generated_iseq, generated_iseq_size);
3003 SIZED_FREE_N(insns_info, insns_info_size);
3004 SIZED_FREE_N(positions, positions_size);
3005 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
3006 SIZED_FREE_N(mark_offset_bits, ISEQ_MBITS_BUFLEN(code_index));
3007 }
3008 debug_list(anchor, list);
3009 COMPILE_ERROR(iseq, adjust->line_no,
3010 "iseq_set_sequence: adjust bug to %d %d < %d",
3011 label_no, orig_sp, sp);
3012 return COMPILE_NG;
3013 }
3014 }
3015 break;
3016 }
3017 default:
3018 /* ignore */
3019 break;
3020 }
3021 list = list->next;
3022 }
3023
3024 body->iseq_encoded = (void *)generated_iseq;
3025 body->iseq_size = code_index;
3026 body->stack_max = stack_max;
3027
3028 if (ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit) {
3029 body->mark_bits.single = ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
3030 }
3031 else {
3032 if (needs_bitmap) {
3033 body->mark_bits.list = mark_offset_bits;
3034 }
3035 else {
3036 body->mark_bits.list = NULL;
3037 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = NULL;
3038 SIZED_FREE_N(mark_offset_bits, mark_offset_bits_size);
3039 }
3040 }
3041
3042 /* get rid of memory leak when REALLOC failed */
3043 body->insns_info.body = insns_info;
3044 body->insns_info.positions_or_succ_index_table.positions = positions;
3045
3046 SIZED_REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index, insns_info_size);
3047 body->insns_info.body = insns_info;
3048 SIZED_REALLOC_N(positions, unsigned int, insns_info_index, positions_size);
3049 body->insns_info.positions_or_succ_index_table.positions = positions;
3050 body->insns_info.size = insns_info_index;
3051
3052 return COMPILE_OK;
3053}
3054
3055static int
3056label_get_position(LABEL *lobj)
3057{
3058 return lobj->position;
3059}
3060
3061static int
3062label_get_sp(LABEL *lobj)
3063{
3064 return lobj->sp;
3065}
3066
3067static int
3068iseq_set_exception_table(rb_iseq_t *iseq)
3069{
3070 const VALUE *tptr, *ptr;
3071 unsigned int tlen, i;
3072 struct iseq_catch_table_entry *entry;
3073
3074 ISEQ_BODY(iseq)->catch_table = NULL;
3075
3076 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
3077 if (NIL_P(catch_table_ary)) return COMPILE_OK;
3078 tlen = (int)RARRAY_LEN(catch_table_ary);
3079 tptr = RARRAY_CONST_PTR(catch_table_ary);
3080
3081 if (tlen > 0) {
3082 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
3083 table->size = tlen;
3084
3085 for (i = 0; i < table->size; i++) {
3086 int pos;
3087 ptr = RARRAY_CONST_PTR(tptr[i]);
3088 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
3089 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
3090 pos = label_get_position((LABEL *)(ptr[1] & ~1));
3091 RUBY_ASSERT(pos >= 0);
3092 entry->start = (unsigned int)pos;
3093 pos = label_get_position((LABEL *)(ptr[2] & ~1));
3094 RUBY_ASSERT(pos >= 0);
3095 entry->end = (unsigned int)pos;
3096 entry->iseq = (rb_iseq_t *)ptr[3];
3097 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
3098
3099 /* stack depth */
3100 if (ptr[4]) {
3101 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
3102 entry->cont = label_get_position(lobj);
3103 entry->sp = label_get_sp(lobj);
3104
3105 /* TODO: Dirty Hack! Fix me */
3106 if (entry->type == CATCH_TYPE_RESCUE ||
3107 entry->type == CATCH_TYPE_BREAK ||
3108 entry->type == CATCH_TYPE_NEXT) {
3109 RUBY_ASSERT(entry->sp > 0);
3110 entry->sp--;
3111 }
3112 }
3113 else {
3114 entry->cont = 0;
3115 }
3116 }
3117 ISEQ_BODY(iseq)->catch_table = table;
3118 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
3119 }
3120
3121 RB_GC_GUARD(catch_table_ary);
3122
3123 return COMPILE_OK;
3124}
3125
3126/*
3127 * set optional argument table
3128 * def foo(a, b=expr1, c=expr2)
3129 * =>
3130 * b:
3131 * expr1
3132 * c:
3133 * expr2
3134 */
3135static int
3136iseq_set_optargs_table(rb_iseq_t *iseq)
3137{
3138 int i;
3139 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
3140
3141 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
3142 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
3143 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
3144 }
3145 }
3146 return COMPILE_OK;
3147}
3148
3149static LINK_ELEMENT *
3150get_destination_insn(INSN *iobj)
3151{
3152 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
3153 LINK_ELEMENT *list;
3154 rb_event_flag_t events = 0;
3155
3156 list = lobj->link.next;
3157 while (list) {
3158 switch (list->type) {
3159 case ISEQ_ELEMENT_INSN:
3160 case ISEQ_ELEMENT_ADJUST:
3161 goto found;
3162 case ISEQ_ELEMENT_LABEL:
3163 /* ignore */
3164 break;
3165 case ISEQ_ELEMENT_TRACE:
3166 {
3167 TRACE *trace = (TRACE *)list;
3168 events |= trace->event;
3169 }
3170 break;
3171 default: break;
3172 }
3173 list = list->next;
3174 }
3175 found:
3176 if (list && IS_INSN(list)) {
3177 INSN *iobj = (INSN *)list;
3178 iobj->insn_info.events |= events;
3179 }
3180 return list;
3181}
3182
3183static LINK_ELEMENT *
3184get_next_insn(INSN *iobj)
3185{
3186 LINK_ELEMENT *list = iobj->link.next;
3187
3188 while (list) {
3189 if (IS_INSN(list) || IS_ADJUST(list)) {
3190 return list;
3191 }
3192 list = list->next;
3193 }
3194 return 0;
3195}
3196
3197static LINK_ELEMENT *
3198get_prev_insn(INSN *iobj)
3199{
3200 LINK_ELEMENT *list = iobj->link.prev;
3201
3202 while (list) {
3203 if (IS_INSN(list) || IS_ADJUST(list)) {
3204 return list;
3205 }
3206 list = list->prev;
3207 }
3208 return 0;
3209}
3210
3211static void
3212unref_destination(INSN *iobj, int pos)
3213{
3214 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3215 --lobj->refcnt;
3216 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3217}
3218
3219static bool
3220replace_destination(INSN *dobj, INSN *nobj)
3221{
3222 VALUE n = OPERAND_AT(nobj, 0);
3223 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3224 LABEL *nl = (LABEL *)n;
3225 if (dl == nl) return false;
3226 --dl->refcnt;
3227 ++nl->refcnt;
3228 OPERAND_AT(dobj, 0) = n;
3229 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3230 return true;
3231}
3232
3233static LABEL*
3234find_destination(INSN *i)
3235{
3236 int pos, len = insn_len(i->insn_id);
3237 for (pos = 0; pos < len; ++pos) {
3238 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3239 return (LABEL *)OPERAND_AT(i, pos);
3240 }
3241 }
3242 return 0;
3243}
3244
3246 const unsigned int capacity;
3247 unsigned int gen;
3248 int *counts;
3249 unsigned int *stamps;
3250};
3251
3252static int
3253unreachable_unref_count(const struct unreachable_unref *unref, const LABEL *lab)
3254{
3255 unsigned int no = (unsigned int)lab->label_no;
3256 return unref->stamps[no] == unref->gen ? unref->counts[no] : 0;
3257}
3258
3259static void
3260unreachable_unref_increment(const struct unreachable_unref *unref, const LABEL *lab)
3261{
3262 unsigned int no = (unsigned int)lab->label_no;
3263 if (unref->stamps[no] != unref->gen) {
3264 unref->stamps[no] = unref->gen;
3265 unref->counts[no] = 0;
3266 }
3267 unref->counts[no]++;
3268}
3269
3270static int
3271remove_unreachable_chunk(rb_iseq_t *iseq, struct unreachable_unref *unref, LINK_ELEMENT *i)
3272{
3273 LINK_ELEMENT *first = i, *end, *scan, *pending_end = 0;
3274 LABEL *pending = 0;
3275
3276 if (!i) return 0;
3277 if (++unref->gen == 0) {
3278 /* The stamp wrapped around, so every stale stamp became ambiguous. */
3279 MEMZERO(unref->stamps, unsigned int, unref->capacity);
3280 unref->gen = 1;
3281 }
3282
3283 end = i;
3284 scan = i;
3285 do {
3286 LABEL *lab;
3287 if (IS_INSN(scan)) {
3288 if (IS_INSN_ID(scan, leave)) {
3289 if (pending) break;
3290 end = scan;
3291 break;
3292 }
3293 else if ((lab = find_destination((INSN *)scan)) != 0) {
3294 unreachable_unref_increment(unref, lab);
3295 if (lab == pending && lab->refcnt <= unreachable_unref_count(unref, lab)) {
3296 pending = 0;
3297 }
3298 }
3299 }
3300 else if (IS_LABEL(scan)) {
3301 lab = (LABEL *)scan;
3302 if (lab->unremovable) {
3303 if (pending) break;
3304 return 0;
3305 }
3306 if (lab->refcnt > unreachable_unref_count(unref, lab)) {
3307 if (pending) break;
3308 pending = lab;
3309 pending_end = (scan == first) ? 0 : end;
3310 }
3311 continue;
3312 }
3313 else if (IS_ADJUST(scan)) {
3314 if (pending) break;
3315 return 0;
3316 }
3317 if (!pending) end = scan;
3318 } while ((scan = scan->next) != 0);
3319
3320 if (pending) {
3321 if (!pending_end) return 0;
3322 end = pending_end;
3323 }
3324 i = first;
3325 do {
3326 if (IS_INSN(i)) {
3327 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3328 VALUE insn = INSN_OF(i);
3329 int pos, len = insn_len(insn);
3330 for (pos = 0; pos < len; ++pos) {
3331 switch (insn_op_types(insn)[pos]) {
3332 case TS_OFFSET:
3333 unref_destination((INSN *)i, pos);
3334 break;
3335 case TS_CALLDATA:
3336 --(body->ci_size);
3337 break;
3338 }
3339 }
3340 }
3341 ELEM_REMOVE(i);
3342 } while ((i != end) && (i = i->next) != 0);
3343 return 1;
3344}
3345
3346static int
3347iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3348{
3349 switch (OPERAND_AT(iobj, 0)) {
3350 case INT2FIX(0): /* empty array */
3351 ELEM_REMOVE(&iobj->link);
3352 return TRUE;
3353 case INT2FIX(1): /* single element array */
3354 ELEM_REMOVE(&iobj->link);
3355 return FALSE;
3356 default:
3357 iobj->insn_id = BIN(adjuststack);
3358 return TRUE;
3359 }
3360}
3361
3362static int
3363is_frozen_putstring(INSN *insn, VALUE *op)
3364{
3365 if (IS_INSN_ID(insn, dupstring) || IS_INSN_ID(insn, dupchilledstring)) {
3366 *op = OPERAND_AT(insn, 0);
3367 return 1;
3368 }
3369 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3370 *op = OPERAND_AT(insn, 0);
3371 return RB_TYPE_P(*op, T_STRING);
3372 }
3373 return 0;
3374}
3375
3376static int
3377insn_has_label_before(LINK_ELEMENT *elem)
3378{
3379 LINK_ELEMENT *prev = elem->prev;
3380 while (prev) {
3381 if (prev->type == ISEQ_ELEMENT_LABEL) {
3382 LABEL *label = (LABEL *)prev;
3383 if (label->refcnt > 0) {
3384 return 1;
3385 }
3386 }
3387 else if (prev->type == ISEQ_ELEMENT_INSN) {
3388 break;
3389 }
3390 prev = prev->prev;
3391 }
3392 return 0;
3393}
3394
3395static int
3396optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3397{
3398 /*
3399 * putobject obj
3400 * dup
3401 * checktype T_XXX
3402 * branchif l1
3403 * l2:
3404 * ...
3405 * l1:
3406 *
3407 * => obj is a T_XXX
3408 *
3409 * putobject obj (T_XXX)
3410 * jump L1
3411 * L1:
3412 *
3413 * => obj is not a T_XXX
3414 *
3415 * putobject obj (T_XXX)
3416 * jump L2
3417 * L2:
3418 */
3419 int line, node_id;
3420 INSN *niobj, *ciobj, *dup = 0;
3421 LABEL *dest = 0;
3422 VALUE type;
3423
3424 switch (INSN_OF(iobj)) {
3425 case BIN(dupstring):
3426 case BIN(dupchilledstring):
3428 break;
3429 case BIN(putnil):
3430 type = INT2FIX(T_NIL);
3431 break;
3432 case BIN(putobject):
3433 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3434 break;
3435 default: return FALSE;
3436 }
3437
3438 ciobj = (INSN *)get_next_insn(iobj);
3439 if (IS_INSN_ID(ciobj, jump)) {
3440 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3441 }
3442 if (IS_INSN_ID(ciobj, dup)) {
3443 ciobj = (INSN *)get_next_insn(dup = ciobj);
3444 }
3445 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3446 niobj = (INSN *)get_next_insn(ciobj);
3447 if (!niobj) {
3448 /* TODO: putobject true/false */
3449 return FALSE;
3450 }
3451 switch (INSN_OF(niobj)) {
3452 case BIN(branchif):
3453 if (OPERAND_AT(ciobj, 0) == type) {
3454 dest = (LABEL *)OPERAND_AT(niobj, 0);
3455 }
3456 break;
3457 case BIN(branchunless):
3458 if (OPERAND_AT(ciobj, 0) != type) {
3459 dest = (LABEL *)OPERAND_AT(niobj, 0);
3460 }
3461 break;
3462 default:
3463 return FALSE;
3464 }
3465 line = ciobj->insn_info.line_no;
3466 node_id = ciobj->insn_info.node_id;
3467 if (!dest) {
3468 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3469 dest = (LABEL *)niobj->link.next; /* reuse label */
3470 }
3471 else {
3472 dest = NEW_LABEL(line);
3473 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3474 }
3475 }
3476 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3477 LABEL_REF(dest);
3478 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3479 return TRUE;
3480}
3481
3482static const struct rb_callinfo *
3483ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3484{
3485 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3486 vm_ci_flag(ci) | add,
3487 vm_ci_argc(ci),
3488 vm_ci_kwarg(ci));
3489 RB_OBJ_WRITTEN(iseq, ci, nci);
3490 return nci;
3491}
3492
3493static const struct rb_callinfo *
3494ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3495{
3496 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3497 vm_ci_flag(ci),
3498 argc,
3499 vm_ci_kwarg(ci));
3500 RB_OBJ_WRITTEN(iseq, ci, nci);
3501 return nci;
3502}
3503
3504#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3505
3506static VALUE
3507iseq_reg_compile(rb_iseq_t *iseq, VALUE str, int options, const char *sourcefile, int sourceline)
3508{
3509 VALUE errinfo = rb_errinfo();
3510 VALUE re = rb_reg_compile(str, options, sourcefile, sourceline);
3511 if (NIL_P(re)) {
3512 VALUE message = rb_attr_get(rb_errinfo(), idMesg);
3513 rb_set_errinfo(errinfo);
3514 COMPILE_ERROR(iseq, sourceline, "%" PRIsVALUE, message);
3515 }
3516 else {
3518 }
3519 return re;
3520}
3521
3522static int
3523iseq_peephole_optimize(rb_iseq_t *iseq, struct unreachable_unref *unref, LINK_ELEMENT *list, const int do_tailcallopt)
3524{
3525 INSN *const iobj = (INSN *)list;
3526
3527 again:
3528 optimize_checktype(iseq, iobj);
3529
3530 if (IS_INSN_ID(iobj, jump)) {
3531 INSN *niobj, *diobj, *piobj;
3532 diobj = (INSN *)get_destination_insn(iobj);
3533 niobj = (INSN *)get_next_insn(iobj);
3534
3535 if (diobj == niobj) {
3536 /*
3537 * jump LABEL
3538 * LABEL:
3539 * =>
3540 * LABEL:
3541 */
3542 unref_destination(iobj, 0);
3543 ELEM_REMOVE(&iobj->link);
3544 return COMPILE_OK;
3545 }
3546 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3547 IS_INSN_ID(diobj, jump) &&
3548 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3549 diobj->insn_info.events == 0) {
3550 /*
3551 * useless jump elimination:
3552 * jump LABEL1
3553 * ...
3554 * LABEL1:
3555 * jump LABEL2
3556 *
3557 * => in this case, first jump instruction should jump to
3558 * LABEL2 directly
3559 */
3560 if (replace_destination(iobj, diobj)) {
3561 remove_unreachable_chunk(iseq, unref, iobj->link.next);
3562 goto again;
3563 }
3564 }
3565 else if (IS_INSN_ID(diobj, leave)) {
3566 /*
3567 * jump LABEL
3568 * ...
3569 * LABEL:
3570 * leave
3571 * =>
3572 * leave
3573 * ...
3574 * LABEL:
3575 * leave
3576 */
3577 /* replace */
3578 unref_destination(iobj, 0);
3579 iobj->insn_id = BIN(leave);
3580 iobj->operand_size = 0;
3581 iobj->insn_info = diobj->insn_info;
3582 goto again;
3583 }
3584 else if (IS_INSN(iobj->link.prev) &&
3585 (piobj = (INSN *)iobj->link.prev) &&
3586 (IS_INSN_ID(piobj, branchif) ||
3587 IS_INSN_ID(piobj, branchunless))) {
3588 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3589 if (niobj == pdiobj) {
3590 int refcnt = IS_LABEL(piobj->link.next) ?
3591 ((LABEL *)piobj->link.next)->refcnt : 0;
3592 /*
3593 * useless jump elimination (if/unless destination):
3594 * if L1
3595 * jump L2
3596 * L1:
3597 * ...
3598 * L2:
3599 *
3600 * ==>
3601 * unless L2
3602 * L1:
3603 * ...
3604 * L2:
3605 */
3606 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3607 ? BIN(branchunless) : BIN(branchif);
3608 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3609 ELEM_REMOVE(&iobj->link);
3610 }
3611 else {
3612 /* TODO: replace other branch destinations too */
3613 }
3614 return COMPILE_OK;
3615 }
3616 else if (diobj == pdiobj) {
3617 /*
3618 * useless jump elimination (if/unless before jump):
3619 * L1:
3620 * ...
3621 * if L1
3622 * jump L1
3623 *
3624 * ==>
3625 * L1:
3626 * ...
3627 * pop
3628 * jump L1
3629 */
3630 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3631 ELEM_REPLACE(&piobj->link, &popiobj->link);
3632 }
3633 }
3634 if (remove_unreachable_chunk(iseq, unref, iobj->link.next)) {
3635 goto again;
3636 }
3637 }
3638
3639 /*
3640 * dupstring "beg"
3641 * dupstring "end"
3642 * newrange excl
3643 *
3644 * ==>
3645 *
3646 * putobject "beg".."end"
3647 */
3648 if (IS_INSN_ID(iobj, newrange)) {
3649 INSN *const range = iobj;
3650 INSN *beg, *end;
3651 VALUE str_beg, str_end;
3652
3653 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3654 is_frozen_putstring(end, &str_end) &&
3655 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3656 is_frozen_putstring(beg, &str_beg) &&
3657 !(insn_has_label_before(&beg->link) || insn_has_label_before(&end->link))) {
3658 int excl = FIX2INT(OPERAND_AT(range, 0));
3659 VALUE lit_range = RB_OBJ_SET_SHAREABLE(rb_range_new(str_beg, str_end, excl));
3660
3661 ELEM_REMOVE(&beg->link);
3662 ELEM_REMOVE(&end->link);
3663 range->insn_id = BIN(putobject);
3664 OPERAND_AT(range, 0) = lit_range;
3665 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3666 }
3667 }
3668
3669 if (IS_INSN_ID(iobj, leave)) {
3670 remove_unreachable_chunk(iseq, unref, iobj->link.next);
3671 }
3672
3673 /*
3674 * ...
3675 * duparray [...]
3676 * concatarray | concattoarray
3677 * =>
3678 * ...
3679 * putobject [...]
3680 * concatarray | concattoarray
3681 */
3682 if (IS_INSN_ID(iobj, duparray)) {
3683 LINK_ELEMENT *next = iobj->link.next;
3684 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3685 iobj->insn_id = BIN(putobject);
3686 }
3687 }
3688
3689 /*
3690 * duparray [...]
3691 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3692 * =>
3693 * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3694 */
3695 if (IS_INSN_ID(iobj, duparray)) {
3696 LINK_ELEMENT *next = iobj->link.next;
3697 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3698 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3699 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3700
3701 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3702 VALUE ary = iobj->operands[0];
3704
3705 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, ary, (VALUE)ci);
3706 ELEM_REMOVE(next);
3707 }
3708 }
3709 }
3710
3711 /*
3712 * duphash {...}
3713 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3714 * =>
3715 * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3716 */
3717 if (IS_INSN_ID(iobj, duphash)) {
3718 LINK_ELEMENT *next = iobj->link.next;
3719 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3720 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3721 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3722
3723 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3724 VALUE hash = iobj->operands[0];
3725 rb_obj_reveal(hash, rb_cHash);
3727
3728 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, hash, (VALUE)ci);
3729 ELEM_REMOVE(next);
3730 }
3731 }
3732 }
3733
3734 /*
3735 * newarray 0
3736 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3737 * =>
3738 * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3739 */
3740 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3741 LINK_ELEMENT *next = iobj->link.next;
3742 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3743 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3744 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3745
3746 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3747 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, rb_cArray_empty_frozen, (VALUE)ci);
3748 ELEM_REMOVE(next);
3749 }
3750 }
3751 }
3752
3753 /*
3754 * newhash 0
3755 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3756 * =>
3757 * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3758 */
3759 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3760 LINK_ELEMENT *next = iobj->link.next;
3761 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3762 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3763 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3764
3765 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3766 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, rb_cHash_empty_frozen, (VALUE)ci);
3767 ELEM_REMOVE(next);
3768 }
3769 }
3770 }
3771
3772 if (IS_INSN_ID(iobj, branchif) ||
3773 IS_INSN_ID(iobj, branchnil) ||
3774 IS_INSN_ID(iobj, branchunless)) {
3775 /*
3776 * if L1
3777 * ...
3778 * L1:
3779 * jump L2
3780 * =>
3781 * if L2
3782 */
3783 INSN *nobj = (INSN *)get_destination_insn(iobj);
3784
3785 /* This jump-jump optimization may ignore line events on the jump
3786 * instruction being skipped. For example, the Line 2 TracePoint
3787 * event would otherwise never fire in the following code:
3788 *
3789 * 1: raise if 1 == 2
3790 * 2: while true
3791 * 3: break
3792 * 4: end
3793 *
3794 * Do not skip a jump that carries a line event. This applies even
3795 * when coverage is disabled because TracePoint consumes the same
3796 * event. [Bug #15980]
3797 */
3798 int stop_optimization =
3799 nobj->link.type == ISEQ_ELEMENT_INSN &&
3800 (nobj->insn_info.events & (RUBY_EVENT_LINE | RUBY_EVENT_COVERAGE_LINE));
3801 if (!stop_optimization) {
3802 INSN *pobj = (INSN *)iobj->link.prev;
3803 int prev_dup = 0;
3804 if (pobj) {
3805 if (!IS_INSN(&pobj->link))
3806 pobj = 0;
3807 else if (IS_INSN_ID(pobj, dup))
3808 prev_dup = 1;
3809 }
3810
3811 for (;;) {
3812 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3813 if (!replace_destination(iobj, nobj)) break;
3814 }
3815 else if (prev_dup && IS_INSN(&nobj->link) && IS_INSN_ID(nobj, dup) &&
3816 !!(nobj = (INSN *)nobj->link.next) &&
3817 IS_INSN(&nobj->link) &&
3818 /* basic blocks, with no labels in the middle */
3819 nobj->insn_id == iobj->insn_id) {
3820 /*
3821 * dup
3822 * if L1
3823 * ...
3824 * L1:
3825 * dup
3826 * if L2
3827 * =>
3828 * dup
3829 * if L2
3830 * ...
3831 * L1:
3832 * dup
3833 * if L2
3834 */
3835 if (!replace_destination(iobj, nobj)) break;
3836 }
3837 else if (pobj) {
3838 /*
3839 * putnil
3840 * if L1
3841 * =>
3842 * # nothing
3843 *
3844 * putobject true
3845 * if L1
3846 * =>
3847 * jump L1
3848 *
3849 * dupstring ".."
3850 * if L1
3851 * =>
3852 * jump L1
3853 *
3854 * dupstring ".."
3855 * dup
3856 * if L1
3857 * =>
3858 * dupstring ".."
3859 * jump L1
3860 *
3861 */
3862 int cond;
3863 if (prev_dup && IS_INSN(pobj->link.prev)) {
3864 pobj = (INSN *)pobj->link.prev;
3865 }
3866 if (IS_INSN_ID(pobj, putobject)) {
3867 cond = (IS_INSN_ID(iobj, branchif) ?
3868 OPERAND_AT(pobj, 0) != Qfalse :
3869 IS_INSN_ID(iobj, branchunless) ?
3870 OPERAND_AT(pobj, 0) == Qfalse :
3871 FALSE);
3872 }
3873 else if (IS_INSN_ID(pobj, dupstring) ||
3874 IS_INSN_ID(pobj, duparray) ||
3875 IS_INSN_ID(pobj, newarray)) {
3876 cond = IS_INSN_ID(iobj, branchif);
3877 }
3878 else if (IS_INSN_ID(pobj, putnil)) {
3879 cond = !IS_INSN_ID(iobj, branchif);
3880 }
3881 else break;
3882 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3883 ELEM_REMOVE(iobj->link.prev);
3884 }
3885 else if (!iseq_pop_newarray(iseq, pobj)) {
3886 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3887 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3888 }
3889 if (cond) {
3890 if (prev_dup) {
3891 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3892 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3893 }
3894 iobj->insn_id = BIN(jump);
3895 goto again;
3896 }
3897 else {
3898 unref_destination(iobj, 0);
3899 ELEM_REMOVE(&iobj->link);
3900 }
3901 break;
3902 }
3903 else break;
3904 {
3905 LINK_ELEMENT *dest = get_destination_insn(nobj);
3906 if (!dest || !IS_INSN(dest)) break;
3907 nobj = (INSN *)dest;
3908 }
3909 }
3910 }
3911 }
3912
3913 if (IS_INSN_ID(iobj, pop)) {
3914 /*
3915 * putself / putnil / putobject obj / dupstring "..."
3916 * pop
3917 * =>
3918 * # do nothing
3919 */
3920 LINK_ELEMENT *prev = iobj->link.prev;
3921 if (IS_INSN(prev)) {
3922 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3923 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3924 previ == BIN(putself) || previ == BIN(dupstring) ||
3925 previ == BIN(dupchilledstring) ||
3926 previ == BIN(dup) ||
3927 previ == BIN(getlocal) ||
3928 previ == BIN(getblockparam) ||
3929 previ == BIN(getblockparamproxy) ||
3930 previ == BIN(getinstancevariable) ||
3931 previ == BIN(duparray)) {
3932 /* just push operand or static value and pop soon, no
3933 * side effects */
3934 ELEM_REMOVE(prev);
3935 ELEM_REMOVE(&iobj->link);
3936 }
3937 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3938 ELEM_REMOVE(&iobj->link);
3939 }
3940 else if (previ == BIN(concatarray)) {
3941 INSN *piobj = (INSN *)prev;
3942 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3943 INSN_OF(piobj) = BIN(pop);
3944 }
3945 else if (previ == BIN(concatstrings)) {
3946 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3947 ELEM_REMOVE(prev);
3948 }
3949 else {
3950 ELEM_REMOVE(&iobj->link);
3951 INSN_OF(prev) = BIN(adjuststack);
3952 }
3953 }
3954 }
3955 }
3956
3957 if (IS_INSN_ID(iobj, newarray) ||
3958 IS_INSN_ID(iobj, duparray) ||
3959 IS_INSN_ID(iobj, concatarray) ||
3960 IS_INSN_ID(iobj, splatarray) ||
3961 0) {
3962 /*
3963 * newarray N
3964 * splatarray
3965 * =>
3966 * newarray N
3967 * newarray always puts an array
3968 */
3969 LINK_ELEMENT *next = iobj->link.next;
3970 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3971 /* remove splatarray following always-array insn */
3972 ELEM_REMOVE(next);
3973 }
3974 }
3975
3976 if (IS_INSN_ID(iobj, newarray)) {
3977 LINK_ELEMENT *next = iobj->link.next;
3978 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3979 OPERAND_AT(next, 1) == INT2FIX(0)) {
3980 VALUE op1, op2;
3981 op1 = OPERAND_AT(iobj, 0);
3982 op2 = OPERAND_AT(next, 0);
3983 ELEM_REMOVE(next);
3984
3985 if (op1 == op2) {
3986 /*
3987 * newarray 2
3988 * expandarray 2, 0
3989 * =>
3990 * swap
3991 */
3992 if (op1 == INT2FIX(2)) {
3993 INSN_OF(iobj) = BIN(swap);
3994 iobj->operand_size = 0;
3995 }
3996 /*
3997 * newarray X
3998 * expandarray X, 0
3999 * =>
4000 * opt_reverse X
4001 */
4002 else {
4003 INSN_OF(iobj) = BIN(opt_reverse);
4004 }
4005 }
4006 else {
4007 long diff = FIX2LONG(op1) - FIX2LONG(op2);
4008 INSN_OF(iobj) = BIN(opt_reverse);
4009 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
4010
4011 if (op1 > op2) {
4012 /* X > Y
4013 * newarray X
4014 * expandarray Y, 0
4015 * =>
4016 * pop * (Y-X)
4017 * opt_reverse Y
4018 */
4019 for (; diff > 0; diff--) {
4020 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
4021 }
4022 }
4023 else { /* (op1 < op2) */
4024 /* X < Y
4025 * newarray X
4026 * expandarray Y, 0
4027 * =>
4028 * putnil * (Y-X)
4029 * opt_reverse Y
4030 */
4031 for (; diff < 0; diff++) {
4032 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
4033 }
4034 }
4035 }
4036 }
4037 }
4038
4039 if (IS_INSN_ID(iobj, duparray)) {
4040 LINK_ELEMENT *next = iobj->link.next;
4041 /*
4042 * duparray obj
4043 * expandarray X, 0
4044 * =>
4045 * putobject obj
4046 * expandarray X, 0
4047 */
4048 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
4049 INSN_OF(iobj) = BIN(putobject);
4050 }
4051 }
4052
4053 if (IS_INSN_ID(iobj, anytostring)) {
4054 LINK_ELEMENT *next = iobj->link.next;
4055 /*
4056 * anytostring
4057 * concatstrings 1
4058 * =>
4059 * anytostring
4060 */
4061 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
4062 OPERAND_AT(next, 0) == INT2FIX(1)) {
4063 ELEM_REMOVE(next);
4064 }
4065 }
4066
4067 if (IS_INSN_ID(iobj, dupstring) || IS_INSN_ID(iobj, dupchilledstring) ||
4068 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
4069 /*
4070 * dupstring ""
4071 * concatstrings N
4072 * =>
4073 * concatstrings N-1
4074 */
4075 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
4076 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
4077 INSN *next = (INSN *)iobj->link.next;
4078 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
4079 ELEM_REMOVE(&next->link);
4080 }
4081 ELEM_REMOVE(&iobj->link);
4082 }
4083 if (IS_NEXT_INSN_ID(&iobj->link, toregexp)) {
4084 INSN *next = (INSN *)iobj->link.next;
4085 if (OPERAND_AT(next, 1) == INT2FIX(1)) {
4086 VALUE src = OPERAND_AT(iobj, 0);
4087 int opt = (int)FIX2LONG(OPERAND_AT(next, 0));
4088 VALUE path = rb_iseq_path(iseq);
4089 int line = iobj->insn_info.line_no;
4090 VALUE re = iseq_reg_compile(iseq, src, opt, RSTRING_PTR(path), line);
4091 /* The folded operand is a Regexp, so the instruction must be
4092 * putobject: dupstring/dupchilledstring would resurrect the
4093 * Regexp as a String at run time (e.g. for a /o regexp whose
4094 * interpolation folds to a constant, such as /#{"a"}/o). */
4095 iobj->insn_id = BIN(putobject);
4096 RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
4097 ELEM_REMOVE(iobj->link.next);
4098 }
4099 }
4100 }
4101
4102 if (IS_INSN_ID(iobj, concatstrings)) {
4103 /*
4104 * concatstrings N
4105 * concatstrings M
4106 * =>
4107 * concatstrings N+M-1
4108 */
4109 LINK_ELEMENT *next = iobj->link.next;
4110 INSN *jump = 0;
4111 if (IS_INSN(next) && IS_INSN_ID(next, jump))
4112 next = get_destination_insn(jump = (INSN *)next);
4113 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
4114 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
4115 OPERAND_AT(iobj, 0) = INT2FIX(n);
4116 if (jump) {
4117 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
4118 if (!--label->refcnt) {
4119 ELEM_REMOVE(&label->link);
4120 }
4121 else {
4122 label = NEW_LABEL(0);
4123 OPERAND_AT(jump, 0) = (VALUE)label;
4124 }
4125 label->refcnt++;
4126 ELEM_INSERT_NEXT(next, &label->link);
4127 CHECK(iseq_peephole_optimize(iseq, unref, get_next_insn(jump), do_tailcallopt));
4128 }
4129 else {
4130 ELEM_REMOVE(next);
4131 }
4132 }
4133 }
4134
4135 if (do_tailcallopt &&
4136 (IS_INSN_ID(iobj, send) ||
4137 IS_INSN_ID(iobj, invokesuper))) {
4138 /*
4139 * send ...
4140 * leave
4141 * =>
4142 * send ..., ... | VM_CALL_TAILCALL, ...
4143 * leave # unreachable
4144 */
4145 INSN *piobj = NULL;
4146 if (iobj->link.next) {
4147 LINK_ELEMENT *next = iobj->link.next;
4148 do {
4149 if (!IS_INSN(next)) {
4150 next = next->next;
4151 continue;
4152 }
4153 switch (INSN_OF(next)) {
4154 case BIN(nop):
4155 next = next->next;
4156 break;
4157 case BIN(jump):
4158 /* if cond
4159 * return tailcall
4160 * end
4161 */
4162 next = get_destination_insn((INSN *)next);
4163 break;
4164 case BIN(leave):
4165 piobj = iobj;
4166 /* fall through */
4167 default:
4168 next = NULL;
4169 break;
4170 }
4171 } while (next);
4172 }
4173
4174 if (piobj) {
4175 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
4176 if (IS_INSN_ID(piobj, send) ||
4177 IS_INSN_ID(piobj, invokesuper)) {
4178 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
4179 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4180 OPERAND_AT(piobj, 0) = (VALUE)ci;
4181 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4182 }
4183 }
4184 else {
4185 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4186 OPERAND_AT(piobj, 0) = (VALUE)ci;
4187 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4188 }
4189 }
4190 }
4191
4192 if (IS_INSN_ID(iobj, dup)) {
4193 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
4194 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
4195
4196 /*
4197 * dup
4198 * setlocal x, y
4199 * setlocal x, y
4200 * =>
4201 * dup
4202 * setlocal x, y
4203 */
4204 if (IS_NEXT_INSN_ID(set1, setlocal)) {
4205 set2 = set1->next;
4206 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4207 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4208 ELEM_REMOVE(set1);
4209 ELEM_REMOVE(&iobj->link);
4210 }
4211 }
4212
4213 /*
4214 * dup
4215 * setlocal x, y
4216 * dup
4217 * setlocal x, y
4218 * =>
4219 * dup
4220 * setlocal x, y
4221 */
4222 else if (IS_NEXT_INSN_ID(set1, dup) &&
4223 IS_NEXT_INSN_ID(set1->next, setlocal)) {
4224 set2 = set1->next->next;
4225 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4226 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4227 ELEM_REMOVE(set1->next);
4228 ELEM_REMOVE(set2);
4229 }
4230 }
4231 }
4232 }
4233
4234 /*
4235 * getlocal x, y
4236 * dup
4237 * setlocal x, y
4238 * =>
4239 * dup
4240 */
4241 if (IS_INSN_ID(iobj, getlocal)) {
4242 LINK_ELEMENT *niobj = &iobj->link;
4243 if (IS_NEXT_INSN_ID(niobj, dup)) {
4244 niobj = niobj->next;
4245 }
4246 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
4247 LINK_ELEMENT *set1 = niobj->next;
4248 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
4249 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
4250 ELEM_REMOVE(set1);
4251 ELEM_REMOVE(niobj);
4252 }
4253 }
4254 }
4255
4256 /*
4257 * opt_invokebuiltin_delegate
4258 * trace
4259 * leave
4260 * =>
4261 * opt_invokebuiltin_delegate_leave
4262 * trace
4263 * leave
4264 */
4265 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4266 if (IS_TRACE(iobj->link.next)) {
4267 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4268 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4269 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
4270 if (iobj == (INSN *)list && bf->argc == 0 && (ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4271 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4272 }
4273 }
4274 }
4275 }
4276
4277 /*
4278 * getblockparam
4279 * branchif / branchunless
4280 * =>
4281 * getblockparamproxy
4282 * branchif / branchunless
4283 */
4284 if (IS_INSN_ID(iobj, getblockparam)) {
4285 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4286 iobj->insn_id = BIN(getblockparamproxy);
4287 }
4288 }
4289
4290 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4291 LINK_ELEMENT *niobj = &iobj->link;
4292 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4293 niobj = niobj->next;
4294 LINK_ELEMENT *siobj;
4295 unsigned int set_flags = 0, unset_flags = 0;
4296
4297 /*
4298 * Eliminate hash allocation for f(*a, kw: 1)
4299 *
4300 * splatarray false
4301 * duphash
4302 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4303 * =>
4304 * splatarray false
4305 * putobject
4306 * send ARGS_SPLAT|KW_SPLAT
4307 */
4308 if (IS_NEXT_INSN_ID(niobj, send)) {
4309 siobj = niobj->next;
4310 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4311 unset_flags = VM_CALL_ARGS_BLOCKARG;
4312 }
4313 /*
4314 * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4315 *
4316 * splatarray false
4317 * duphash
4318 * getlocal / getinstancevariable / getblockparamproxy
4319 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4320 * =>
4321 * splatarray false
4322 * putobject
4323 * getlocal / getinstancevariable / getblockparamproxy
4324 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4325 */
4326 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4327 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4328 siobj = niobj->next->next;
4329 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4330 }
4331
4332 if (set_flags) {
4333 const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4334 unsigned int flags = vm_ci_flag(ci);
4335 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4336 ((INSN*)niobj)->insn_id = BIN(putobject);
4337 RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), RB_OBJ_SET_SHAREABLE(rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)))));
4338
4339 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4340 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4341 RB_OBJ_WRITTEN(iseq, ci, nci);
4342 OPERAND_AT(siobj, 0) = (VALUE)nci;
4343 }
4344 }
4345 }
4346 }
4347
4348 /*
4349 * putself / (or any other independent instruction)
4350 * putnil / (or any other independent instruction)
4351 * swap
4352 * =>
4353 * putnil / (or any other independent instruction)
4354 * putself / (or any other independent instruction)
4355 */
4356 if (IS_NEXT_INSN_ID(&iobj->link, swap)) {
4357 LINK_ELEMENT *second = &iobj->link;
4358 LINK_ELEMENT *first = second->prev;
4359 LINK_ELEMENT *swap = second->next;
4360
4361 if (IS_INDEPENDENT_INSN(first) && IS_INDEPENDENT_INSN(second)) {
4362 ELEM_REMOVE(swap);
4363 ELEM_SWAP(first, second);
4364 }
4365 }
4366
4367 return COMPILE_OK;
4368}
4369
4370static int
4371insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4372{
4373 if (insn_id == BIN(opt_neq)) {
4374 VALUE original_ci = iobj->operands[0];
4375 VALUE new_ci = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4376 insn_replace_with_operands(iseq, iobj, insn_id, 2, new_ci, original_ci);
4377 }
4378 else {
4379 iobj->insn_id = insn_id;
4380 iobj->operand_size = insn_len(insn_id) - 1;
4381 }
4382 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4383
4384 return COMPILE_OK;
4385}
4386
4387static int
4388iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4389{
4390 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4391 IS_INSN(iobj->link.next)) {
4392 /*
4393 * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4394 */
4395 INSN *niobj = (INSN *)iobj->link.next;
4396 if (IS_INSN_ID(niobj, send)) {
4397 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4398 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4399 VALUE method = INT2FIX(0);
4400 switch (vm_ci_mid(ci)) {
4401 case idMax:
4402 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4403 break;
4404 case idMin:
4405 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4406 break;
4407 case idHash:
4408 method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4409 break;
4410 }
4411
4412 if (method != INT2FIX(0)) {
4413 VALUE num = iobj->operands[0];
4414 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, num, method);
4415 ELEM_REMOVE(&niobj->link);
4416 return COMPILE_OK;
4417 }
4418 }
4419 }
4420 else if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
4421 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4422 IS_NEXT_INSN_ID(&niobj->link, send)) {
4423 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4424 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4425 VALUE num = iobj->operands[0];
4426 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK));
4427 ELEM_REMOVE(&iobj->link);
4428 ELEM_REMOVE(niobj->link.next);
4429 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4430 return COMPILE_OK;
4431 }
4432 }
4433 // newarray n, dupchilledstring "E", getlocal b, send :pack with {buffer: b}
4434 // -> dupchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
4435 else if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
4436 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4437 IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4438 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4439 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4440 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4441 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4442 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4443 VALUE num = iobj->operands[0];
4444 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 2), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER));
4445 // Remove the "send" insn.
4446 ELEM_REMOVE((niobj->link.next)->next);
4447 // Remove the modified insn from its original "newarray" position...
4448 ELEM_REMOVE(&iobj->link);
4449 // and insert it after the buffer insn.
4450 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4451 return COMPILE_OK;
4452 }
4453 }
4454
4455 // Break the "else if" chain since some prior checks abort after sub-ifs.
4456 // We already found "newarray". To match `[...].include?(arg)` we look for
4457 // the instruction(s) representing the argument followed by a "send".
4458 if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
4459 IS_INSN_ID(niobj, putobject) ||
4460 IS_INSN_ID(niobj, putself) ||
4461 IS_INSN_ID(niobj, getlocal) ||
4462 IS_INSN_ID(niobj, getinstancevariable)) &&
4463 IS_NEXT_INSN_ID(&niobj->link, send)) {
4464
4465 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4466 const struct rb_callinfo *ci;
4467 // Allow any number (0 or more) of simple method calls on the argument
4468 // (as in `[...].include?(arg.method1.method2)`.
4469 do {
4470 sendobj = sendobj->next;
4471 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4472 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4473
4474 // If this send is for .include? with one arg we can do our opt.
4475 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4476 VALUE num = iobj->operands[0];
4477 INSN *sendins = (INSN *)sendobj;
4478 insn_replace_with_operands(iseq, sendins, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P));
4479 // Remove the original "newarray" insn.
4480 ELEM_REMOVE(&iobj->link);
4481 return COMPILE_OK;
4482 }
4483 }
4484 }
4485
4486 /*
4487 * duparray [...]
4488 * some insn for the arg...
4489 * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4490 * =>
4491 * arg insn...
4492 * opt_duparray_send [...], :include?, 1
4493 */
4494 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4495 INSN *niobj = (INSN *)iobj->link.next;
4496 if ((IS_INSN_ID(niobj, getlocal) ||
4497 IS_INSN_ID(niobj, getinstancevariable) ||
4498 IS_INSN_ID(niobj, putself) ||
4499 IS_INSN_ID(niobj, putobject) ||
4500 IS_INSN_ID(niobj, putnil)) &&
4501 IS_NEXT_INSN_ID(&niobj->link, send)) {
4502
4503 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4504 const struct rb_callinfo *ci;
4505 // Allow any number (0 or more) of simple method calls on the argument
4506 // (as in `[...].include?(arg.method1.method2)`.
4507 do {
4508 sendobj = sendobj->next;
4509 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4510 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4511
4512 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4513 // Move the array arg from duparray to opt_duparray_send.
4514 VALUE ary = iobj->operands[0];
4516
4517 INSN *sendins = (INSN *)sendobj;
4518 insn_replace_with_operands(iseq, sendins, BIN(opt_duparray_send), 3, ary, rb_id2sym(idIncludeP), INT2FIX(1));
4519
4520 // Remove the duparray insn.
4521 ELEM_REMOVE(&iobj->link);
4522 return COMPILE_OK;
4523 }
4524 }
4525 }
4526
4527
4528 if (IS_INSN_ID(iobj, send)) {
4529 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4530 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4531
4532#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4533 if (vm_ci_simple(ci)) {
4534 switch (vm_ci_argc(ci)) {
4535 case 0:
4536 switch (vm_ci_mid(ci)) {
4537 case idLength: SP_INSN(length); return COMPILE_OK;
4538 case idSize: SP_INSN(size); return COMPILE_OK;
4539 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4540 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4541 case idSucc: SP_INSN(succ); return COMPILE_OK;
4542 case idNot: SP_INSN(not); return COMPILE_OK;
4543 }
4544 break;
4545 case 1:
4546 switch (vm_ci_mid(ci)) {
4547 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4548 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4549 case idMULT: SP_INSN(mult); return COMPILE_OK;
4550 case idDIV: SP_INSN(div); return COMPILE_OK;
4551 case idMOD: SP_INSN(mod); return COMPILE_OK;
4552 case idEq: SP_INSN(eq); return COMPILE_OK;
4553 case idNeq: SP_INSN(neq); return COMPILE_OK;
4554 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4555 case idLT: SP_INSN(lt); return COMPILE_OK;
4556 case idLE: SP_INSN(le); return COMPILE_OK;
4557 case idGT: SP_INSN(gt); return COMPILE_OK;
4558 case idGE: SP_INSN(ge); return COMPILE_OK;
4559 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4560 case idAREF: SP_INSN(aref); return COMPILE_OK;
4561 case idAnd: SP_INSN(and); return COMPILE_OK;
4562 case idOr: SP_INSN(or); return COMPILE_OK;
4563 }
4564 break;
4565 case 2:
4566 switch (vm_ci_mid(ci)) {
4567 case idASET: SP_INSN(aset); return COMPILE_OK;
4568 }
4569 break;
4570 }
4571 }
4572
4573 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4574 iobj->insn_id = BIN(opt_send_without_block);
4575 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4576 }
4577 }
4578#undef SP_INSN
4579
4580 return COMPILE_OK;
4581}
4582
4583static inline int
4584tailcallable_p(rb_iseq_t *iseq)
4585{
4586 switch (ISEQ_BODY(iseq)->type) {
4587 case ISEQ_TYPE_TOP:
4588 case ISEQ_TYPE_EVAL:
4589 case ISEQ_TYPE_MAIN:
4590 /* not tail callable because cfp will be over popped */
4591 case ISEQ_TYPE_RESCUE:
4592 case ISEQ_TYPE_ENSURE:
4593 /* rescue block can't tail call because of errinfo */
4594 return FALSE;
4595 default:
4596 return TRUE;
4597 }
4598}
4599
4600static int
4601iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4602{
4603 LINK_ELEMENT *list;
4604 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4605 const int do_tailcallopt = tailcallable_p(iseq) &&
4606 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4607 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4608 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4609 const int do_without_ints = ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_WITHOUT_INTERRUPTS;
4610 int rescue_level = 0;
4611 int tailcallopt = do_tailcallopt;
4612
4613 list = FIRST_ELEMENT(anchor);
4614
4615 int do_block_optimization = 0;
4616 LABEL * block_loop_label = NULL;
4617
4618 int nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
4619 VALUE unref_counts_buf = 0, unref_stamps_buf = 0;
4621 .capacity = nlabels,
4622 .gen = 0,
4623 .counts = ALLOCV_N(int, unref_counts_buf, nlabels),
4624 .stamps = ALLOCV_N(unsigned int, unref_stamps_buf, nlabels),
4625 };
4626 MEMZERO(unreachable_unref.counts, int, nlabels);
4627 MEMZERO(unreachable_unref.stamps, unsigned int, nlabels);
4628
4629 // If we're optimizing a block
4630 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
4631 do_block_optimization = 1;
4632
4633 // If the block starts with a nop and a label,
4634 // record the label so we can detect if it's a jump target
4635 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4636 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop) && IS_LABEL(le->next)) {
4637 block_loop_label = (LABEL *)le->next;
4638 }
4639 }
4640
4641 while (list) {
4642 if (IS_INSN(list)) {
4643 if (do_peepholeopt) {
4644 iseq_peephole_optimize(iseq, &unreachable_unref, list, tailcallopt);
4645 }
4646 if (do_si) {
4647 iseq_specialized_instruction(iseq, (INSN *)list);
4648 }
4649 if (do_ou) {
4650 insn_operands_unification((INSN *)list);
4651 }
4652
4653 if (do_without_ints) {
4654 INSN *item = (INSN *)list;
4655 if (IS_INSN_ID(item, jump)) {
4656 item->insn_id = BIN(jump_without_ints);
4657 }
4658 else if (IS_INSN_ID(item, branchif)) {
4659 item->insn_id = BIN(branchif_without_ints);
4660 }
4661 else if (IS_INSN_ID(item, branchunless)) {
4662 item->insn_id = BIN(branchunless_without_ints);
4663 }
4664 else if (IS_INSN_ID(item, branchnil)) {
4665 item->insn_id = BIN(branchnil_without_ints);
4666 }
4667 }
4668
4669 if (do_block_optimization) {
4670 INSN * item = (INSN *)list;
4671 // Give up if there is a throw
4672 if (IS_INSN_ID(item, throw)) {
4673 do_block_optimization = 0;
4674 }
4675 else {
4676 // If the instruction has a jump target, check if the
4677 // jump target is the block loop label
4678 const char *types = insn_op_types(item->insn_id);
4679 for (int j = 0; types[j]; j++) {
4680 if (types[j] == TS_OFFSET) {
4681 // If the jump target is equal to the block loop
4682 // label, then we can't do the optimization because
4683 // the leading `nop` instruction fires the block
4684 // entry tracepoint
4685 LABEL * target = (LABEL *)OPERAND_AT(item, j);
4686 if (target == block_loop_label) {
4687 do_block_optimization = 0;
4688 }
4689 }
4690 }
4691 }
4692 }
4693 }
4694 if (IS_LABEL(list)) {
4695 switch (((LABEL *)list)->rescued) {
4696 case LABEL_RESCUE_BEG:
4697 rescue_level++;
4698 tailcallopt = FALSE;
4699 break;
4700 case LABEL_RESCUE_END:
4701 if (!--rescue_level) tailcallopt = do_tailcallopt;
4702 break;
4703 }
4704 }
4705 list = list->next;
4706 }
4707
4708 if (do_block_optimization) {
4709 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4710 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4711 ELEM_REMOVE(le);
4712 }
4713 }
4714
4715 ALLOCV_END(unref_counts_buf);
4716 ALLOCV_END(unref_stamps_buf);
4717 return COMPILE_OK;
4718}
4719
4720#if OPT_INSTRUCTIONS_UNIFICATION
4721static INSN *
4722new_unified_insn(rb_iseq_t *iseq,
4723 int insn_id, int size, LINK_ELEMENT *seq_list)
4724{
4725 INSN *iobj = 0;
4726 LINK_ELEMENT *list = seq_list;
4727 int i, argc = 0;
4728 VALUE *operands = 0, *ptr = 0;
4729
4730
4731 /* count argc */
4732 for (i = 0; i < size; i++) {
4733 iobj = (INSN *)list;
4734 argc += iobj->operand_size;
4735 list = list->next;
4736 }
4737
4738 if (argc > 0) {
4739 ptr = operands = compile_data_alloc2_type(iseq, VALUE, argc);
4740 }
4741
4742 /* copy operands */
4743 list = seq_list;
4744 for (i = 0; i < size; i++) {
4745 iobj = (INSN *)list;
4746 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4747 ptr += iobj->operand_size;
4748 list = list->next;
4749 }
4750
4751 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4752}
4753#endif
4754
4755/*
4756 * This scheme can get more performance if do this optimize with
4757 * label address resolving.
4758 * It's future work (if compile time was bottle neck).
4759 */
4760static int
4761iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4762{
4763#if OPT_INSTRUCTIONS_UNIFICATION
4764 LINK_ELEMENT *list;
4765 INSN *iobj, *niobj;
4766 int id, k;
4767 intptr_t j;
4768
4769 list = FIRST_ELEMENT(anchor);
4770 while (list) {
4771 if (IS_INSN(list)) {
4772 iobj = (INSN *)list;
4773 id = iobj->insn_id;
4774 if (unified_insns_data[id] != 0) {
4775 const int *const *entry = unified_insns_data[id];
4776 for (j = 1; j < (intptr_t)entry[0]; j++) {
4777 const int *unified = entry[j];
4778 LINK_ELEMENT *li = list->next;
4779 for (k = 2; k < unified[1]; k++) {
4780 if (!IS_INSN(li) ||
4781 ((INSN *)li)->insn_id != unified[k]) {
4782 goto miss;
4783 }
4784 li = li->next;
4785 }
4786 /* matched */
4787 niobj =
4788 new_unified_insn(iseq, unified[0], unified[1] - 1,
4789 list);
4790
4791 /* insert to list */
4792 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4793 niobj->link.next = li;
4794 if (li) {
4795 li->prev = (LINK_ELEMENT *)niobj;
4796 }
4797
4798 list->prev->next = (LINK_ELEMENT *)niobj;
4799 list = (LINK_ELEMENT *)niobj;
4800 break;
4801 miss:;
4802 }
4803 }
4804 }
4805 list = list->next;
4806 }
4807#endif
4808 return COMPILE_OK;
4809}
4810
4811static int
4812all_string_result_p(const NODE *node)
4813{
4814 if (!node) return FALSE;
4815 switch (nd_type(node)) {
4816 case NODE_STR: case NODE_DSTR: case NODE_FILE:
4817 return TRUE;
4818 case NODE_IF: case NODE_UNLESS:
4819 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4820 if (all_string_result_p(RNODE_IF(node)->nd_body))
4821 return all_string_result_p(RNODE_IF(node)->nd_else);
4822 return FALSE;
4823 case NODE_AND: case NODE_OR:
4824 if (!RNODE_AND(node)->nd_2nd)
4825 return all_string_result_p(RNODE_AND(node)->nd_1st);
4826 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4827 return FALSE;
4828 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4829 default:
4830 return FALSE;
4831 }
4832}
4833
4835 rb_iseq_t *const iseq;
4836 LINK_ANCHOR *const ret;
4837 VALUE lit;
4838 const NODE *lit_node;
4839 int cnt;
4840 int dregx;
4841};
4842
4843static int
4844append_dstr_fragment(struct dstr_ctxt *args, const NODE *const node, rb_parser_string_t *str)
4845{
4846 VALUE s = rb_str_new_mutable_parser_string(str);
4847 if (args->dregx) {
4848 VALUE error = rb_reg_check_preprocess(s);
4849 if (!NIL_P(error)) {
4850 COMPILE_ERROR(args->iseq, nd_line(node), "%" PRIsVALUE, error);
4851 return COMPILE_NG;
4852 }
4853 }
4854 if (NIL_P(args->lit)) {
4855 args->lit = s;
4856 args->lit_node = node;
4857 }
4858 else {
4859 rb_str_buf_append(args->lit, s);
4860 }
4861 return COMPILE_OK;
4862}
4863
4864static void
4865flush_dstr_fragment(struct dstr_ctxt *args)
4866{
4867 if (!NIL_P(args->lit)) {
4868 rb_iseq_t *iseq = args->iseq;
4869 VALUE lit = args->lit;
4870 args->lit = Qnil;
4871 lit = rb_fstring(lit);
4872 ADD_INSN1(args->ret, args->lit_node, putobject, lit);
4873 RB_OBJ_WRITTEN(args->iseq, Qundef, lit);
4874 args->cnt++;
4875 }
4876}
4877
4878static int
4879compile_dstr_fragments_0(struct dstr_ctxt *args, const NODE *const node)
4880{
4881 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4882 rb_parser_string_t *str = RNODE_DSTR(node)->string;
4883
4884 if (str) {
4885 CHECK(append_dstr_fragment(args, node, str));
4886 }
4887
4888 while (list) {
4889 const NODE *const head = list->nd_head;
4890 if (nd_type_p(head, NODE_STR)) {
4891 CHECK(append_dstr_fragment(args, node, RNODE_STR(head)->string));
4892 }
4893 else if (nd_type_p(head, NODE_DSTR)) {
4894 CHECK(compile_dstr_fragments_0(args, head));
4895 }
4896 else {
4897 flush_dstr_fragment(args);
4898 rb_iseq_t *iseq = args->iseq;
4899 CHECK(COMPILE(args->ret, "each string", head));
4900 args->cnt++;
4901 }
4902 list = (struct RNode_LIST *)list->nd_next;
4903 }
4904 return COMPILE_OK;
4905}
4906
4907static int
4908compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp, int dregx)
4909{
4910 struct dstr_ctxt args = {
4911 .iseq = iseq, .ret = ret,
4912 .lit = Qnil, .lit_node = NULL,
4913 .cnt = 0, .dregx = dregx,
4914 };
4915 CHECK(compile_dstr_fragments_0(&args, node));
4916 flush_dstr_fragment(&args);
4917
4918 *cntp = args.cnt;
4919
4920 return COMPILE_OK;
4921}
4922
4923static int
4924compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4925{
4926 while (node && nd_type_p(node, NODE_BLOCK)) {
4927 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4928 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4929 node = RNODE_BLOCK(node)->nd_next;
4930 }
4931 if (node) {
4932 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4933 }
4934 return COMPILE_OK;
4935}
4936
4937static int
4938compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4939{
4940 int cnt;
4941 if (!RNODE_DSTR(node)->nd_next) {
4942 VALUE lit = rb_node_dstr_string_val(node);
4943 ADD_INSN1(ret, node, dupstring, lit);
4945 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4946 }
4947 else {
4948 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, FALSE));
4949 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4950 }
4951 return COMPILE_OK;
4952}
4953
4954static int
4955compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4956{
4957 int cnt;
4958 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4959
4960 if (!RNODE_DREGX(node)->nd_next) {
4961 if (!popped) {
4962 VALUE src = rb_node_dregx_string_val(node);
4963 VALUE match = iseq_reg_compile(iseq, src, cflag, NULL, 0);
4964 ADD_INSN1(ret, node, putobject, match);
4965 RB_OBJ_WRITTEN(iseq, Qundef, match);
4966 }
4967 return COMPILE_OK;
4968 }
4969
4970 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, TRUE));
4971 ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
4972
4973 if (popped) {
4974 ADD_INSN(ret, node, pop);
4975 }
4976
4977 return COMPILE_OK;
4978}
4979
4980static int
4981compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4982 LABEL *then_label, LABEL *else_label)
4983{
4984 const int line = nd_line(node);
4985 LABEL *lend = NEW_LABEL(line);
4986 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4987 + VM_SVAR_FLIPFLOP_START;
4988 VALUE key = INT2FIX(cnt);
4989
4990 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4991 ADD_INSNL(ret, node, branchif, lend);
4992
4993 /* *flip == 0 */
4994 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4995 ADD_INSNL(ret, node, branchunless, else_label);
4996 ADD_INSN1(ret, node, putobject, Qtrue);
4997 ADD_INSN1(ret, node, setspecial, key);
4998 if (!again) {
4999 ADD_INSNL(ret, node, jump, then_label);
5000 }
5001
5002 /* *flip == 1 */
5003 ADD_LABEL(ret, lend);
5004 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
5005 ADD_INSNL(ret, node, branchunless, then_label);
5006 ADD_INSN1(ret, node, putobject, Qfalse);
5007 ADD_INSN1(ret, node, setspecial, key);
5008 ADD_INSNL(ret, node, jump, then_label);
5009
5010 return COMPILE_OK;
5011}
5012
5013static int
5014compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
5015 LABEL *then_label, LABEL *else_label);
5016
5017#define COMPILE_SINGLE 2
5018static int
5019compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
5020 LABEL *then_label, LABEL *else_label)
5021{
5022 DECL_ANCHOR(seq);
5023 INIT_ANCHOR(seq);
5024 LABEL *label = NEW_LABEL(nd_line(cond));
5025 if (!then_label) then_label = label;
5026 else if (!else_label) else_label = label;
5027
5028 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
5029
5030 if (LIST_INSN_SIZE_ONE(seq)) {
5031 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
5032 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
5033 return COMPILE_OK;
5034 }
5035 if (!label->refcnt) {
5036 return COMPILE_SINGLE;
5037 }
5038 ADD_LABEL(seq, label);
5039 ADD_SEQ(ret, seq);
5040 return COMPILE_OK;
5041}
5042
5043static int
5044compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
5045 LABEL *then_label, LABEL *else_label)
5046{
5047 int ok;
5048 DECL_ANCHOR(ignore);
5049
5050 again:
5051 switch (nd_type(cond)) {
5052 case NODE_AND:
5053 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
5054 cond = RNODE_AND(cond)->nd_2nd;
5055 if (ok == COMPILE_SINGLE) {
5056 ADD_INSNL(ret, cond, jump, else_label);
5057 INIT_ANCHOR(ignore);
5058 ret = ignore;
5059 then_label = NEW_LABEL(nd_line(cond));
5060 }
5061 goto again;
5062 case NODE_OR:
5063 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
5064 cond = RNODE_OR(cond)->nd_2nd;
5065 if (ok == COMPILE_SINGLE) {
5066 ADD_INSNL(ret, cond, jump, then_label);
5067 INIT_ANCHOR(ignore);
5068 ret = ignore;
5069 else_label = NEW_LABEL(nd_line(cond));
5070 }
5071 goto again;
5072 case NODE_SYM:
5073 case NODE_LINE:
5074 case NODE_FILE:
5075 case NODE_ENCODING:
5076 case NODE_INTEGER: /* NODE_INTEGER is always true */
5077 case NODE_FLOAT: /* NODE_FLOAT is always true */
5078 case NODE_RATIONAL: /* NODE_RATIONAL is always true */
5079 case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
5080 case NODE_TRUE:
5081 case NODE_STR:
5082 case NODE_REGX:
5083 case NODE_ZLIST:
5084 case NODE_LAMBDA:
5085 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
5086 ADD_INSNL(ret, cond, jump, then_label);
5087 return COMPILE_OK;
5088 case NODE_FALSE:
5089 case NODE_NIL:
5090 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
5091 ADD_INSNL(ret, cond, jump, else_label);
5092 return COMPILE_OK;
5093 case NODE_LIST:
5094 case NODE_ARGSCAT:
5095 case NODE_DREGX:
5096 case NODE_DSTR:
5097 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
5098 ADD_INSNL(ret, cond, jump, then_label);
5099 return COMPILE_OK;
5100 case NODE_FLIP2:
5101 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
5102 return COMPILE_OK;
5103 case NODE_FLIP3:
5104 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
5105 return COMPILE_OK;
5106 case NODE_DEFINED:
5107 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
5108 break;
5109 default:
5110 {
5111 DECL_ANCHOR(cond_seq);
5112 INIT_ANCHOR(cond_seq);
5113
5114 CHECK(COMPILE(cond_seq, "branch condition", cond));
5115
5116 if (LIST_INSN_SIZE_ONE(cond_seq)) {
5117 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
5118 if (insn->insn_id == BIN(putobject)) {
5119 if (RTEST(insn->operands[0])) {
5120 ADD_INSNL(ret, cond, jump, then_label);
5121 // maybe unreachable
5122 return COMPILE_OK;
5123 }
5124 else {
5125 ADD_INSNL(ret, cond, jump, else_label);
5126 return COMPILE_OK;
5127 }
5128 }
5129 }
5130 ADD_SEQ(ret, cond_seq);
5131 }
5132 break;
5133 }
5134
5135 ADD_INSNL(ret, cond, branchunless, else_label);
5136 ADD_INSNL(ret, cond, jump, then_label);
5137 return COMPILE_OK;
5138}
5139
5140#define HASH_BRACE 1
5141
5142static int
5143keyword_node_p(const NODE *const node)
5144{
5145 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
5146}
5147
5148static VALUE
5149get_symbol_value(rb_iseq_t *iseq, const NODE *node)
5150{
5151 switch (nd_type(node)) {
5152 case NODE_SYM:
5153 return rb_node_sym_string_val(node);
5154 default:
5155 UNKNOWN_NODE("get_symbol_value", node, Qnil);
5156 }
5157}
5158
5159static VALUE
5160node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
5161{
5162 NODE *node = node_hash->nd_head;
5163 VALUE hash = rb_hash_new();
5164 VALUE ary = rb_ary_new();
5165
5166 for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5167 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
5168 VALUE idx = rb_hash_aref(hash, key);
5169 if (!NIL_P(idx)) {
5170 rb_ary_store(ary, FIX2INT(idx), Qfalse);
5171 (*count_ptr)--;
5172 }
5173 rb_hash_aset(hash, key, INT2FIX(i));
5174 rb_ary_store(ary, i, Qtrue);
5175 (*count_ptr)++;
5176 }
5177
5178 return ary;
5179}
5180
5181static int
5182compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5183 const NODE *const root_node,
5184 struct rb_callinfo_kwarg **const kw_arg_ptr,
5185 unsigned int *flag)
5186{
5187 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
5188 RUBY_ASSERT(kw_arg_ptr != NULL);
5189 RUBY_ASSERT(flag != NULL);
5190
5191 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
5192 const NODE *node = RNODE_HASH(root_node)->nd_head;
5193 int seen_nodes = 0;
5194
5195 while (node) {
5196 const NODE *key_node = RNODE_LIST(node)->nd_head;
5197 seen_nodes++;
5198
5199 RUBY_ASSERT(nd_type_p(node, NODE_LIST));
5200 if (key_node && nd_type_p(key_node, NODE_SYM)) {
5201 /* can be keywords */
5202 }
5203 else {
5204 if (flag) {
5205 *flag |= VM_CALL_KW_SPLAT;
5206 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5207 /* A new hash will be created for the keyword arguments
5208 * in this case, so mark the method as passing mutable
5209 * keyword splat.
5210 */
5211 *flag |= VM_CALL_KW_SPLAT_MUT;
5212 }
5213 }
5214 return FALSE;
5215 }
5216 node = RNODE_LIST(node)->nd_next; /* skip value node */
5217 node = RNODE_LIST(node)->nd_next;
5218 }
5219
5220 /* may be keywords */
5221 node = RNODE_HASH(root_node)->nd_head;
5222 {
5223 int len = 0;
5224 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
5225
5226 if (len > VM_CALL_KW_LEN_MAX) {
5227 COMPILE_ERROR(ERROR_ARGS_AT(root_node) "too many keyword arguments (%d, maximum is %d)",
5228 len, (int)VM_CALL_KW_LEN_MAX);
5229 }
5230
5231 struct rb_callinfo_kwarg *kw_arg =
5232 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
5233 VALUE *keywords = kw_arg->keywords;
5234 int i = 0;
5235 int j = 0;
5236 kw_arg->references = 0;
5237 kw_arg->keyword_len = len;
5238
5239 *kw_arg_ptr = kw_arg;
5240
5241 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5242 const NODE *key_node = RNODE_LIST(node)->nd_head;
5243 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5244 int popped = TRUE;
5245 if (rb_ary_entry(key_index, i)) {
5246 keywords[j] = get_symbol_value(iseq, key_node);
5247 j++;
5248 popped = FALSE;
5249 }
5250 NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
5251 }
5252 RUBY_ASSERT(j == len);
5253 return TRUE;
5254 }
5255 }
5256 return FALSE;
5257}
5258
5259static int
5260compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
5261{
5262 int len = 0;
5263
5264 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
5265 if (CPDEBUG > 0) {
5266 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
5267 }
5268
5269 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
5270 *kwnode_ptr = RNODE_LIST(node)->nd_head;
5271 }
5272 else {
5273 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
5274 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
5275 }
5276 }
5277
5278 return len;
5279}
5280
5281static inline bool
5282frozen_string_literal_p(const rb_iseq_t *iseq)
5283{
5284 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
5285}
5286
5287static inline bool
5288static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
5289{
5290 switch (nd_type(node)) {
5291 case NODE_SYM:
5292 case NODE_REGX:
5293 case NODE_LINE:
5294 case NODE_ENCODING:
5295 case NODE_INTEGER:
5296 case NODE_FLOAT:
5297 case NODE_RATIONAL:
5298 case NODE_IMAGINARY:
5299 case NODE_NIL:
5300 case NODE_TRUE:
5301 case NODE_FALSE:
5302 return TRUE;
5303 case NODE_STR:
5304 case NODE_FILE:
5305 return hash_key || frozen_string_literal_p(iseq);
5306 default:
5307 return FALSE;
5308 }
5309}
5310
5311static inline VALUE
5312static_literal_value(const NODE *node, rb_iseq_t *iseq)
5313{
5314 switch (nd_type(node)) {
5315 case NODE_INTEGER:
5316 {
5317 VALUE lit = rb_node_integer_literal_val(node);
5318 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5319 return lit;
5320 }
5321 case NODE_FLOAT:
5322 {
5323 VALUE lit = rb_node_float_literal_val(node);
5324 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5325 return lit;
5326 }
5327 case NODE_RATIONAL:
5328 return rb_ractor_make_shareable(rb_node_rational_literal_val(node));
5329 case NODE_IMAGINARY:
5330 return rb_ractor_make_shareable(rb_node_imaginary_literal_val(node));
5331 case NODE_NIL:
5332 return Qnil;
5333 case NODE_TRUE:
5334 return Qtrue;
5335 case NODE_FALSE:
5336 return Qfalse;
5337 case NODE_SYM:
5338 return rb_node_sym_string_val(node);
5339 case NODE_REGX:
5340 return RB_OBJ_SET_SHAREABLE(rb_node_regx_string_val(node));
5341 case NODE_LINE:
5342 return rb_node_line_lineno_val(node);
5343 case NODE_ENCODING:
5344 return rb_node_encoding_val(node);
5345 case NODE_FILE:
5346 case NODE_STR:
5347 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
5348 VALUE lit = get_string_value(node);
5349 VALUE str = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
5351 return str;
5352 }
5353 else {
5354 return get_string_value(node);
5355 }
5356 default:
5357 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
5358 }
5359}
5360
5361static int
5362compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
5363{
5364 const NODE *line_node = node;
5365
5366 if (nd_type_p(node, NODE_ZLIST)) {
5367 if (!popped) {
5368 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5369 }
5370 return 0;
5371 }
5372
5373 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5374
5375 if (popped) {
5376 for (; node; node = RNODE_LIST(node)->nd_next) {
5377 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
5378 }
5379 return 1;
5380 }
5381
5382 /* Compilation of an array literal.
5383 * The following code is essentially the same as:
5384 *
5385 * for (int count = 0; node; count++; node->nd_next) {
5386 * compile(node->nd_head);
5387 * }
5388 * ADD_INSN(newarray, count);
5389 *
5390 * However, there are three points.
5391 *
5392 * - The code above causes stack overflow for a big string literal.
5393 * The following limits the stack length up to max_stack_len.
5394 *
5395 * [x1,x2,...,x10000] =>
5396 * push x1 ; push x2 ; ...; push x256; newarray 256;
5397 * push x257; push x258; ...; push x512; pushtoarray 256;
5398 * push x513; push x514; ...; push x768; pushtoarray 256;
5399 * ...
5400 *
5401 * - Long subarray can be optimized by pre-allocating a hidden array.
5402 *
5403 * [1,2,3,...,100] =>
5404 * duparray [1,2,3,...,100]
5405 *
5406 * [x, 1,2,3,...,100, z] =>
5407 * push x; newarray 1;
5408 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5409 * push z; pushtoarray 1;
5410 *
5411 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5412 * to only push it onto the array if it is not empty
5413 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5414 *
5415 * [1,2,3,**kw] =>
5416 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5417 */
5418
5419 const int max_stack_len = 0x100;
5420 const int min_tmp_ary_len = 0x40;
5421 int stack_len = 0;
5422
5423 /* Either create a new array, or push to the existing array */
5424#define FLUSH_CHUNK \
5425 if (stack_len) { \
5426 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5427 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5428 first_chunk = FALSE; \
5429 stack_len = 0; \
5430 }
5431
5432 while (node) {
5433 int count = 1;
5434
5435 /* pre-allocation check (this branch can be omittable) */
5436 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5437 /* count the elements that are optimizable */
5438 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5439 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5440 count++;
5441
5442 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5443 /* The literal contains only optimizable elements, or the subarray is long enough */
5444 VALUE ary = rb_ary_hidden_new(count);
5445
5446 /* Create a hidden array */
5447 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5448 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5450
5451 /* Emit optimized code */
5452 FLUSH_CHUNK;
5453 if (first_chunk) {
5454 ADD_INSN1(ret, line_node, duparray, ary);
5455 first_chunk = FALSE;
5456 }
5457 else {
5458 ADD_INSN1(ret, line_node, putobject, ary);
5459 ADD_INSN(ret, line_node, concattoarray);
5460 }
5462 RB_OBJ_WRITTEN(iseq, Qundef, ary);
5463 }
5464 }
5465
5466 /* Base case: Compile "count" elements */
5467 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5468 if (CPDEBUG > 0) {
5469 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5470 }
5471
5472 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5473 /* Create array or push existing non-keyword elements onto array */
5474 if (stack_len == 0 && first_chunk) {
5475 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5476 }
5477 else {
5478 FLUSH_CHUNK;
5479 }
5480 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5481 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5482 return 1;
5483 }
5484 else {
5485 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5486 stack_len++;
5487 }
5488
5489 /* If there are many pushed elements, flush them to avoid stack overflow */
5490 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5491 }
5492 }
5493
5494 FLUSH_CHUNK;
5495#undef FLUSH_CHUNK
5496 return 1;
5497}
5498
5499static inline int
5500static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5501{
5502 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);
5503}
5504
5505static int
5506compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5507{
5508 const NODE *line_node = node;
5509
5510 node = RNODE_HASH(node)->nd_head;
5511
5512 if (!node || nd_type_p(node, NODE_ZLIST)) {
5513 if (!popped) {
5514 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5515 }
5516 return 0;
5517 }
5518
5519 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5520
5521 if (popped) {
5522 for (; node; node = RNODE_LIST(node)->nd_next) {
5523 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5524 }
5525 return 1;
5526 }
5527
5528 /* Compilation of a hash literal (or keyword arguments).
5529 * This is very similar to compile_array, but there are some differences:
5530 *
5531 * - It contains key-value pairs. So we need to take every two elements.
5532 * We can assume that the length is always even.
5533 *
5534 * - Merging is done by a method call (id_core_hash_merge_bang_ptr).
5535 * Sometimes we need to insert the receiver, so "anchor" is needed.
5536 * In addition, a method call is much slower than concatarray.
5537 * So it pays only when the subsequence is really long.
5538 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5539 *
5540 * - We need to handle keyword splat: **kw.
5541 * For **kw, the key part (node->nd_head) is NULL, and the value part
5542 * (node->nd_next->nd_head) is "kw".
5543 * The code is a bit difficult to avoid hash allocation for **{}.
5544 */
5545
5546 const int max_stack_len = 0x100;
5547 const int min_tmp_hash_len = 0x800;
5548 int stack_len = 0;
5549 int first_chunk = 1;
5550 DECL_ANCHOR(anchor);
5551 INIT_ANCHOR(anchor);
5552
5553 /* Convert pushed elements to a hash, and merge if needed */
5554#define FLUSH_CHUNK() \
5555 if (stack_len) { \
5556 if (first_chunk) { \
5557 APPEND_LIST(ret, anchor); \
5558 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5559 } \
5560 else { \
5561 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5562 ADD_INSN(ret, line_node, swap); \
5563 APPEND_LIST(ret, anchor); \
5564 ADD_SEND(ret, line_node, id_core_hash_merge_bang_ptr, INT2FIX(stack_len + 1)); \
5565 } \
5566 INIT_ANCHOR(anchor); \
5567 first_chunk = stack_len = 0; \
5568 }
5569
5570 while (node) {
5571 int count = 1;
5572
5573 /* pre-allocation check (this branch can be omittable) */
5574 if (static_literal_node_pair_p(node, iseq)) {
5575 /* count the elements that are optimizable */
5576 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5577 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5578 count++;
5579
5580 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5581 /* The literal contains only optimizable elements, or the subsequence is long enough */
5582 VALUE ary = rb_ary_hidden_new(count);
5583
5584 /* Create a hidden hash */
5585 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5586 VALUE elem[2];
5587 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5588 if (!RB_SPECIAL_CONST_P(elem[0])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[0]);
5589 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5590 if (!RB_SPECIAL_CONST_P(elem[1])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[1]);
5591 rb_ary_cat(ary, elem, 2);
5592 }
5593 VALUE hash = rb_hash_alloc_fixed_size(Qfalse, RARRAY_LEN(ary) / 2);
5594 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
5595 RB_GC_GUARD(ary);
5596 hash = RB_OBJ_SET_FROZEN_SHAREABLE(hash);
5597
5598 /* Emit optimized code */
5599 FLUSH_CHUNK();
5600 if (first_chunk) {
5601 ADD_INSN1(ret, line_node, duphash, hash);
5602 first_chunk = 0;
5603 }
5604 else {
5605 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5606 ADD_INSN(ret, line_node, swap);
5607
5608 ADD_INSN1(ret, line_node, putobject, hash);
5609
5610 ADD_SEND(ret, line_node, id_core_hash_merge_bang_kwd, INT2FIX(2));
5611 }
5612 RB_OBJ_WRITTEN(iseq, Qundef, hash);
5613 }
5614 }
5615
5616 /* Base case: Compile "count" elements */
5617 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5618
5619 if (CPDEBUG > 0) {
5620 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5621 }
5622
5623 if (RNODE_LIST(node)->nd_head) {
5624 /* Normal key-value pair */
5625 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5626 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5627 stack_len += 2;
5628
5629 /* If there are many pushed elements, flush them to avoid stack overflow */
5630 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5631 }
5632 else {
5633 /* kwsplat case: foo(..., **kw, ...) */
5634 FLUSH_CHUNK();
5635
5636 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5637 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5638 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5639 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5640 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5641
5642 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5643 if (empty_kw) {
5644 if (only_kw && method_call_keywords) {
5645 /* **{} appears at the only keyword argument in method call,
5646 * so it won't be modified.
5647 * kw is a special NODE_LIT that contains a special empty hash,
5648 * so this emits: putobject {}.
5649 * This is only done for method calls and not for literal hashes,
5650 * because literal hashes should always result in a new hash.
5651 */
5652 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5653 }
5654 else if (first_kw) {
5655 /* **{} appears as the first keyword argument, so it may be modified.
5656 * We need to create a fresh hash object.
5657 */
5658 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5659 }
5660 /* Any empty keyword splats that are not the first can be ignored.
5661 * since merging an empty hash into the existing hash is the same
5662 * as not merging it. */
5663 }
5664 else {
5665 if (only_kw && method_call_keywords) {
5666 /* **kw is only keyword argument in method call.
5667 * Use directly. This will be not be flagged as mutable.
5668 * This is only done for method calls and not for literal hashes,
5669 * because literal hashes should always result in a new hash.
5670 */
5671 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5672 }
5673 else {
5674 /* There is more than one keyword argument, or this is not a method
5675 * call. In that case, we need to add an empty hash (if first keyword),
5676 * or merge the hash to the accumulated hash (if not the first keyword).
5677 */
5678 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5679 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5680 else ADD_INSN(ret, line_node, swap);
5681
5682 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5683
5684 ADD_SEND(ret, line_node, id_core_hash_merge_bang_kwd, INT2FIX(2));
5685 }
5686 }
5687
5688 first_chunk = 0;
5689 }
5690 }
5691 }
5692
5693 FLUSH_CHUNK();
5694#undef FLUSH_CHUNK
5695 return 1;
5696}
5697
5698static VALUE
5699rb_node_case_when_optimizable_literal(const NODE *const node)
5700{
5701 switch (nd_type(node)) {
5702 case NODE_INTEGER:
5703 return rb_node_integer_literal_val(node);
5704 case NODE_FLOAT: {
5705 VALUE v = rb_node_float_literal_val(node);
5706 double ival;
5707
5708 if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5709 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5710 }
5711 return v;
5712 }
5713 case NODE_RATIONAL:
5714 case NODE_IMAGINARY:
5715 return Qundef;
5716 case NODE_NIL:
5717 return Qnil;
5718 case NODE_TRUE:
5719 return Qtrue;
5720 case NODE_FALSE:
5721 return Qfalse;
5722 case NODE_SYM:
5723 return rb_node_sym_string_val(node);
5724 case NODE_LINE:
5725 return rb_node_line_lineno_val(node);
5726 case NODE_STR:
5727 return rb_node_str_string_val(node);
5728 case NODE_FILE:
5729 return rb_node_file_path_val(node);
5730 }
5731 return Qundef;
5732}
5733
5734static int
5735when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5736 LABEL *l1, int only_special_literals, VALUE literals)
5737{
5738 while (vals) {
5739 const NODE *val = RNODE_LIST(vals)->nd_head;
5740 VALUE lit = rb_node_case_when_optimizable_literal(val);
5741
5742 if (UNDEF_P(lit)) {
5743 only_special_literals = 0;
5744 }
5745 else {
5746 cdhash_aset_if_missing(literals, lit, (VALUE)(l1));
5747 }
5748
5749 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5750 debugp_param("nd_lit", get_string_value(val));
5751 lit = get_string_value(val);
5752 ADD_INSN1(cond_seq, val, putobject, lit);
5753 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5754 }
5755 else {
5756 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5757 }
5758
5759 // Emit pattern === target
5760 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5761 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5762 ADD_INSNL(cond_seq, val, branchif, l1);
5763 vals = RNODE_LIST(vals)->nd_next;
5764 }
5765 return only_special_literals;
5766}
5767
5768static int
5769when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5770 LABEL *l1, int only_special_literals, VALUE literals)
5771{
5772 const NODE *line_node = vals;
5773
5774 switch (nd_type(vals)) {
5775 case NODE_LIST:
5776 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5777 return COMPILE_NG;
5778 break;
5779 case NODE_SPLAT:
5780 ADD_INSN (cond_seq, line_node, dup);
5781 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5782 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5783 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5784 ADD_INSNL(cond_seq, line_node, branchif, l1);
5785 break;
5786 case NODE_ARGSCAT:
5787 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5788 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5789 break;
5790 case NODE_ARGSPUSH:
5791 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5792 ADD_INSN (cond_seq, line_node, dup);
5793 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5794 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5795 ADD_INSNL(cond_seq, line_node, branchif, l1);
5796 break;
5797 default:
5798 ADD_INSN (cond_seq, line_node, dup);
5799 CHECK(COMPILE(cond_seq, "when val", vals));
5800 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5801 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5802 ADD_INSNL(cond_seq, line_node, branchif, l1);
5803 break;
5804 }
5805 return COMPILE_OK;
5806}
5807
5808/* Multiple Assignment Handling
5809 *
5810 * In order to handle evaluation of multiple assignment such that the left hand side
5811 * is evaluated before the right hand side, we need to process the left hand side
5812 * and see if there are any attributes that need to be assigned, or constants set
5813 * on explicit objects. If so, we add instructions to evaluate the receiver of
5814 * any assigned attributes or constants before we process the right hand side.
5815 *
5816 * For a multiple assignment such as:
5817 *
5818 * l1.m1, l2[0] = r3, r4
5819 *
5820 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5821 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5822 * On the VM stack, this looks like:
5823 *
5824 * self # putself
5825 * l1 # send
5826 * l1, self # putself
5827 * l1, l2 # send
5828 * l1, l2, 0 # putobject 0
5829 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5830 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5831 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5832 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5833 * l1, l2, 0, [r3, r4], r4, m1= # send
5834 * l1, l2, 0, [r3, r4], r4 # pop
5835 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5836 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5837 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5838 * l1, l2, 0, [r3, r4], r4, []= # send
5839 * l1, l2, 0, [r3, r4], r4 # pop
5840 * l1, l2, 0, [r3, r4] # pop
5841 * [r3, r4], l2, 0, [r3, r4] # setn 3
5842 * [r3, r4], l2, 0 # pop
5843 * [r3, r4], l2 # pop
5844 * [r3, r4] # pop
5845 *
5846 * This is made more complex when you have to handle splats, post args,
5847 * and arbitrary levels of nesting. You need to keep track of the total
5848 * number of attributes to set, and for each attribute, how many entries
5849 * are on the stack before the final attribute, in order to correctly
5850 * calculate the topn value to use to get the receiver of the attribute
5851 * setter method.
5852 *
5853 * A brief description of the VM stack for simple multiple assignment
5854 * with no splat (rhs_array will not be present if the return value of
5855 * the multiple assignment is not needed):
5856 *
5857 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5858 *
5859 * For multiple assignment with splats, while processing the part before
5860 * the splat (splat+post here is an array of the splat and the post arguments):
5861 *
5862 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5863 *
5864 * When processing the splat and post arguments:
5865 *
5866 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5867 *
5868 * When processing nested multiple assignment, existing values on the stack
5869 * are kept. So for:
5870 *
5871 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5872 *
5873 * The stack layout would be the following before processing the nested
5874 * multiple assignment:
5875 *
5876 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5877 *
5878 * In order to handle this correctly, we need to keep track of the nesting
5879 * level for each attribute assignment, as well as the attribute number
5880 * (left hand side attributes are processed left to right) and number of
5881 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5882 * this information.
5883 *
5884 * We also need to track information for the entire multiple assignment, such
5885 * as the total number of arguments, and the current nesting level, to
5886 * handle both nested multiple assignment as well as cases where the
5887 * rhs is not needed. We also need to keep track of all attribute
5888 * assignments in this, which we do using a linked listed. struct masgn_state
5889 * tracks this information.
5890 */
5891
5893 INSN *before_insn;
5894 struct masgn_lhs_node *next;
5895 const NODE *line_node;
5896 int argn;
5897 int num_args;
5898 int lhs_pos;
5899};
5900
5902 struct masgn_lhs_node *first_memo;
5903 struct masgn_lhs_node *last_memo;
5904 int lhs_level;
5905 int num_args;
5906 bool nested;
5907};
5908
5909static int
5910add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5911{
5912 if (!state) {
5913 rb_bug("no masgn_state");
5914 }
5915
5916 struct masgn_lhs_node *memo;
5917 memo = malloc(sizeof(struct masgn_lhs_node));
5918 if (!memo) {
5919 return COMPILE_NG;
5920 }
5921
5922 memo->before_insn = before_insn;
5923 memo->line_node = line_node;
5924 memo->argn = state->num_args + 1;
5925 memo->num_args = argc;
5926 state->num_args += argc;
5927 memo->lhs_pos = lhs_pos;
5928 memo->next = NULL;
5929 if (!state->first_memo) {
5930 state->first_memo = memo;
5931 }
5932 else {
5933 state->last_memo->next = memo;
5934 }
5935 state->last_memo = memo;
5936
5937 return COMPILE_OK;
5938}
5939
5940static 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);
5941
5942static int
5943compile_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)
5944{
5945 switch (nd_type(node)) {
5946 case NODE_ATTRASGN: {
5947 INSN *iobj;
5948 const NODE *line_node = node;
5949
5950 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5951
5952 bool safenav_call = false;
5953 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5954 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5955 ASSUME(iobj);
5956 ELEM_REMOVE(insn_element);
5957 if (!IS_INSN_ID(iobj, send)) {
5958 safenav_call = true;
5959 iobj = (INSN *)get_prev_insn(iobj);
5960 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5961 }
5962 (pre->last = iobj->link.prev)->next = 0;
5963
5964 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5965 int argc = vm_ci_argc(ci) + 1;
5966 ci = ci_argc_set(iseq, ci, argc);
5967 OPERAND_AT(iobj, 0) = (VALUE)ci;
5968 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5969
5970 if (argc == 1) {
5971 ADD_INSN(lhs, line_node, swap);
5972 }
5973 else {
5974 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5975 }
5976
5977 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5978 return COMPILE_NG;
5979 }
5980
5981 iobj->link.prev = lhs->last;
5982 lhs->last->next = &iobj->link;
5983 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5984 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5985 int argc = vm_ci_argc(ci);
5986 bool dupsplat = false;
5987 ci = ci_argc_set(iseq, ci, argc - 1);
5988 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5989 /* Given h[*a], _ = ary
5990 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5991 * `a` must be dupped, because it will be appended with ary[0]
5992 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5993 */
5994 dupsplat = true;
5995 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5996 }
5997 OPERAND_AT(iobj, 0) = (VALUE)ci;
5998 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5999
6000 /* Given: h[*a], h[*b, 1] = ary
6001 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
6002 * so this uses splatarray true on a to dup it before using pushtoarray
6003 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
6004 * so you can use pushtoarray directly
6005 */
6006 int line_no = nd_line(line_node);
6007 int node_id = nd_node_id(line_node);
6008
6009 if (dupsplat) {
6010 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
6011 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
6012 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
6013 }
6014 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
6015 }
6016 if (!safenav_call) {
6017 ADD_INSN(lhs, line_node, pop);
6018 if (argc != 1) {
6019 ADD_INSN(lhs, line_node, pop);
6020 }
6021 }
6022 for (int i=0; i < argc; i++) {
6023 ADD_INSN(post, line_node, pop);
6024 }
6025 break;
6026 }
6027 case NODE_MASGN: {
6028 DECL_ANCHOR(nest_rhs);
6029 INIT_ANCHOR(nest_rhs);
6030 DECL_ANCHOR(nest_lhs);
6031 INIT_ANCHOR(nest_lhs);
6032
6033 int prev_level = state->lhs_level;
6034 bool prev_nested = state->nested;
6035 state->nested = 1;
6036 state->lhs_level = lhs_pos - 1;
6037 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
6038 state->lhs_level = prev_level;
6039 state->nested = prev_nested;
6040
6041 ADD_SEQ(lhs, nest_rhs);
6042 ADD_SEQ(lhs, nest_lhs);
6043 break;
6044 }
6045 case NODE_CDECL:
6046 if (!RNODE_CDECL(node)->nd_vid) {
6047 /* Special handling only needed for expr::C, not for C */
6048 INSN *iobj;
6049
6050 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
6051
6052 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
6053 iobj = (INSN *)insn_element; /* setconstant insn */
6054 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
6055 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
6056 ELEM_REMOVE(insn_element);
6057 pre->last = iobj->link.prev;
6058 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
6059
6060 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
6061 return COMPILE_NG;
6062 }
6063
6064 ADD_INSN(post, node, pop);
6065 break;
6066 }
6067 /* Fallthrough */
6068 default: {
6069 DECL_ANCHOR(anchor);
6070 INIT_ANCHOR(anchor);
6071 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
6072 ELEM_REMOVE(FIRST_ELEMENT(anchor));
6073 ADD_SEQ(lhs, anchor);
6074 }
6075 }
6076
6077 return COMPILE_OK;
6078}
6079
6080static int
6081compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
6082{
6083 if (lhsn) {
6084 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
6085 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
6086 }
6087 return COMPILE_OK;
6088}
6089
6090static int
6091compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6092 const NODE *rhsn, const NODE *orig_lhsn)
6093{
6094 VALUE mem[64];
6095 const int memsize = numberof(mem);
6096 int memindex = 0;
6097 int llen = 0, rlen = 0;
6098 int i;
6099 const NODE *lhsn = orig_lhsn;
6100
6101#define MEMORY(v) { \
6102 int i; \
6103 if (memindex == memsize) return 0; \
6104 for (i=0; i<memindex; i++) { \
6105 if (mem[i] == (v)) return 0; \
6106 } \
6107 mem[memindex++] = (v); \
6108}
6109
6110 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
6111 return 0;
6112 }
6113
6114 while (lhsn) {
6115 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
6116 switch (nd_type(ln)) {
6117 case NODE_LASGN:
6118 case NODE_DASGN:
6119 case NODE_IASGN:
6120 case NODE_CVASGN:
6121 MEMORY(get_nd_vid(ln));
6122 break;
6123 default:
6124 return 0;
6125 }
6126 lhsn = RNODE_LIST(lhsn)->nd_next;
6127 llen++;
6128 }
6129
6130 while (rhsn) {
6131 if (llen <= rlen) {
6132 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
6133 }
6134 else {
6135 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
6136 }
6137 rhsn = RNODE_LIST(rhsn)->nd_next;
6138 rlen++;
6139 }
6140
6141 if (llen > rlen) {
6142 for (i=0; i<llen-rlen; i++) {
6143 ADD_INSN(ret, orig_lhsn, putnil);
6144 }
6145 }
6146
6147 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
6148 return 1;
6149}
6150
6151static int
6152compile_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)
6153{
6154 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
6155 const NODE *splatn = RNODE_MASGN(node)->nd_args;
6156 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
6157 const NODE *lhsn_count = lhsn;
6158 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
6159
6160 int llen = 0;
6161 int lpos = 0;
6162
6163 while (lhsn_count) {
6164 llen++;
6165 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
6166 }
6167 while (lhsn) {
6168 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
6169 lpos++;
6170 lhsn = RNODE_LIST(lhsn)->nd_next;
6171 }
6172
6173 if (lhs_splat) {
6174 if (nd_type_p(splatn, NODE_POSTARG)) {
6175 /*a, b, *r, p1, p2 */
6176 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
6177 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
6178 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
6179 int ppos = 0;
6180 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
6181
6182 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
6183
6184 if (NODE_NAMED_REST_P(restn)) {
6185 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
6186 }
6187 while (postn) {
6188 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
6189 ppos++;
6190 postn = RNODE_LIST(postn)->nd_next;
6191 }
6192 }
6193 else {
6194 /* a, b, *r */
6195 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
6196 }
6197 }
6198
6199 if (!state->nested) {
6200 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
6201 }
6202
6203 if (!popped) {
6204 ADD_INSN(rhs, node, dup);
6205 }
6206 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
6207 return COMPILE_OK;
6208}
6209
6210static int
6211compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6212{
6213 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
6214 struct masgn_state state;
6215 state.lhs_level = popped ? 0 : 1;
6216 state.nested = 0;
6217 state.num_args = 0;
6218 state.first_memo = NULL;
6219 state.last_memo = NULL;
6220
6221 DECL_ANCHOR(pre);
6222 INIT_ANCHOR(pre);
6223 DECL_ANCHOR(rhs);
6224 INIT_ANCHOR(rhs);
6225 DECL_ANCHOR(lhs);
6226 INIT_ANCHOR(lhs);
6227 DECL_ANCHOR(post);
6228 INIT_ANCHOR(post);
6229 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
6230
6231 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
6232 while (memo) {
6233 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
6234 for (int i = 0; i < memo->num_args; i++) {
6235 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
6236 }
6237 tmp_memo = memo->next;
6238 free(memo);
6239 memo = tmp_memo;
6240 }
6241 CHECK(ok);
6242
6243 ADD_SEQ(ret, pre);
6244 ADD_SEQ(ret, rhs);
6245 ADD_SEQ(ret, lhs);
6246 if (!popped && state.num_args >= 1) {
6247 /* make sure rhs array is returned before popping */
6248 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
6249 }
6250 ADD_SEQ(ret, post);
6251 }
6252 return COMPILE_OK;
6253}
6254
6255static VALUE
6256collect_const_segments(rb_iseq_t *iseq, const NODE *node)
6257{
6258 VALUE arr = rb_ary_new();
6259 for (;;) {
6260 switch (nd_type(node)) {
6261 case NODE_CONST:
6262 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
6264 return arr;
6265 case NODE_COLON3:
6266 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
6267 rb_ary_unshift(arr, ID2SYM(idNULL));
6269 return arr;
6270 case NODE_COLON2:
6271 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
6272 node = RNODE_COLON2(node)->nd_head;
6273 break;
6274 default:
6275 return Qfalse;
6276 }
6277 }
6278}
6279
6280static int
6281compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
6282 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
6283{
6284 switch (nd_type(node)) {
6285 case NODE_CONST:
6286 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
6287 ADD_INSN1(body, node, putobject, Qtrue);
6288 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
6289 break;
6290 case NODE_COLON3:
6291 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
6292 ADD_INSN(body, node, pop);
6293 ADD_INSN1(body, node, putobject, rb_cObject);
6294 ADD_INSN1(body, node, putobject, Qtrue);
6295 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
6296 break;
6297 case NODE_COLON2:
6298 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
6299 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
6300 ADD_INSN1(body, node, putobject, Qfalse);
6301 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
6302 break;
6303 default:
6304 CHECK(COMPILE(pref, "const colon2 prefix", node));
6305 break;
6306 }
6307 return COMPILE_OK;
6308}
6309
6310static int
6311cpath_const_p(const NODE *node)
6312{
6313 switch (nd_type(node)) {
6314 case NODE_CONST:
6315 case NODE_COLON3:
6316 return TRUE;
6317 case NODE_COLON2:
6318 if (RNODE_COLON2(node)->nd_head) {
6319 return cpath_const_p(RNODE_COLON2(node)->nd_head);
6320 }
6321 return TRUE;
6322 default:
6323 return FALSE;
6324 }
6325}
6326
6327static int
6328compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
6329{
6330 if (nd_type_p(cpath, NODE_COLON3)) {
6331 /* toplevel class ::Foo */
6332 ADD_INSN1(ret, cpath, putobject, rb_cObject);
6333 return VM_DEFINECLASS_FLAG_SCOPED;
6334 }
6335 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
6336 /* Bar::Foo or expr::Foo */
6337 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
6338 int flags = VM_DEFINECLASS_FLAG_SCOPED;
6339 if (!cpath_const_p(RNODE_COLON2(cpath)->nd_head)) {
6340 flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF;
6341 }
6342 return flags;
6343 }
6344 else {
6345 /* class at cbase Foo */
6346 ADD_INSN1(ret, cpath, putspecialobject,
6347 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
6348 return 0;
6349 }
6350}
6351
6352static inline int
6353private_recv_p(const NODE *node)
6354{
6355 NODE *recv = get_nd_recv(node);
6356 if (recv && nd_type_p(recv, NODE_SELF)) {
6357 return RNODE_SELF(recv)->nd_state != 0;
6358 }
6359 return 0;
6360}
6361
6362static void
6363defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6364 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
6365
6366static int
6367compile_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);
6368
6369static void
6370defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6371 const NODE *const node, LABEL **lfinish, VALUE needstr,
6372 bool keep_result)
6373{
6374 enum defined_type expr_type = DEFINED_NOT_DEFINED;
6375 enum node_type type;
6376 const int line = nd_line(node);
6377 const NODE *line_node = node;
6378
6379 switch (type = nd_type(node)) {
6380
6381 /* easy literals */
6382 case NODE_NIL:
6383 expr_type = DEFINED_NIL;
6384 break;
6385 case NODE_SELF:
6386 expr_type = DEFINED_SELF;
6387 break;
6388 case NODE_TRUE:
6389 expr_type = DEFINED_TRUE;
6390 break;
6391 case NODE_FALSE:
6392 expr_type = DEFINED_FALSE;
6393 break;
6394
6395 case NODE_HASH:
6396 case NODE_LIST:{
6397 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6398
6399 if (vals) {
6400 do {
6401 if (RNODE_LIST(vals)->nd_head) {
6402 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
6403
6404 if (!lfinish[1]) {
6405 lfinish[1] = NEW_LABEL(line);
6406 }
6407 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6408 }
6409 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6410 }
6411 }
6412 /* fall through */
6413 case NODE_STR:
6414 case NODE_SYM:
6415 case NODE_REGX:
6416 case NODE_LINE:
6417 case NODE_FILE:
6418 case NODE_ENCODING:
6419 case NODE_INTEGER:
6420 case NODE_FLOAT:
6421 case NODE_RATIONAL:
6422 case NODE_IMAGINARY:
6423 case NODE_ZLIST:
6424 case NODE_AND:
6425 case NODE_OR:
6426 default:
6427 expr_type = DEFINED_EXPR;
6428 break;
6429
6430 case NODE_SPLAT:
6431 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6432 if (!lfinish[1]) {
6433 lfinish[1] = NEW_LABEL(line);
6434 }
6435 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6436 expr_type = DEFINED_EXPR;
6437 break;
6438
6439 /* variables */
6440 case NODE_LVAR:
6441 case NODE_DVAR:
6442 expr_type = DEFINED_LVAR;
6443 break;
6444
6445#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6446 case NODE_IVAR:
6447 ADD_INSN3(ret, line_node, definedivar,
6448 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6449 return;
6450
6451 case NODE_GVAR:
6452 ADD_INSN(ret, line_node, putnil);
6453 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6454 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6455 return;
6456
6457 case NODE_CVAR:
6458 ADD_INSN(ret, line_node, putnil);
6459 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6460 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6461 return;
6462
6463 case NODE_CONST:
6464 ADD_INSN(ret, line_node, putnil);
6465 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6466 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6467 return;
6468 case NODE_COLON2:
6469 if (!lfinish[1]) {
6470 lfinish[1] = NEW_LABEL(line);
6471 }
6472 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6473 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6474 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6475
6476 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6477 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6478 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6479 }
6480 else {
6481 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6482 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6483 }
6484 return;
6485 case NODE_COLON3:
6486 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6487 ADD_INSN3(ret, line_node, defined,
6488 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6489 return;
6490
6491 /* method dispatch */
6492 case NODE_CALL:
6493 case NODE_OPCALL:
6494 case NODE_VCALL:
6495 case NODE_FCALL:
6496 case NODE_ATTRASGN:{
6497 const int explicit_receiver =
6498 (type == NODE_CALL || type == NODE_OPCALL ||
6499 (type == NODE_ATTRASGN && !private_recv_p(node)));
6500
6501 if (get_nd_args(node) || explicit_receiver) {
6502 if (!lfinish[1]) {
6503 lfinish[1] = NEW_LABEL(line);
6504 }
6505 if (!lfinish[2]) {
6506 lfinish[2] = NEW_LABEL(line);
6507 }
6508 }
6509 if (get_nd_args(node)) {
6510 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6511 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6512 }
6513 if (explicit_receiver) {
6514 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6515 switch (nd_type(get_nd_recv(node))) {
6516 case NODE_CALL:
6517 case NODE_OPCALL:
6518 case NODE_VCALL:
6519 case NODE_FCALL:
6520 case NODE_ATTRASGN:
6521 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6522 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6523 break;
6524 default:
6525 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6526 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6527 break;
6528 }
6529 if (keep_result) {
6530 ADD_INSN(ret, line_node, dup);
6531 }
6532 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6533 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6534 }
6535 else {
6536 ADD_INSN(ret, line_node, putself);
6537 if (keep_result) {
6538 ADD_INSN(ret, line_node, dup);
6539 }
6540 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6541 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6542 }
6543 return;
6544 }
6545
6546 case NODE_YIELD:
6547 ADD_INSN(ret, line_node, putnil);
6548 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6549 PUSH_VAL(DEFINED_YIELD));
6550 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6551 return;
6552
6553 case NODE_BACK_REF:
6554 case NODE_NTH_REF:
6555 ADD_INSN(ret, line_node, putnil);
6556 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6557 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6558 PUSH_VAL(DEFINED_GVAR));
6559 return;
6560
6561 case NODE_SUPER:
6562 case NODE_ZSUPER:
6563 ADD_INSN(ret, line_node, putnil);
6564 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6565 PUSH_VAL(DEFINED_ZSUPER));
6566 return;
6567
6568#undef PUSH_VAL
6569 case NODE_OP_ASGN1:
6570 case NODE_OP_ASGN2:
6571 case NODE_OP_ASGN_OR:
6572 case NODE_OP_ASGN_AND:
6573 case NODE_MASGN:
6574 case NODE_LASGN:
6575 case NODE_DASGN:
6576 case NODE_GASGN:
6577 case NODE_IASGN:
6578 case NODE_CDECL:
6579 case NODE_CVASGN:
6580 case NODE_OP_CDECL:
6581 expr_type = DEFINED_ASGN;
6582 break;
6583 }
6584
6585 RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6586
6587 if (needstr != Qfalse) {
6588 VALUE str = rb_iseq_defined_string(expr_type);
6589 ADD_INSN1(ret, line_node, putobject, str);
6590 }
6591 else {
6592 ADD_INSN1(ret, line_node, putobject, Qtrue);
6593 }
6594}
6595
6596static void
6597build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6598{
6599 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6600 iseq_set_exception_local_table(iseq);
6601}
6602
6603static void
6604defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6605 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6606{
6607 LINK_ELEMENT *lcur = ret->last;
6608 defined_expr0(iseq, ret, node, lfinish, needstr, false);
6609 if (lfinish[1]) {
6610 int line = nd_line(node);
6611 LABEL *lstart = NEW_LABEL(line);
6612 LABEL *lend = NEW_LABEL(line);
6613 const rb_iseq_t *rescue;
6615 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6616 rescue = NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc,
6617 rb_str_concat(rb_str_new2("defined guard in "),
6618 ISEQ_BODY(iseq)->location.label),
6619 ISEQ_TYPE_RESCUE, 0);
6620 lstart->rescued = LABEL_RESCUE_BEG;
6621 lend->rescued = LABEL_RESCUE_END;
6622 APPEND_LABEL(ret, lcur, lstart);
6623 ADD_LABEL(ret, lend);
6624 if (!ignore) {
6625 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6626 }
6627 }
6628}
6629
6630static int
6631compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6632{
6633 const int line = nd_line(node);
6634 const NODE *line_node = node;
6635 if (!RNODE_DEFINED(node)->nd_head) {
6636 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6637 ADD_INSN1(ret, line_node, putobject, str);
6638 }
6639 else {
6640 LABEL *lfinish[3];
6641 LINK_ELEMENT *last = ret->last;
6642 lfinish[0] = NEW_LABEL(line);
6643 lfinish[1] = 0;
6644 lfinish[2] = 0;
6645 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6646 if (lfinish[1]) {
6647 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6648 ADD_INSN(ret, line_node, swap);
6649 if (lfinish[2]) {
6650 ADD_LABEL(ret, lfinish[2]);
6651 }
6652 ADD_INSN(ret, line_node, pop);
6653 ADD_LABEL(ret, lfinish[1]);
6654 }
6655 ADD_LABEL(ret, lfinish[0]);
6656 }
6657 return COMPILE_OK;
6658}
6659
6660static VALUE
6661make_name_for_block(const rb_iseq_t *orig_iseq)
6662{
6663 int level = 1;
6664 const rb_iseq_t *iseq = orig_iseq;
6665
6666 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6667 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6668 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6669 level++;
6670 }
6671 iseq = ISEQ_BODY(iseq)->parent_iseq;
6672 }
6673 }
6674
6675 if (level == 1) {
6676 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6677 }
6678 else {
6679 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6680 }
6681}
6682
6683static void
6684push_ensure_entry(rb_iseq_t *iseq,
6686 struct ensure_range *er, const void *const node)
6687{
6688 enl->ensure_node = node;
6689 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6690 enl->erange = er;
6691 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6692}
6693
6694static void
6695add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6696 LABEL *lstart, LABEL *lend)
6697{
6698 struct ensure_range *ne =
6699 compile_data_alloc_type(iseq, struct ensure_range);
6700
6701 while (erange->next != 0) {
6702 erange = erange->next;
6703 }
6704 ne->next = 0;
6705 ne->begin = lend;
6706 ne->end = erange->end;
6707 erange->end = lstart;
6708
6709 erange->next = ne;
6710}
6711
6712static bool
6713can_add_ensure_iseq(const rb_iseq_t *iseq)
6714{
6716 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6717 while (e) {
6718 if (e->ensure_node) return false;
6719 e = e->prev;
6720 }
6721 }
6722 return true;
6723}
6724
6725static void
6726add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6727{
6728 RUBY_ASSERT(can_add_ensure_iseq(iseq));
6729
6731 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6732 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6733 DECL_ANCHOR(ensure);
6734
6735 INIT_ANCHOR(ensure);
6736 while (enlp) {
6737 if (enlp->erange != NULL) {
6738 DECL_ANCHOR(ensure_part);
6739 LABEL *lstart = NEW_LABEL(0);
6740 LABEL *lend = NEW_LABEL(0);
6741 INIT_ANCHOR(ensure_part);
6742
6743 add_ensure_range(iseq, enlp->erange, lstart, lend);
6744
6745 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6746 ADD_LABEL(ensure_part, lstart);
6747 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6748 ADD_LABEL(ensure_part, lend);
6749 ADD_SEQ(ensure, ensure_part);
6750 }
6751 else {
6752 if (!is_return) {
6753 break;
6754 }
6755 }
6756 enlp = enlp->prev;
6757 }
6758 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6759 ADD_SEQ(ret, ensure);
6760}
6761
6762#if RUBY_DEBUG
6763static int
6764check_keyword(const NODE *node)
6765{
6766 /* This check is essentially a code clone of compile_keyword_arg. */
6767
6768 if (nd_type_p(node, NODE_LIST)) {
6769 while (RNODE_LIST(node)->nd_next) {
6770 node = RNODE_LIST(node)->nd_next;
6771 }
6772 node = RNODE_LIST(node)->nd_head;
6773 }
6774
6775 return keyword_node_p(node);
6776}
6777#endif
6778
6779static bool
6780keyword_node_single_splat_p(NODE *kwnode)
6781{
6782 RUBY_ASSERT(keyword_node_p(kwnode));
6783
6784 NODE *node = RNODE_HASH(kwnode)->nd_head;
6785 return RNODE_LIST(node)->nd_head == NULL &&
6786 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6787}
6788
6789static void
6790compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6791 NODE *kwnode, unsigned int *flag_ptr)
6792{
6793 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6794 ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6795 ADD_INSN1(args, argn, newhash, INT2FIX(0));
6796 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6797 ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6798}
6799
6800#define SPLATARRAY_FALSE 0
6801#define SPLATARRAY_TRUE 1
6802#define DUP_SINGLE_KW_SPLAT 2
6803
6804static int
6805setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6806 unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6807{
6808 if (!argn) return 0;
6809
6810 NODE *kwnode = NULL;
6811
6812 switch (nd_type(argn)) {
6813 case NODE_LIST: {
6814 // f(x, y, z)
6815 int len = compile_args(iseq, args, argn, &kwnode);
6816 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6817
6818 if (kwnode) {
6819 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6820 len -= 1;
6821 }
6822 else {
6823 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6824 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6825 }
6826 else {
6827 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6828 }
6829 }
6830 }
6831
6832 return len;
6833 }
6834 case NODE_SPLAT: {
6835 // f(*a)
6836 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6837 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6838 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6839 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6840 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6841 return 1;
6842 }
6843 case NODE_ARGSCAT: {
6844 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6845 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6846 bool args_pushed = false;
6847
6848 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6849 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6850 if (kwnode) rest_len--;
6851 ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6852 args_pushed = true;
6853 }
6854 else {
6855 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6856 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6857 }
6858
6859 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6860 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6861 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6862 argc += 1;
6863 }
6864 else if (!args_pushed) {
6865 ADD_INSN(args, argn, concattoarray);
6866 }
6867
6868 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6869 if (kwnode) {
6870 // kwsplat
6871 *flag_ptr |= VM_CALL_KW_SPLAT;
6872 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6873 argc += 1;
6874 }
6875
6876 return argc;
6877 }
6878 case NODE_ARGSPUSH: {
6879 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6880 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6881
6882 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6883 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6884 if (kwnode) rest_len--;
6885 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6886 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6887 }
6888 else {
6889 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6890 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6891 }
6892 else {
6893 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6894 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6895 }
6896 }
6897
6898 if (kwnode) {
6899 // f(*a, k:1)
6900 *flag_ptr |= VM_CALL_KW_SPLAT;
6901 if (!keyword_node_single_splat_p(kwnode)) {
6902 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6903 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6904 }
6905 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6906 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6907 }
6908 else {
6909 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6910 }
6911 argc += 1;
6912 }
6913
6914 return argc;
6915 }
6916 default: {
6917 UNKNOWN_NODE("setup_arg", argn, Qnil);
6918 }
6919 }
6920}
6921
6922static void
6923setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6924{
6925 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6926 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6927 }
6928}
6929
6930static bool
6931setup_args_dup_rest_p(const NODE *argn)
6932{
6933 switch(nd_type(argn)) {
6934 case NODE_LVAR:
6935 case NODE_DVAR:
6936 case NODE_GVAR:
6937 case NODE_IVAR:
6938 case NODE_CVAR:
6939 case NODE_CONST:
6940 case NODE_COLON3:
6941 case NODE_INTEGER:
6942 case NODE_FLOAT:
6943 case NODE_RATIONAL:
6944 case NODE_IMAGINARY:
6945 case NODE_STR:
6946 case NODE_SYM:
6947 case NODE_REGX:
6948 case NODE_SELF:
6949 case NODE_NIL:
6950 case NODE_TRUE:
6951 case NODE_FALSE:
6952 case NODE_LAMBDA:
6953 case NODE_NTH_REF:
6954 case NODE_BACK_REF:
6955 return false;
6956 case NODE_COLON2:
6957 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6958 case NODE_LIST:
6959 while (argn) {
6960 if (setup_args_dup_rest_p(RNODE_LIST(argn)->nd_head)) {
6961 return true;
6962 }
6963 argn = RNODE_LIST(argn)->nd_next;
6964 }
6965 return false;
6966 default:
6967 return true;
6968 }
6969}
6970
6971static VALUE
6972setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6973 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6974{
6975 VALUE ret;
6976 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6977
6978 if (argn) {
6979 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6980 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6981
6982 if (check_arg) {
6983 switch(nd_type(check_arg)) {
6984 case(NODE_SPLAT):
6985 // avoid caller side array allocation for f(*arg)
6986 dup_rest = SPLATARRAY_FALSE;
6987 break;
6988 case(NODE_ARGSCAT):
6989 // avoid caller side array allocation for f(1, *arg)
6990 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6991 break;
6992 case(NODE_ARGSPUSH):
6993 // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
6994 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6995 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6996 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6997 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6998 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6999
7000 if (dup_rest == SPLATARRAY_FALSE) {
7001 // require allocation for keyword key/value/splat that may modify splatted argument
7002 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
7003 while (node) {
7004 NODE *key_node = RNODE_LIST(node)->nd_head;
7005 if (key_node && setup_args_dup_rest_p(key_node)) {
7006 dup_rest = SPLATARRAY_TRUE;
7007 break;
7008 }
7009
7010 node = RNODE_LIST(node)->nd_next;
7011 NODE *value_node = RNODE_LIST(node)->nd_head;
7012 if (setup_args_dup_rest_p(value_node)) {
7013 dup_rest = SPLATARRAY_TRUE;
7014 break;
7015 }
7016
7017 node = RNODE_LIST(node)->nd_next;
7018 }
7019 }
7020 break;
7021 default:
7022 break;
7023 }
7024 }
7025
7026 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
7027 // for block pass that may modify splatted argument, dup rest and kwrest if given
7028 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
7029 }
7030 }
7031 initial_dup_rest = dup_rest;
7032
7033 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
7034 DECL_ANCHOR(arg_block);
7035 INIT_ANCHOR(arg_block);
7036
7037 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
7038 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
7039
7040 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
7041 const NODE * arg_node =
7042 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
7043
7044 int argc = 0;
7045
7046 // Only compile leading args:
7047 // foo(x, y, ...)
7048 // ^^^^
7049 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
7050 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
7051 }
7052
7053 *flag |= VM_CALL_FORWARDING;
7054
7055 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
7056 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
7057 return INT2FIX(argc);
7058 }
7059 else {
7060 *flag |= VM_CALL_ARGS_BLOCKARG;
7061
7062 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
7063 }
7064
7065 if (LIST_INSN_SIZE_ONE(arg_block)) {
7066 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
7067 if (IS_INSN(elem)) {
7068 INSN *iobj = (INSN *)elem;
7069 if (iobj->insn_id == BIN(getblockparam)) {
7070 iobj->insn_id = BIN(getblockparamproxy);
7071 }
7072 }
7073 }
7074 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
7075 ADD_SEQ(args, arg_block);
7076 }
7077 else {
7078 ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
7079 }
7080 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
7081 return ret;
7082}
7083
7084static void
7085build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
7086{
7087 const NODE *body = ptr;
7088 int line = nd_line(body);
7089 VALUE argc = INT2FIX(0);
7090 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
7091
7092 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7093 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
7094 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
7095 iseq_set_local_table(iseq, 0, 0);
7096}
7097
7098static void
7099compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
7100{
7101 const NODE *vars;
7102 LINK_ELEMENT *last;
7103 int line = nd_line(node);
7104 const NODE *line_node = node;
7105 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
7106
7107#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
7108 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
7109#else
7110 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
7111#endif
7112 ADD_INSN(ret, line_node, dup);
7113 ADD_INSNL(ret, line_node, branchunless, fail_label);
7114
7115 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
7116 INSN *cap;
7117 if (RNODE_BLOCK(vars)->nd_next) {
7118 ADD_INSN(ret, line_node, dup);
7119 }
7120 last = ret->last;
7121 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
7122 last = last->next; /* putobject :var */
7123 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
7124 NULL, INT2FIX(0), NULL);
7125 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
7126#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
7127 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
7128 /* only one name */
7129 DECL_ANCHOR(nom);
7130
7131 INIT_ANCHOR(nom);
7132 ADD_INSNL(nom, line_node, jump, end_label);
7133 ADD_LABEL(nom, fail_label);
7134# if 0 /* $~ must be MatchData or nil */
7135 ADD_INSN(nom, line_node, pop);
7136 ADD_INSN(nom, line_node, putnil);
7137# endif
7138 ADD_LABEL(nom, end_label);
7139 (nom->last->next = cap->link.next)->prev = nom->last;
7140 (cap->link.next = nom->anchor.next)->prev = &cap->link;
7141 return;
7142 }
7143#endif
7144 }
7145 ADD_INSNL(ret, line_node, jump, end_label);
7146 ADD_LABEL(ret, fail_label);
7147 ADD_INSN(ret, line_node, pop);
7148 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
7149 last = ret->last;
7150 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
7151 last = last->next; /* putobject :var */
7152 ((INSN*)last)->insn_id = BIN(putnil);
7153 ((INSN*)last)->operand_size = 0;
7154 }
7155 ADD_LABEL(ret, end_label);
7156}
7157
7158static int
7159optimizable_range_item_p(const NODE *n)
7160{
7161 if (!n) return FALSE;
7162 switch (nd_type(n)) {
7163 case NODE_LINE:
7164 return TRUE;
7165 case NODE_INTEGER:
7166 return TRUE;
7167 case NODE_NIL:
7168 return TRUE;
7169 default:
7170 return FALSE;
7171 }
7172}
7173
7174static VALUE
7175optimized_range_item(const NODE *n)
7176{
7177 switch (nd_type(n)) {
7178 case NODE_LINE:
7179 return rb_node_line_lineno_val(n);
7180 case NODE_INTEGER:
7181 return rb_node_integer_literal_val(n);
7182 case NODE_FLOAT:
7183 return rb_node_float_literal_val(n);
7184 case NODE_RATIONAL:
7185 return rb_node_rational_literal_val(n);
7186 case NODE_IMAGINARY:
7187 return rb_node_imaginary_literal_val(n);
7188 case NODE_NIL:
7189 return Qnil;
7190 default:
7191 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
7192 }
7193}
7194
7195static int
7196compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
7197{
7198 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
7199 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
7200
7201 const int line = nd_line(node);
7202 const NODE *line_node = node;
7203 DECL_ANCHOR(cond_seq);
7204 LABEL *then_label, *else_label, *end_label;
7205 VALUE branches = Qfalse;
7206
7207 INIT_ANCHOR(cond_seq);
7208 then_label = NEW_LABEL(line);
7209 else_label = NEW_LABEL(line);
7210 end_label = 0;
7211
7212 NODE *cond = RNODE_IF(node)->nd_cond;
7213 if (nd_type(cond) == NODE_BLOCK) {
7214 cond = RNODE_BLOCK(cond)->nd_head;
7215 }
7216
7217 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
7218 ADD_SEQ(ret, cond_seq);
7219
7220 if (then_label->refcnt && else_label->refcnt) {
7221 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
7222 }
7223
7224 if (then_label->refcnt) {
7225 ADD_LABEL(ret, then_label);
7226
7227 DECL_ANCHOR(then_seq);
7228 INIT_ANCHOR(then_seq);
7229 CHECK(COMPILE_(then_seq, "then", node_body, popped));
7230
7231 if (else_label->refcnt) {
7232 const NODE *const coverage_node = node_body ? node_body : node;
7233 add_trace_branch_coverage(
7234 iseq,
7235 ret,
7236 nd_code_loc(coverage_node),
7237 nd_node_id(coverage_node),
7238 0,
7239 type == NODE_IF ? "then" : "else",
7240 branches);
7241 end_label = NEW_LABEL(line);
7242 ADD_INSNL(then_seq, line_node, jump, end_label);
7243 if (!popped) {
7244 ADD_INSN(then_seq, line_node, pop);
7245 }
7246 }
7247 ADD_SEQ(ret, then_seq);
7248 }
7249
7250 if (else_label->refcnt) {
7251 ADD_LABEL(ret, else_label);
7252
7253 DECL_ANCHOR(else_seq);
7254 INIT_ANCHOR(else_seq);
7255 CHECK(COMPILE_(else_seq, "else", node_else, popped));
7256
7257 if (then_label->refcnt) {
7258 const NODE *const coverage_node = node_else ? node_else : node;
7259 add_trace_branch_coverage(
7260 iseq,
7261 ret,
7262 nd_code_loc(coverage_node),
7263 nd_node_id(coverage_node),
7264 1,
7265 type == NODE_IF ? "else" : "then",
7266 branches);
7267 }
7268 ADD_SEQ(ret, else_seq);
7269 }
7270
7271 if (end_label) {
7272 ADD_LABEL(ret, end_label);
7273 }
7274
7275 return COMPILE_OK;
7276}
7277
7278static int
7279compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7280{
7281 const NODE *vals;
7282 const NODE *node = orig_node;
7283 LABEL *endlabel, *elselabel;
7284 DECL_ANCHOR(head);
7285 DECL_ANCHOR(body_seq);
7286 DECL_ANCHOR(cond_seq);
7287 int only_special_literals = 1;
7288 VALUE literals = cdhash_new(0);
7289 int line;
7290 enum node_type type;
7291 const NODE *line_node;
7292 VALUE branches = Qfalse;
7293 int branch_id = 0;
7294
7295 INIT_ANCHOR(head);
7296 INIT_ANCHOR(body_seq);
7297 INIT_ANCHOR(cond_seq);
7298
7299 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
7300
7301 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), "case");
7302
7303 node = RNODE_CASE(node)->nd_body;
7304 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
7305 type = nd_type(node);
7306 line = nd_line(node);
7307 line_node = node;
7308
7309 endlabel = NEW_LABEL(line);
7310 elselabel = NEW_LABEL(line);
7311
7312 ADD_SEQ(ret, head); /* case VAL */
7313
7314 while (type == NODE_WHEN) {
7315 LABEL *l1;
7316
7317 l1 = NEW_LABEL(line);
7318 ADD_LABEL(body_seq, l1);
7319 ADD_INSN(body_seq, line_node, pop);
7320
7321 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7322 add_trace_branch_coverage(
7323 iseq,
7324 body_seq,
7325 nd_code_loc(coverage_node),
7326 nd_node_id(coverage_node),
7327 branch_id++,
7328 "when",
7329 branches);
7330
7331 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
7332 ADD_INSNL(body_seq, line_node, jump, endlabel);
7333
7334 vals = RNODE_WHEN(node)->nd_head;
7335 if (vals) {
7336 switch (nd_type(vals)) {
7337 case NODE_LIST:
7338 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
7339 if (only_special_literals < 0) return COMPILE_NG;
7340 break;
7341 case NODE_SPLAT:
7342 case NODE_ARGSCAT:
7343 case NODE_ARGSPUSH:
7344 only_special_literals = 0;
7345 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
7346 break;
7347 default:
7348 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
7349 }
7350 }
7351 else {
7352 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
7353 }
7354
7355 node = RNODE_WHEN(node)->nd_next;
7356 if (!node) {
7357 break;
7358 }
7359 type = nd_type(node);
7360 line = nd_line(node);
7361 line_node = node;
7362 }
7363 /* else */
7364 if (node) {
7365 ADD_LABEL(cond_seq, elselabel);
7366 ADD_INSN(cond_seq, line_node, pop);
7367 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
7368 CHECK(COMPILE_(cond_seq, "else", node, popped));
7369 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7370 }
7371 else {
7372 debugs("== else (implicit)\n");
7373 ADD_LABEL(cond_seq, elselabel);
7374 ADD_INSN(cond_seq, orig_node, pop);
7375 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
7376 if (!popped) {
7377 ADD_INSN(cond_seq, orig_node, putnil);
7378 }
7379 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7380 }
7381
7382 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7383 ADD_INSN(ret, orig_node, dup);
7384 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
7385 RB_OBJ_WRITTEN(iseq, Qundef, literals);
7386 LABEL_REF(elselabel);
7387 }
7388
7389 ADD_SEQ(ret, cond_seq);
7390 ADD_SEQ(ret, body_seq);
7391 ADD_LABEL(ret, endlabel);
7392 return COMPILE_OK;
7393}
7394
7395static int
7396compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7397{
7398 const NODE *vals;
7399 const NODE *val;
7400 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
7401 LABEL *endlabel;
7402 DECL_ANCHOR(body_seq);
7403 VALUE branches = Qfalse;
7404 int branch_id = 0;
7405
7406 branches = decl_branch_base(iseq, nd_node_id(orig_node), nd_code_loc(orig_node), "case");
7407
7408 INIT_ANCHOR(body_seq);
7409 endlabel = NEW_LABEL(nd_line(node));
7410
7411 while (node && nd_type_p(node, NODE_WHEN)) {
7412 const int line = nd_line(node);
7413 LABEL *l1 = NEW_LABEL(line);
7414 ADD_LABEL(body_seq, l1);
7415
7416 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7417 add_trace_branch_coverage(
7418 iseq,
7419 body_seq,
7420 nd_code_loc(coverage_node),
7421 nd_node_id(coverage_node),
7422 branch_id++,
7423 "when",
7424 branches);
7425
7426 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7427 ADD_INSNL(body_seq, node, jump, endlabel);
7428
7429 vals = RNODE_WHEN(node)->nd_head;
7430 if (!vals) {
7431 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7432 }
7433 switch (nd_type(vals)) {
7434 case NODE_LIST:
7435 while (vals) {
7436 LABEL *lnext;
7437 val = RNODE_LIST(vals)->nd_head;
7438 lnext = NEW_LABEL(nd_line(val));
7439 debug_compile("== when2\n", (void)0);
7440 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7441 ADD_LABEL(ret, lnext);
7442 vals = RNODE_LIST(vals)->nd_next;
7443 }
7444 break;
7445 case NODE_SPLAT:
7446 case NODE_ARGSCAT:
7447 case NODE_ARGSPUSH:
7448 ADD_INSN(ret, vals, putnil);
7449 CHECK(COMPILE(ret, "when2/cond splat", vals));
7450 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7451 ADD_INSNL(ret, vals, branchif, l1);
7452 break;
7453 default:
7454 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7455 }
7456 node = RNODE_WHEN(node)->nd_next;
7457 }
7458 /* else */
7459 const NODE *const coverage_node = node ? node : orig_node;
7460 add_trace_branch_coverage(
7461 iseq,
7462 ret,
7463 nd_code_loc(coverage_node),
7464 nd_node_id(coverage_node),
7465 branch_id,
7466 "else",
7467 branches);
7468 CHECK(COMPILE_(ret, "else", node, popped));
7469 ADD_INSNL(ret, orig_node, jump, endlabel);
7470
7471 ADD_SEQ(ret, body_seq);
7472 ADD_LABEL(ret, endlabel);
7473 return COMPILE_OK;
7474}
7475
7476static 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);
7477
7478static 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);
7479static 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);
7480static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7481static 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);
7482static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7483
7484#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7485#define CASE3_BI_OFFSET_ERROR_STRING 1
7486#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7487#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7488#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7489
7490static int
7491iseq_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)
7492{
7493 const int line = nd_line(node);
7494 const NODE *line_node = node;
7495
7496 switch (nd_type(node)) {
7497 case NODE_ARYPTN: {
7498 /*
7499 * if pattern.use_rest_num?
7500 * rest_num = 0
7501 * end
7502 * if pattern.has_constant_node?
7503 * unless pattern.constant === obj
7504 * goto match_failed
7505 * end
7506 * end
7507 * unless obj.respond_to?(:deconstruct)
7508 * goto match_failed
7509 * end
7510 * d = obj.deconstruct
7511 * unless Array === d
7512 * goto type_error
7513 * end
7514 * min_argc = pattern.pre_args_num + pattern.post_args_num
7515 * if pattern.has_rest_arg?
7516 * unless d.length >= min_argc
7517 * goto match_failed
7518 * end
7519 * else
7520 * unless d.length == min_argc
7521 * goto match_failed
7522 * end
7523 * end
7524 * pattern.pre_args_num.each do |i|
7525 * unless pattern.pre_args[i].match?(d[i])
7526 * goto match_failed
7527 * end
7528 * end
7529 * if pattern.use_rest_num?
7530 * rest_num = d.length - min_argc
7531 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7532 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7533 * goto match_failed
7534 * end
7535 * end
7536 * end
7537 * pattern.post_args_num.each do |i|
7538 * j = pattern.pre_args_num + i
7539 * j += rest_num
7540 * unless pattern.post_args[i].match?(d[j])
7541 * goto match_failed
7542 * end
7543 * end
7544 * goto matched
7545 * type_error:
7546 * FrozenCore.raise TypeError
7547 * match_failed:
7548 * goto unmatched
7549 */
7550 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7551 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7552 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7553
7554 const int min_argc = pre_args_num + post_args_num;
7555 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7556 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7557
7558 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7559 int i;
7560 match_failed = NEW_LABEL(line);
7561 type_error = NEW_LABEL(line);
7562 deconstruct = NEW_LABEL(line);
7563 deconstructed = NEW_LABEL(line);
7564
7565 if (use_rest_num) {
7566 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7567 ADD_INSN(ret, line_node, swap);
7568 if (base_index) {
7569 base_index++;
7570 }
7571 }
7572
7573 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7574
7575 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7576
7577 ADD_INSN(ret, line_node, dup);
7578 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7579 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7580 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7581 if (in_single_pattern) {
7582 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7583 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7584 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7585 INT2FIX(min_argc), base_index + 1 /* (1) */));
7586 }
7587 ADD_INSNL(ret, line_node, branchunless, match_failed);
7588
7589 for (i = 0; i < pre_args_num; i++) {
7590 ADD_INSN(ret, line_node, dup);
7591 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7592 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7593 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));
7594 args = RNODE_LIST(args)->nd_next;
7595 }
7596
7597 if (RNODE_ARYPTN(node)->rest_arg) {
7598 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7599 ADD_INSN(ret, line_node, dup);
7600 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7601 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7602 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7603 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7604 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7605 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
7606 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7607
7608 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));
7609 }
7610 else {
7611 if (post_args_num > 0) {
7612 ADD_INSN(ret, line_node, dup);
7613 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7614 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7615 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7616 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7617 ADD_INSN(ret, line_node, pop);
7618 }
7619 }
7620 }
7621
7622 args = RNODE_ARYPTN(node)->post_args;
7623 for (i = 0; i < post_args_num; i++) {
7624 ADD_INSN(ret, line_node, dup);
7625
7626 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7627 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7628 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7629
7630 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7631 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));
7632 args = RNODE_LIST(args)->nd_next;
7633 }
7634
7635 ADD_INSN(ret, line_node, pop);
7636 if (use_rest_num) {
7637 ADD_INSN(ret, line_node, pop);
7638 }
7639 ADD_INSNL(ret, line_node, jump, matched);
7640 ADD_INSN(ret, line_node, putnil);
7641 if (use_rest_num) {
7642 ADD_INSN(ret, line_node, putnil);
7643 }
7644
7645 ADD_LABEL(ret, type_error);
7646 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7647 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7648 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7649 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7650 ADD_INSN(ret, line_node, pop);
7651
7652 ADD_LABEL(ret, match_failed);
7653 ADD_INSN(ret, line_node, pop);
7654 if (use_rest_num) {
7655 ADD_INSN(ret, line_node, pop);
7656 }
7657 ADD_INSNL(ret, line_node, jump, unmatched);
7658
7659 break;
7660 }
7661 case NODE_FNDPTN: {
7662 /*
7663 * if pattern.has_constant_node?
7664 * unless pattern.constant === obj
7665 * goto match_failed
7666 * end
7667 * end
7668 * unless obj.respond_to?(:deconstruct)
7669 * goto match_failed
7670 * end
7671 * d = obj.deconstruct
7672 * unless Array === d
7673 * goto type_error
7674 * end
7675 * unless d.length >= pattern.args_num
7676 * goto match_failed
7677 * end
7678 *
7679 * begin
7680 * len = d.length
7681 * limit = d.length - pattern.args_num
7682 * i = 0
7683 * while i <= limit
7684 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7685 * if pattern.has_pre_rest_arg_id
7686 * unless pattern.pre_rest_arg.match?(d[0, i])
7687 * goto find_failed
7688 * end
7689 * end
7690 * if pattern.has_post_rest_arg_id
7691 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7692 * goto find_failed
7693 * end
7694 * end
7695 * goto find_succeeded
7696 * end
7697 * i+=1
7698 * end
7699 * find_failed:
7700 * goto match_failed
7701 * find_succeeded:
7702 * end
7703 *
7704 * goto matched
7705 * type_error:
7706 * FrozenCore.raise TypeError
7707 * match_failed:
7708 * goto unmatched
7709 */
7710 const NODE *args = RNODE_FNDPTN(node)->args;
7711 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7712
7713 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7714 match_failed = NEW_LABEL(line);
7715 type_error = NEW_LABEL(line);
7716 deconstruct = NEW_LABEL(line);
7717 deconstructed = NEW_LABEL(line);
7718
7719 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7720
7721 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7722
7723 ADD_INSN(ret, line_node, dup);
7724 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7725 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7726 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7727 if (in_single_pattern) {
7728 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) */));
7729 }
7730 ADD_INSNL(ret, line_node, branchunless, match_failed);
7731
7732 {
7733 LABEL *while_begin = NEW_LABEL(nd_line(node));
7734 LABEL *next_loop = NEW_LABEL(nd_line(node));
7735 LABEL *find_succeeded = NEW_LABEL(line);
7736 LABEL *find_failed = NEW_LABEL(nd_line(node));
7737 int j;
7738
7739 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7740 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7741
7742 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7743 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7744 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7745
7746 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7747
7748 ADD_LABEL(ret, while_begin);
7749
7750 ADD_INSN(ret, line_node, dup);
7751 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7752 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7753 ADD_INSNL(ret, line_node, branchunless, find_failed);
7754
7755 for (j = 0; j < args_num; j++) {
7756 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7757 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7758 if (j != 0) {
7759 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7760 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7761 }
7762 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7763
7764 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));
7765 args = RNODE_LIST(args)->nd_next;
7766 }
7767
7768 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7769 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7770 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7771 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7772 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7773 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));
7774 }
7775 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7776 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7777 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7778 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7779 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7780 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7781 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7782 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));
7783 }
7784 ADD_INSNL(ret, line_node, jump, find_succeeded);
7785
7786 ADD_LABEL(ret, next_loop);
7787 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7788 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7789 ADD_INSNL(ret, line_node, jump, while_begin);
7790
7791 ADD_LABEL(ret, find_failed);
7792 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7793 if (in_single_pattern) {
7794 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7795 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7796 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7797 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7798 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7799
7800 ADD_INSN1(ret, line_node, putobject, Qfalse);
7801 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7802
7803 ADD_INSN(ret, line_node, pop);
7804 ADD_INSN(ret, line_node, pop);
7805 }
7806 ADD_INSNL(ret, line_node, jump, match_failed);
7807 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7808
7809 ADD_LABEL(ret, find_succeeded);
7810 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7811 }
7812
7813 ADD_INSN(ret, line_node, pop);
7814 ADD_INSNL(ret, line_node, jump, matched);
7815 ADD_INSN(ret, line_node, putnil);
7816
7817 ADD_LABEL(ret, type_error);
7818 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7819 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7820 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7821 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7822 ADD_INSN(ret, line_node, pop);
7823
7824 ADD_LABEL(ret, match_failed);
7825 ADD_INSN(ret, line_node, pop);
7826 ADD_INSNL(ret, line_node, jump, unmatched);
7827
7828 break;
7829 }
7830 case NODE_HSHPTN: {
7831 /*
7832 * keys = nil
7833 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7834 * keys = pattern.kw_args_node.keys
7835 * end
7836 * if pattern.has_constant_node?
7837 * unless pattern.constant === obj
7838 * goto match_failed
7839 * end
7840 * end
7841 * unless obj.respond_to?(:deconstruct_keys)
7842 * goto match_failed
7843 * end
7844 * d = obj.deconstruct_keys(keys)
7845 * unless Hash === d
7846 * goto type_error
7847 * end
7848 * if pattern.has_kw_rest_arg_node?
7849 * d = d.dup
7850 * end
7851 * if pattern.has_kw_args_node?
7852 * pattern.kw_args_node.each |k,|
7853 * unless d.key?(k)
7854 * goto match_failed
7855 * end
7856 * end
7857 * pattern.kw_args_node.each |k, pat|
7858 * if pattern.has_kw_rest_arg_node?
7859 * unless pat.match?(d.delete(k))
7860 * goto match_failed
7861 * end
7862 * else
7863 * unless pat.match?(d[k])
7864 * goto match_failed
7865 * end
7866 * end
7867 * end
7868 * else
7869 * unless d.empty?
7870 * goto match_failed
7871 * end
7872 * end
7873 * if pattern.has_kw_rest_arg_node?
7874 * if pattern.no_rest_keyword?
7875 * unless d.empty?
7876 * goto match_failed
7877 * end
7878 * else
7879 * unless pattern.kw_rest_arg_node.match?(d)
7880 * goto match_failed
7881 * end
7882 * end
7883 * end
7884 * goto matched
7885 * type_error:
7886 * FrozenCore.raise TypeError
7887 * match_failed:
7888 * goto unmatched
7889 */
7890 LABEL *match_failed, *type_error;
7891 VALUE keys = Qnil;
7892
7893 match_failed = NEW_LABEL(line);
7894 type_error = NEW_LABEL(line);
7895
7896 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7897 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7898 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7899 while (kw_args) {
7900 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7901 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7902 }
7903 }
7904
7905 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7906
7907 ADD_INSN(ret, line_node, dup);
7908 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7909 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7910 if (in_single_pattern) {
7911 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7912 }
7913 ADD_INSNL(ret, line_node, branchunless, match_failed);
7914
7915 if (NIL_P(keys)) {
7916 ADD_INSN(ret, line_node, putnil);
7917 }
7918 else {
7920 ADD_INSN1(ret, line_node, duparray, keys);
7921 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7922 }
7923 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7924
7925 ADD_INSN(ret, line_node, dup);
7926 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7927 ADD_INSNL(ret, line_node, branchunless, type_error);
7928
7929 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7930 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7931 }
7932
7933 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7934 int i;
7935 int keys_num;
7936 const NODE *args;
7937 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7938 if (args) {
7939 DECL_ANCHOR(match_values);
7940 INIT_ANCHOR(match_values);
7941 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7942 for (i = 0; i < keys_num; i++) {
7943 NODE *key_node = RNODE_LIST(args)->nd_head;
7944 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7945 VALUE key = get_symbol_value(iseq, key_node);
7946
7947 ADD_INSN(ret, line_node, dup);
7948 ADD_INSN1(ret, line_node, putobject, key);
7949 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7950 if (in_single_pattern) {
7951 LABEL *match_succeeded;
7952 match_succeeded = NEW_LABEL(line);
7953
7954 ADD_INSN(ret, line_node, dup);
7955 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7956
7957 VALUE str = rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key));
7958 ADD_INSN1(ret, line_node, putobject, RB_OBJ_SET_SHAREABLE(str)); // (4)
7959 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7960 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7961 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7962 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7963 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7964 ADD_INSN1(ret, line_node, putobject, key); // (7)
7965 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7966
7967 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7968
7969 ADD_LABEL(ret, match_succeeded);
7970 }
7971 ADD_INSNL(ret, line_node, branchunless, match_failed);
7972
7973 ADD_INSN(match_values, line_node, dup);
7974 ADD_INSN1(match_values, line_node, putobject, key);
7975 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7976 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7977 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7978 }
7979 ADD_SEQ(ret, match_values);
7980 }
7981 }
7982 else {
7983 ADD_INSN(ret, line_node, dup);
7984 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7985 if (in_single_pattern) {
7986 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7987 }
7988 ADD_INSNL(ret, line_node, branchunless, match_failed);
7989 }
7990
7991 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7992 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7993 ADD_INSN(ret, line_node, dup);
7994 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7995 if (in_single_pattern) {
7996 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7997 }
7998 ADD_INSNL(ret, line_node, branchunless, match_failed);
7999 }
8000 else {
8001 ADD_INSN(ret, line_node, dup); // (11)
8002 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));
8003 }
8004 }
8005
8006 ADD_INSN(ret, line_node, pop);
8007 ADD_INSNL(ret, line_node, jump, matched);
8008 ADD_INSN(ret, line_node, putnil);
8009
8010 ADD_LABEL(ret, type_error);
8011 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8012 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
8013 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
8014 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
8015 ADD_INSN(ret, line_node, pop);
8016
8017 ADD_LABEL(ret, match_failed);
8018 ADD_INSN(ret, line_node, pop);
8019 ADD_INSNL(ret, line_node, jump, unmatched);
8020 break;
8021 }
8022 case NODE_SYM:
8023 case NODE_REGX:
8024 case NODE_LINE:
8025 case NODE_INTEGER:
8026 case NODE_FLOAT:
8027 case NODE_RATIONAL:
8028 case NODE_IMAGINARY:
8029 case NODE_FILE:
8030 case NODE_ENCODING:
8031 case NODE_STR:
8032 case NODE_XSTR:
8033 case NODE_DSTR:
8034 case NODE_DSYM:
8035 case NODE_DREGX:
8036 case NODE_LIST:
8037 case NODE_ZLIST:
8038 case NODE_LAMBDA:
8039 case NODE_DOT2:
8040 case NODE_DOT3:
8041 case NODE_CONST:
8042 case NODE_LVAR:
8043 case NODE_DVAR:
8044 case NODE_IVAR:
8045 case NODE_CVAR:
8046 case NODE_GVAR:
8047 case NODE_TRUE:
8048 case NODE_FALSE:
8049 case NODE_SELF:
8050 case NODE_NIL:
8051 case NODE_COLON2:
8052 case NODE_COLON3:
8053 case NODE_BEGIN:
8054 case NODE_BLOCK:
8055 case NODE_ONCE:
8056 CHECK(COMPILE(ret, "case in literal", node)); // (1)
8057 if (in_single_pattern) {
8058 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
8059 }
8060 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
8061 if (in_single_pattern) {
8062 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
8063 }
8064 ADD_INSNL(ret, line_node, branchif, matched);
8065 ADD_INSNL(ret, line_node, jump, unmatched);
8066 break;
8067 case NODE_LASGN: {
8068 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
8069 ID id = RNODE_LASGN(node)->nd_vid;
8070 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8071
8072 if (in_alt_pattern) {
8073 const char *name = rb_id2name(id);
8074 if (name && strlen(name) > 0 && name[0] != '_') {
8075 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
8076 rb_id2str(id));
8077 return COMPILE_NG;
8078 }
8079 }
8080
8081 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8082 ADD_INSNL(ret, line_node, jump, matched);
8083 break;
8084 }
8085 case NODE_DASGN: {
8086 int idx, lv, ls;
8087 ID id = RNODE_DASGN(node)->nd_vid;
8088
8089 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
8090
8091 if (in_alt_pattern) {
8092 const char *name = rb_id2name(id);
8093 if (name && strlen(name) > 0 && name[0] != '_') {
8094 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
8095 rb_id2str(id));
8096 return COMPILE_NG;
8097 }
8098 }
8099
8100 if (idx < 0) {
8101 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
8102 rb_id2str(id));
8103 return COMPILE_NG;
8104 }
8105 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
8106 ADD_INSNL(ret, line_node, jump, matched);
8107 break;
8108 }
8109 case NODE_IF:
8110 case NODE_UNLESS: {
8111 LABEL *match_failed;
8112 match_failed = unmatched;
8113 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
8114 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
8115 if (in_single_pattern) {
8116 LABEL *match_succeeded;
8117 match_succeeded = NEW_LABEL(line);
8118
8119 ADD_INSN(ret, line_node, dup);
8120 if (nd_type_p(node, NODE_IF)) {
8121 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8122 }
8123 else {
8124 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
8125 }
8126
8127 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
8128 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8129 ADD_INSN1(ret, line_node, putobject, Qfalse);
8130 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8131
8132 ADD_INSN(ret, line_node, pop);
8133 ADD_INSN(ret, line_node, pop);
8134
8135 ADD_LABEL(ret, match_succeeded);
8136 }
8137 if (nd_type_p(node, NODE_IF)) {
8138 ADD_INSNL(ret, line_node, branchunless, match_failed);
8139 }
8140 else {
8141 ADD_INSNL(ret, line_node, branchif, match_failed);
8142 }
8143 ADD_INSNL(ret, line_node, jump, matched);
8144 break;
8145 }
8146 case NODE_HASH: {
8147 NODE *n;
8148 LABEL *match_failed;
8149 match_failed = NEW_LABEL(line);
8150
8151 n = RNODE_HASH(node)->nd_head;
8152 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
8153 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8154 return COMPILE_NG;
8155 }
8156
8157 ADD_INSN(ret, line_node, dup); // (1)
8158 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));
8159 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));
8160 ADD_INSN(ret, line_node, putnil);
8161
8162 ADD_LABEL(ret, match_failed);
8163 ADD_INSN(ret, line_node, pop);
8164 ADD_INSNL(ret, line_node, jump, unmatched);
8165 break;
8166 }
8167 case NODE_OR: {
8168 LABEL *match_succeeded, *fin;
8169 match_succeeded = NEW_LABEL(line);
8170 fin = NEW_LABEL(line);
8171
8172 ADD_INSN(ret, line_node, dup); // (1)
8173 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));
8174 ADD_LABEL(ret, match_succeeded);
8175 ADD_INSN(ret, line_node, pop);
8176 ADD_INSNL(ret, line_node, jump, matched);
8177 ADD_INSN(ret, line_node, putnil);
8178 ADD_LABEL(ret, fin);
8179 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
8180 break;
8181 }
8182 default:
8183 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
8184 }
8185 return COMPILE_OK;
8186}
8187
8188static int
8189iseq_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)
8190{
8191 LABEL *fin = NEW_LABEL(nd_line(node));
8192 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
8193 ADD_LABEL(ret, fin);
8194 return COMPILE_OK;
8195}
8196
8197static int
8198iseq_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)
8199{
8200 const NODE *line_node = node;
8201
8202 if (RNODE_ARYPTN(node)->nd_pconst) {
8203 ADD_INSN(ret, line_node, dup); // (1)
8204 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
8205 if (in_single_pattern) {
8206 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
8207 }
8208 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
8209 if (in_single_pattern) {
8210 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
8211 }
8212 ADD_INSNL(ret, line_node, branchunless, match_failed);
8213 }
8214 return COMPILE_OK;
8215}
8216
8217
8218static int
8219iseq_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)
8220{
8221 const NODE *line_node = node;
8222
8223 // NOTE: this optimization allows us to re-use the #deconstruct value
8224 // (or its absence).
8225 if (use_deconstructed_cache) {
8226 // If value is nil then we haven't tried to deconstruct
8227 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8228 ADD_INSNL(ret, line_node, branchnil, deconstruct);
8229
8230 // If false then the value is not deconstructable
8231 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8232 ADD_INSNL(ret, line_node, branchunless, match_failed);
8233
8234 // Drop value, add deconstructed to the stack and jump
8235 ADD_INSN(ret, line_node, pop); // (1)
8236 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
8237 ADD_INSNL(ret, line_node, jump, deconstructed);
8238 }
8239 else {
8240 ADD_INSNL(ret, line_node, jump, deconstruct);
8241 }
8242
8243 ADD_LABEL(ret, deconstruct);
8244 ADD_INSN(ret, line_node, dup);
8245 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
8246 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
8247
8248 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
8249 if (use_deconstructed_cache) {
8250 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
8251 }
8252
8253 if (in_single_pattern) {
8254 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
8255 }
8256
8257 ADD_INSNL(ret, line_node, branchunless, match_failed);
8258
8259 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
8260
8261 // Cache the result (if it's cacheable - currently, only top-level array patterns)
8262 if (use_deconstructed_cache) {
8263 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8264 }
8265
8266 ADD_INSN(ret, line_node, dup);
8267 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
8268 ADD_INSNL(ret, line_node, branchunless, type_error);
8269
8270 ADD_LABEL(ret, deconstructed);
8271
8272 return COMPILE_OK;
8273}
8274
8275static int
8276iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
8277{
8278 /*
8279 * if match_succeeded?
8280 * goto match_succeeded
8281 * end
8282 * error_string = FrozenCore.sprintf(errmsg, matchee)
8283 * key_error_p = false
8284 * match_succeeded:
8285 */
8286 const int line = nd_line(node);
8287 const NODE *line_node = node;
8288 LABEL *match_succeeded = NEW_LABEL(line);
8289
8290 ADD_INSN(ret, line_node, dup);
8291 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8292
8293 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8294 ADD_INSN1(ret, line_node, putobject, errmsg);
8295 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8296 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
8297 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8298
8299 ADD_INSN1(ret, line_node, putobject, Qfalse);
8300 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8301
8302 ADD_INSN(ret, line_node, pop);
8303 ADD_INSN(ret, line_node, pop);
8304 ADD_LABEL(ret, match_succeeded);
8305
8306 return COMPILE_OK;
8307}
8308
8309static int
8310iseq_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)
8311{
8312 /*
8313 * if match_succeeded?
8314 * goto match_succeeded
8315 * end
8316 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
8317 * key_error_p = false
8318 * match_succeeded:
8319 */
8320 const int line = nd_line(node);
8321 const NODE *line_node = node;
8322 LABEL *match_succeeded = NEW_LABEL(line);
8323
8324 ADD_INSN(ret, line_node, dup);
8325 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8326
8327 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8328 ADD_INSN1(ret, line_node, putobject, errmsg);
8329 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8330 ADD_INSN(ret, line_node, dup);
8331 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
8332 ADD_INSN1(ret, line_node, putobject, pattern_length);
8333 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
8334 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8335
8336 ADD_INSN1(ret, line_node, putobject, Qfalse);
8337 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
8338
8339 ADD_INSN(ret, line_node, pop);
8340 ADD_INSN(ret, line_node, pop);
8341 ADD_LABEL(ret, match_succeeded);
8342
8343 return COMPILE_OK;
8344}
8345
8346static int
8347iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
8348{
8349 /*
8350 * if match_succeeded?
8351 * goto match_succeeded
8352 * end
8353 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
8354 * key_error_p = false
8355 * match_succeeded:
8356 */
8357 const int line = nd_line(node);
8358 const NODE *line_node = node;
8359 LABEL *match_succeeded = NEW_LABEL(line);
8360
8361 ADD_INSN(ret, line_node, dup);
8362 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8363
8364 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8365 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
8366 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8367 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
8368 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
8369 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8370
8371 ADD_INSN1(ret, line_node, putobject, Qfalse);
8372 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8373
8374 ADD_INSN(ret, line_node, pop);
8375 ADD_INSN(ret, line_node, pop);
8376
8377 ADD_LABEL(ret, match_succeeded);
8378 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
8379 ADD_INSN(ret, line_node, pop);
8380 ADD_INSN(ret, line_node, pop);
8381
8382 return COMPILE_OK;
8383}
8384
8385static int
8386compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
8387{
8388 const NODE *pattern;
8389 const NODE *node = orig_node;
8390 LABEL *endlabel, *elselabel;
8391 DECL_ANCHOR(head);
8392 DECL_ANCHOR(body_seq);
8393 DECL_ANCHOR(cond_seq);
8394 int line;
8395 enum node_type type;
8396 const NODE *line_node;
8397 VALUE branches = 0;
8398 int branch_id = 0;
8399 bool single_pattern;
8400
8401 INIT_ANCHOR(head);
8402 INIT_ANCHOR(body_seq);
8403 INIT_ANCHOR(cond_seq);
8404
8405 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), "case");
8406
8407 node = RNODE_CASE3(node)->nd_body;
8408 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
8409 type = nd_type(node);
8410 line = nd_line(node);
8411 line_node = node;
8412 single_pattern = !RNODE_IN(node)->nd_next;
8413
8414 endlabel = NEW_LABEL(line);
8415 elselabel = NEW_LABEL(line);
8416
8417 if (single_pattern) {
8418 /* allocate stack for ... */
8419 ADD_INSN(head, line_node, putnil); /* key_error_key */
8420 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
8421 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
8422 ADD_INSN(head, line_node, putnil); /* error_string */
8423 }
8424 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
8425
8426 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8427
8428 ADD_SEQ(ret, head); /* case VAL */
8429
8430 while (type == NODE_IN) {
8431 LABEL *l1;
8432
8433 if (branch_id) {
8434 ADD_INSN(body_seq, line_node, putnil);
8435 }
8436 l1 = NEW_LABEL(line);
8437 ADD_LABEL(body_seq, l1);
8438 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8439
8440 const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8441 add_trace_branch_coverage(
8442 iseq,
8443 body_seq,
8444 nd_code_loc(coverage_node),
8445 nd_node_id(coverage_node),
8446 branch_id++,
8447 "in",
8448 branches);
8449
8450 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8451 ADD_INSNL(body_seq, line_node, jump, endlabel);
8452
8453 pattern = RNODE_IN(node)->nd_head;
8454 if (pattern) {
8455 int pat_line = nd_line(pattern);
8456 LABEL *next_pat = NEW_LABEL(pat_line);
8457 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8458 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8459 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8460 ADD_LABEL(cond_seq, next_pat);
8461 LABEL_UNREMOVABLE(next_pat);
8462 }
8463 else {
8464 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8465 return COMPILE_NG;
8466 }
8467
8468 node = RNODE_IN(node)->nd_next;
8469 if (!node) {
8470 break;
8471 }
8472 type = nd_type(node);
8473 line = nd_line(node);
8474 line_node = node;
8475 }
8476 /* else */
8477 if (node) {
8478 ADD_LABEL(cond_seq, elselabel);
8479 ADD_INSN(cond_seq, line_node, pop);
8480 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8481 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8482 CHECK(COMPILE_(cond_seq, "else", node, popped));
8483 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8484 ADD_INSN(cond_seq, line_node, putnil);
8485 if (popped) {
8486 ADD_INSN(cond_seq, line_node, putnil);
8487 }
8488 }
8489 else {
8490 debugs("== else (implicit)\n");
8491 ADD_LABEL(cond_seq, elselabel);
8492 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8493 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8494
8495 if (single_pattern) {
8496 /*
8497 * if key_error_p
8498 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8499 * else
8500 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8501 * end
8502 */
8503 LABEL *key_error, *fin;
8504 struct rb_callinfo_kwarg *kw_arg;
8505
8506 key_error = NEW_LABEL(line);
8507 fin = NEW_LABEL(line);
8508
8509 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8510 kw_arg->references = 0;
8511 kw_arg->keyword_len = 2;
8512 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8513 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8514
8515 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8516 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8517 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8518 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8519 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8520 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8521 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8522 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8523 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8524 ADD_INSNL(cond_seq, orig_node, jump, fin);
8525
8526 ADD_LABEL(cond_seq, key_error);
8527 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8528 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8529 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8530 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8531 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8532 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8533 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8534 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8535 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8536 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8537
8538 ADD_LABEL(cond_seq, fin);
8539 }
8540 else {
8541 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8542 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8543 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8544 }
8545 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8546 if (!popped) {
8547 ADD_INSN(cond_seq, orig_node, putnil);
8548 }
8549 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8550 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8551 if (popped) {
8552 ADD_INSN(cond_seq, line_node, putnil);
8553 }
8554 }
8555
8556 ADD_SEQ(ret, cond_seq);
8557 ADD_SEQ(ret, body_seq);
8558 ADD_LABEL(ret, endlabel);
8559 return COMPILE_OK;
8560}
8561
8562#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8563#undef CASE3_BI_OFFSET_ERROR_STRING
8564#undef CASE3_BI_OFFSET_KEY_ERROR_P
8565#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8566#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8567
8568static int
8569compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8570{
8571 const int line = (int)nd_line(node);
8572 const NODE *line_node = node;
8573
8574 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8575 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8576 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8577 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8578 VALUE branches = Qfalse;
8579
8581
8582 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8583 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8584 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8585 LABEL *end_label = NEW_LABEL(line);
8586 LABEL *adjust_label = NEW_LABEL(line);
8587
8588 LABEL *next_catch_label = NEW_LABEL(line);
8589 LABEL *tmp_label = NULL;
8590
8591 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8592 push_ensure_entry(iseq, &enl, NULL, NULL);
8593
8594 if (RNODE_WHILE(node)->nd_state == 1) {
8595 ADD_INSNL(ret, line_node, jump, next_label);
8596 }
8597 else {
8598 tmp_label = NEW_LABEL(line);
8599 ADD_INSNL(ret, line_node, jump, tmp_label);
8600 }
8601 ADD_LABEL(ret, adjust_label);
8602 ADD_INSN(ret, line_node, putnil);
8603 ADD_LABEL(ret, next_catch_label);
8604 ADD_INSN(ret, line_node, pop);
8605 ADD_INSNL(ret, line_node, jump, next_label);
8606 if (tmp_label) ADD_LABEL(ret, tmp_label);
8607
8608 ADD_LABEL(ret, redo_label);
8609 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8610
8611 const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8612 add_trace_branch_coverage(
8613 iseq,
8614 ret,
8615 nd_code_loc(coverage_node),
8616 nd_node_id(coverage_node),
8617 0,
8618 "body",
8619 branches);
8620
8621 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8622 ADD_LABEL(ret, next_label); /* next */
8623
8624 if (type == NODE_WHILE) {
8625 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8626 redo_label, end_label));
8627 }
8628 else {
8629 /* until */
8630 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8631 end_label, redo_label));
8632 }
8633
8634 ADD_LABEL(ret, end_label);
8635 ADD_ADJUST_RESTORE(ret, adjust_label);
8636
8637 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8638 /* ADD_INSN(ret, line_node, putundef); */
8639 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8640 return COMPILE_NG;
8641 }
8642 else {
8643 ADD_INSN(ret, line_node, putnil);
8644 }
8645
8646 ADD_LABEL(ret, break_label); /* break */
8647
8648 if (popped) {
8649 ADD_INSN(ret, line_node, pop);
8650 }
8651
8652 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8653 break_label);
8654 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8655 next_catch_label);
8656 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8657 ISEQ_COMPILE_DATA(iseq)->redo_label);
8658
8659 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8660 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8661 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8662 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8663 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8664 return COMPILE_OK;
8665}
8666
8667static int
8668compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8669{
8670 const int line = nd_line(node);
8671 const NODE *line_node = node;
8672 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8673 LABEL *retry_label = NEW_LABEL(line);
8674 LABEL *retry_end_l = NEW_LABEL(line);
8675 const rb_iseq_t *child_iseq;
8676
8677 ADD_LABEL(ret, retry_label);
8678 if (nd_type_p(node, NODE_FOR)) {
8679 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8680
8681 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8682 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8683 ISEQ_TYPE_BLOCK, line);
8684 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8685 }
8686 else {
8687 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8688 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8689 ISEQ_TYPE_BLOCK, line);
8690 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8691 }
8692
8693 {
8694 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8695 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8696 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8697 //
8698 // Normally, "send" instruction is at the last.
8699 // However, qcall under branch coverage measurement adds some instructions after the "send".
8700 //
8701 // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8702 INSN *iobj;
8703 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8704 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8705 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8706 iobj = (INSN*) get_prev_insn(iobj);
8707 }
8708 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8709
8710 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8711 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8712 if (&iobj->link == LAST_ELEMENT(ret)) {
8713 ret->last = (LINK_ELEMENT*) retry_end_l;
8714 }
8715 }
8716
8717 if (popped) {
8718 ADD_INSN(ret, line_node, pop);
8719 }
8720
8721 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8722
8723 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8724 return COMPILE_OK;
8725}
8726
8727static int
8728compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8729{
8730 /* massign to var in "for"
8731 * (args.length == 1 && Array.try_convert(args[0])) || args
8732 */
8733 const NODE *line_node = node;
8734 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8735 LABEL *not_single = NEW_LABEL(nd_line(var));
8736 LABEL *not_ary = NEW_LABEL(nd_line(var));
8737 CHECK(COMPILE(ret, "for var", var));
8738 ADD_INSN(ret, line_node, dup);
8739 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8740 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8741 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8742 ADD_INSNL(ret, line_node, branchunless, not_single);
8743 ADD_INSN(ret, line_node, dup);
8744 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8745 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8746 ADD_INSN1(ret, line_node, putobject, rb_cArray);
8747 ADD_INSN(ret, line_node, swap);
8748 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8749 ADD_INSN(ret, line_node, dup);
8750 ADD_INSNL(ret, line_node, branchunless, not_ary);
8751 ADD_INSN(ret, line_node, swap);
8752 ADD_LABEL(ret, not_ary);
8753 ADD_INSN(ret, line_node, pop);
8754 ADD_LABEL(ret, not_single);
8755 return COMPILE_OK;
8756}
8757
8758static int
8759compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8760{
8761 const NODE *line_node = node;
8762 unsigned long throw_flag = 0;
8763
8764 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8765 /* while/until */
8766 LABEL *splabel = NEW_LABEL(0);
8767 ADD_LABEL(ret, splabel);
8768 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8769 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8770 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8771 add_ensure_iseq(ret, iseq, 0);
8772 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8773 ADD_ADJUST_RESTORE(ret, splabel);
8774
8775 if (!popped) {
8776 ADD_INSN(ret, line_node, putnil);
8777 }
8778 }
8779 else {
8780 const rb_iseq_t *ip = iseq;
8781
8782 while (ip) {
8783 if (!ISEQ_COMPILE_DATA(ip)) {
8784 ip = 0;
8785 break;
8786 }
8787
8788 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8789 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8790 }
8791 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8792 throw_flag = 0;
8793 }
8794 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8795 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8796 return COMPILE_NG;
8797 }
8798 else {
8799 ip = ISEQ_BODY(ip)->parent_iseq;
8800 continue;
8801 }
8802
8803 /* escape from block */
8804 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8805 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8806 if (popped) {
8807 ADD_INSN(ret, line_node, pop);
8808 }
8809 return COMPILE_OK;
8810 }
8811 COMPILE_ERROR(ERROR_ARGS "Invalid break");
8812 return COMPILE_NG;
8813 }
8814 return COMPILE_OK;
8815}
8816
8817static int
8818compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8819{
8820 const NODE *line_node = node;
8821 unsigned long throw_flag = 0;
8822
8823 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8824 LABEL *splabel = NEW_LABEL(0);
8825 debugs("next in while loop\n");
8826 ADD_LABEL(ret, splabel);
8827 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8828 add_ensure_iseq(ret, iseq, 0);
8829 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8830 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8831 ADD_ADJUST_RESTORE(ret, splabel);
8832 if (!popped) {
8833 ADD_INSN(ret, line_node, putnil);
8834 }
8835 }
8836 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8837 LABEL *splabel = NEW_LABEL(0);
8838 debugs("next in block\n");
8839 ADD_LABEL(ret, splabel);
8840 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8841 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8842 add_ensure_iseq(ret, iseq, 0);
8843 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8844 ADD_ADJUST_RESTORE(ret, splabel);
8845
8846 if (!popped) {
8847 ADD_INSN(ret, line_node, putnil);
8848 }
8849 }
8850 else {
8851 const rb_iseq_t *ip = iseq;
8852
8853 while (ip) {
8854 if (!ISEQ_COMPILE_DATA(ip)) {
8855 ip = 0;
8856 break;
8857 }
8858
8859 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8860 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8861 /* while loop */
8862 break;
8863 }
8864 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8865 break;
8866 }
8867 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8868 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8869 return COMPILE_NG;
8870 }
8871
8872 ip = ISEQ_BODY(ip)->parent_iseq;
8873 }
8874 if (ip != 0) {
8875 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8876 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8877
8878 if (popped) {
8879 ADD_INSN(ret, line_node, pop);
8880 }
8881 }
8882 else {
8883 COMPILE_ERROR(ERROR_ARGS "Invalid next");
8884 return COMPILE_NG;
8885 }
8886 }
8887 return COMPILE_OK;
8888}
8889
8890static int
8891compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8892{
8893 const NODE *line_node = node;
8894
8895 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8896 LABEL *splabel = NEW_LABEL(0);
8897 debugs("redo in while");
8898 ADD_LABEL(ret, splabel);
8899 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8900 add_ensure_iseq(ret, iseq, 0);
8901 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8902 ADD_ADJUST_RESTORE(ret, splabel);
8903 if (!popped) {
8904 ADD_INSN(ret, line_node, putnil);
8905 }
8906 }
8907 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8908 LABEL *splabel = NEW_LABEL(0);
8909
8910 debugs("redo in block");
8911 ADD_LABEL(ret, splabel);
8912 add_ensure_iseq(ret, iseq, 0);
8913 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8914 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8915 ADD_ADJUST_RESTORE(ret, splabel);
8916
8917 if (!popped) {
8918 ADD_INSN(ret, line_node, putnil);
8919 }
8920 }
8921 else {
8922 const rb_iseq_t *ip = iseq;
8923
8924 while (ip) {
8925 if (!ISEQ_COMPILE_DATA(ip)) {
8926 ip = 0;
8927 break;
8928 }
8929
8930 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8931 break;
8932 }
8933 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8934 break;
8935 }
8936 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8937 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8938 return COMPILE_NG;
8939 }
8940
8941 ip = ISEQ_BODY(ip)->parent_iseq;
8942 }
8943 if (ip != 0) {
8944 ADD_INSN(ret, line_node, putnil);
8945 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8946
8947 if (popped) {
8948 ADD_INSN(ret, line_node, pop);
8949 }
8950 }
8951 else {
8952 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8953 return COMPILE_NG;
8954 }
8955 }
8956 return COMPILE_OK;
8957}
8958
8959static int
8960compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8961{
8962 const NODE *line_node = node;
8963
8964 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8965 ADD_INSN(ret, line_node, putnil);
8966 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8967
8968 if (popped) {
8969 ADD_INSN(ret, line_node, pop);
8970 }
8971 }
8972 else {
8973 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8974 return COMPILE_NG;
8975 }
8976 return COMPILE_OK;
8977}
8978
8979static int
8980compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8981{
8982 const int line = nd_line(node);
8983 const NODE *line_node = node;
8984 LABEL *lstart = NEW_LABEL(line);
8985 LABEL *lend = NEW_LABEL(line);
8986 LABEL *lcont = NEW_LABEL(line);
8987 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8988 rb_str_concat(rb_str_new2("rescue in "),
8989 ISEQ_BODY(iseq)->location.label),
8990 ISEQ_TYPE_RESCUE, line);
8991
8992 lstart->rescued = LABEL_RESCUE_BEG;
8993 lend->rescued = LABEL_RESCUE_END;
8994 ADD_LABEL(ret, lstart);
8995
8996 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8997 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8998 {
8999 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
9000 }
9001 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
9002
9003 ADD_LABEL(ret, lend);
9004 if (RNODE_RESCUE(node)->nd_else) {
9005 ADD_INSN(ret, line_node, pop);
9006 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
9007 }
9008 ADD_INSN(ret, line_node, nop);
9009 ADD_LABEL(ret, lcont);
9010
9011 if (popped) {
9012 ADD_INSN(ret, line_node, pop);
9013 }
9014
9015 /* register catch entry */
9016 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
9017 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
9018 return COMPILE_OK;
9019}
9020
9021static int
9022compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9023{
9024 const int line = nd_line(node);
9025 const NODE *line_node = node;
9026 const NODE *resq = node;
9027 const NODE *narg;
9028 LABEL *label_miss, *label_hit;
9029
9030 while (resq) {
9031 label_miss = NEW_LABEL(line);
9032 label_hit = NEW_LABEL(line);
9033
9034 narg = RNODE_RESBODY(resq)->nd_args;
9035 if (narg) {
9036 switch (nd_type(narg)) {
9037 case NODE_LIST:
9038 while (narg) {
9039 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
9040 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
9041 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
9042 ADD_INSNL(ret, line_node, branchif, label_hit);
9043 narg = RNODE_LIST(narg)->nd_next;
9044 }
9045 break;
9046 case NODE_SPLAT:
9047 case NODE_ARGSCAT:
9048 case NODE_ARGSPUSH:
9049 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
9050 CHECK(COMPILE(ret, "rescue/cond splat", narg));
9051 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
9052 ADD_INSNL(ret, line_node, branchif, label_hit);
9053 break;
9054 default:
9055 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
9056 }
9057 }
9058 else {
9059 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
9060 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
9061 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
9062 ADD_INSNL(ret, line_node, branchif, label_hit);
9063 }
9064 ADD_INSNL(ret, line_node, jump, label_miss);
9065 ADD_LABEL(ret, label_hit);
9066 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
9067
9068 if (RNODE_RESBODY(resq)->nd_exc_var) {
9069 CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
9070 }
9071
9072 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) {
9073 // empty body
9074 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
9075 }
9076 else {
9077 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
9078 }
9079
9080 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
9081 ADD_INSN(ret, line_node, nop);
9082 }
9083 ADD_INSN(ret, line_node, leave);
9084 ADD_LABEL(ret, label_miss);
9085 resq = RNODE_RESBODY(resq)->nd_next;
9086 }
9087 return COMPILE_OK;
9088}
9089
9090static int
9091compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9092{
9093 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
9094 const NODE *line_node = node;
9095 DECL_ANCHOR(ensr);
9096 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
9097 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
9098 ISEQ_TYPE_ENSURE, line);
9099 LABEL *lstart = NEW_LABEL(line);
9100 LABEL *lend = NEW_LABEL(line);
9101 LABEL *lcont = NEW_LABEL(line);
9102 LINK_ELEMENT *last;
9103 int last_leave = 0;
9104 struct ensure_range er;
9106 struct ensure_range *erange;
9107
9108 INIT_ANCHOR(ensr);
9109 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
9110 last = ensr->last;
9111 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
9112
9113 er.begin = lstart;
9114 er.end = lend;
9115 er.next = 0;
9116 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
9117
9118 ADD_LABEL(ret, lstart);
9119 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
9120 ADD_LABEL(ret, lend);
9121 ADD_SEQ(ret, ensr);
9122 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
9123 ADD_LABEL(ret, lcont);
9124 if (last_leave) ADD_INSN(ret, line_node, pop);
9125
9126 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
9127 if (lstart->link.next != &lend->link) {
9128 while (erange) {
9129 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
9130 ensure, lcont);
9131 erange = erange->next;
9132 }
9133 }
9134
9135 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
9136 return COMPILE_OK;
9137}
9138
9139static int
9140compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9141{
9142 const NODE *line_node = node;
9143
9144 if (iseq) {
9145 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
9146 const rb_iseq_t *is = iseq;
9147 enum rb_iseq_type t = type;
9148 const NODE *retval = RNODE_RETURN(node)->nd_stts;
9149 LABEL *splabel = 0;
9150
9151 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
9152 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
9153 t = ISEQ_BODY(is)->type;
9154 }
9155 switch (t) {
9156 case ISEQ_TYPE_TOP:
9157 case ISEQ_TYPE_MAIN:
9158 if (retval) {
9159 rb_warn("argument of top-level return is ignored");
9160 }
9161 if (is == iseq) {
9162 /* plain top-level, leave directly */
9163 type = ISEQ_TYPE_METHOD;
9164 }
9165 break;
9166 default:
9167 break;
9168 }
9169
9170 if (type == ISEQ_TYPE_METHOD) {
9171 splabel = NEW_LABEL(0);
9172 ADD_LABEL(ret, splabel);
9173 ADD_ADJUST(ret, line_node, 0);
9174 }
9175
9176 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
9177
9178 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
9179 add_ensure_iseq(ret, iseq, 1);
9180 ADD_TRACE(ret, RUBY_EVENT_RETURN);
9181 ADD_INSN(ret, line_node, leave);
9182 ADD_ADJUST_RESTORE(ret, splabel);
9183
9184 if (!popped) {
9185 ADD_INSN(ret, line_node, putnil);
9186 }
9187 }
9188 else {
9189 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
9190 if (popped) {
9191 ADD_INSN(ret, line_node, pop);
9192 }
9193 }
9194 }
9195 return COMPILE_OK;
9196}
9197
9198static bool
9199drop_unreachable_return(LINK_ANCHOR *ret)
9200{
9201 LINK_ELEMENT *i = ret->last, *last;
9202 if (!i) return false;
9203 if (IS_TRACE(i)) i = i->prev;
9204 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
9205 last = i = i->prev;
9206 if (IS_ADJUST(i)) i = i->prev;
9207 if (!IS_INSN(i)) return false;
9208 switch (INSN_OF(i)) {
9209 case BIN(leave):
9210 case BIN(jump):
9211 break;
9212 default:
9213 return false;
9214 }
9215 (ret->last = last->prev)->next = NULL;
9216 return true;
9217}
9218
9219static int
9220compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9221{
9222 CHECK(COMPILE_(ret, "nd_body", node, popped));
9223
9224 if (!popped && !all_string_result_p(node)) {
9225 const NODE *line_node = node;
9226 const unsigned int flag = VM_CALL_FCALL;
9227
9228 // Note, this dup could be removed if we are willing to change anytostring. It pops
9229 // two VALUEs off the stack when it could work by replacing the top most VALUE.
9230 ADD_INSN(ret, line_node, dup);
9231 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
9232 ADD_INSN(ret, line_node, anytostring);
9233 }
9234 return COMPILE_OK;
9235}
9236
9237static void
9238compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
9239{
9240 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
9241
9242 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
9243 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
9244}
9245
9246static LABEL *
9247qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
9248{
9249 LABEL *else_label = NEW_LABEL(nd_line(line_node));
9250 VALUE br = 0;
9251
9252 br = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), "&.");
9253 *branches = br;
9254 ADD_INSN(recv, line_node, dup);
9255 ADD_INSNL(recv, line_node, branchnil, else_label);
9256 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
9257 return else_label;
9258}
9259
9260static void
9261qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
9262{
9263 LABEL *end_label;
9264 if (!else_label) return;
9265 end_label = NEW_LABEL(nd_line(line_node));
9266 ADD_INSNL(ret, line_node, jump, end_label);
9267 ADD_LABEL(ret, else_label);
9268 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
9269 ADD_LABEL(ret, end_label);
9270}
9271
9272static int
9273compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
9274{
9275 /* optimization shortcut
9276 * "literal".freeze -> opt_str_freeze("literal")
9277 */
9278 if (get_nd_recv(node) &&
9279 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
9280 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
9281 get_nd_args(node) == NULL &&
9282 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
9283 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
9284 VALUE str = get_string_value(get_nd_recv(node));
9285 if (get_node_call_nd_mid(node) == idUMinus) {
9286 ADD_INSN2(ret, line_node, opt_str_uminus, str,
9287 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
9288 }
9289 else {
9290 ADD_INSN2(ret, line_node, opt_str_freeze, str,
9291 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
9292 }
9293 RB_OBJ_WRITTEN(iseq, Qundef, str);
9294 if (popped) {
9295 ADD_INSN(ret, line_node, pop);
9296 }
9297 return TRUE;
9298 }
9299 return FALSE;
9300}
9301
9302static int
9303iseq_has_builtin_function_table(const rb_iseq_t *iseq)
9304{
9305 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
9306}
9307
9308static const struct rb_builtin_function *
9309iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
9310{
9311 int i;
9312 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
9313 for (i=0; table[i].index != -1; i++) {
9314 if (strcmp(table[i].name, name) == 0) {
9315 return &table[i];
9316 }
9317 }
9318 return NULL;
9319}
9320
9321static const char *
9322iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
9323{
9324 const char *name = rb_id2name(mid);
9325 static const char prefix[] = "__builtin_";
9326 const size_t prefix_len = sizeof(prefix) - 1;
9327
9328 switch (type) {
9329 case NODE_CALL:
9330 if (recv) {
9331 switch (nd_type(recv)) {
9332 case NODE_VCALL:
9333 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
9334 return name;
9335 }
9336 break;
9337 case NODE_CONST:
9338 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
9339 return name;
9340 }
9341 break;
9342 default: break;
9343 }
9344 }
9345 break;
9346 case NODE_VCALL:
9347 case NODE_FCALL:
9348 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
9349 return &name[prefix_len];
9350 }
9351 break;
9352 default: break;
9353 }
9354 return NULL;
9355}
9356
9357static int
9358delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
9359{
9360
9361 if (argc == 0) {
9362 *pstart_index = 0;
9363 return TRUE;
9364 }
9365 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
9366 unsigned int start=0;
9367
9368 // local_table: [p1, p2, p3, l1, l2, l3]
9369 // arguments: [p3, l1, l2] -> 2
9370 for (start = 0;
9371 argc + start <= ISEQ_BODY(iseq)->local_table_size;
9372 start++) {
9373 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
9374
9375 for (unsigned int i=start; i-start<argc; i++) {
9376 if (IS_INSN(elem) &&
9377 INSN_OF(elem) == BIN(getlocal)) {
9378 int local_index = FIX2INT(OPERAND_AT(elem, 0));
9379 int local_level = FIX2INT(OPERAND_AT(elem, 1));
9380
9381 if (local_level == 0) {
9382 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
9383 if (0) { // for debug
9384 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
9385 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
9386 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9387 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
9388 }
9389 if (i == index) {
9390 elem = elem->next;
9391 continue; /* for */
9392 }
9393 else {
9394 goto next;
9395 }
9396 }
9397 else {
9398 goto fail; // level != 0 is unsupported
9399 }
9400 }
9401 else {
9402 goto fail; // insn is not a getlocal
9403 }
9404 }
9405 goto success;
9406 next:;
9407 }
9408 fail:
9409 return FALSE;
9410 success:
9411 *pstart_index = start;
9412 return TRUE;
9413 }
9414 else {
9415 return FALSE;
9416 }
9417}
9418
9419static int
9420compile_builtin_attr_symbol(rb_iseq_t *iseq, VALUE symbol)
9421{
9422 VALUE string = rb_sym2str(symbol);
9423 if (rb_streql_lit(string, "leaf")) {
9424 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9425 }
9426 else if (rb_streql_lit(string, "inline_block")) {
9427 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9428 }
9429 else if (rb_streql_lit(string, "use_block")) {
9430 iseq_set_use_block(iseq);
9431 }
9432 else if (rb_streql_lit(string, "c_trace")) {
9433 // Let the iseq act like a C method in backtraces
9434 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9435 }
9436 else if (rb_streql_lit(string, "without_interrupts")) {
9437 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_WITHOUT_INTERRUPTS;
9438 }
9439 else if (rb_streql_lit(string, "caller_user_box")) {
9440 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_CALLER_USER_BOX;
9441 }
9442 else {
9443 return COMPILE_NG;
9444 }
9445 return COMPILE_OK;
9446}
9447
9448// Compile Primitive.attr! :leaf, ...
9449static int
9450compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9451{
9452 VALUE symbol;
9453 if (!node) goto no_arg;
9454 while (node) {
9455 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9456 const NODE *next = RNODE_LIST(node)->nd_next;
9457
9458 node = RNODE_LIST(node)->nd_head;
9459 if (!node) goto no_arg;
9460 switch (nd_type(node)) {
9461 case NODE_SYM:
9462 symbol = rb_node_sym_string_val(node);
9463 break;
9464 default:
9465 goto bad_arg;
9466 }
9467
9468 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9469 if (compile_builtin_attr_symbol(iseq, symbol) != COMPILE_OK) goto unknown_arg;
9470 node = next;
9471 }
9472 return COMPILE_OK;
9473 no_arg:
9474 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9475 return COMPILE_NG;
9476 non_symbol_arg:
9477 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9478 return COMPILE_NG;
9479 unknown_arg:
9480 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %" PRIsVALUE, symbol);
9481 return COMPILE_NG;
9482 bad_arg:
9483 UNKNOWN_NODE("attr!", node, COMPILE_NG);
9484}
9485
9486static int
9487compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9488{
9489 VALUE name;
9490
9491 if (!node) goto no_arg;
9492 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9493 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9494 node = RNODE_LIST(node)->nd_head;
9495 if (!node) goto no_arg;
9496 switch (nd_type(node)) {
9497 case NODE_SYM:
9498 name = rb_node_sym_string_val(node);
9499 break;
9500 default:
9501 goto bad_arg;
9502 }
9503 if (!SYMBOL_P(name)) goto non_symbol_arg;
9504 if (!popped) {
9505 compile_lvar(iseq, ret, line_node, SYM2ID(name));
9506 }
9507 return COMPILE_OK;
9508 no_arg:
9509 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9510 return COMPILE_NG;
9511 too_many_arg:
9512 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9513 return COMPILE_NG;
9514 non_symbol_arg:
9515 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9516 rb_builtin_class_name(name));
9517 return COMPILE_NG;
9518 bad_arg:
9519 UNKNOWN_NODE("arg!", node, COMPILE_NG);
9520}
9521
9522static NODE *
9523mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9524{
9525 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9526 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9527 return RNODE_IF(node)->nd_body;
9528 }
9529 else {
9530 rb_bug("mandatory_node: can't find mandatory node");
9531 }
9532}
9533
9534static int
9535compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9536{
9537 // arguments
9538 struct rb_args_info args = {
9539 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9540 };
9541 rb_node_args_t args_node;
9542 rb_node_init(RNODE(&args_node), NODE_ARGS);
9543 args_node.nd_ainfo = args;
9544
9545 // local table without non-mandatory parameters
9546 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9547 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9548
9549 VALUE idtmp = 0;
9550 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9551 tbl->size = table_size;
9552
9553 int i;
9554
9555 // lead parameters
9556 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9557 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9558 }
9559 // local variables
9560 for (; i<table_size; i++) {
9561 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9562 }
9563
9564 rb_node_scope_t scope_node;
9565 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9566 scope_node.nd_tbl = tbl;
9567 scope_node.nd_body = mandatory_node(iseq, node);
9568 scope_node.nd_parent = NULL;
9569 scope_node.nd_args = &args_node;
9570
9571 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9572
9573 const rb_iseq_t *mandatory_only_iseq =
9574 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9575 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9576 nd_line(line_node), NULL, 0,
9577 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9578 ISEQ_SCRIPT_LINES(iseq));
9579 RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
9580
9581 ALLOCV_END(idtmp);
9582 return COMPILE_OK;
9583}
9584
9585static int
9586compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9587 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9588{
9589 NODE *args_node = get_nd_args(node);
9590
9591 if (parent_block != NULL) {
9592 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9593 return COMPILE_NG;
9594 }
9595 else {
9596# define BUILTIN_INLINE_PREFIX "_bi"
9597 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9598 bool cconst = false;
9599 retry:;
9600 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9601
9602 if (bf == NULL) {
9603 if (strcmp("cstmt!", builtin_func) == 0 ||
9604 strcmp("cexpr!", builtin_func) == 0) {
9605 // ok
9606 }
9607 else if (strcmp("cconst!", builtin_func) == 0) {
9608 cconst = true;
9609 }
9610 else if (strcmp("cinit!", builtin_func) == 0) {
9611 // ignore
9612 return COMPILE_OK;
9613 }
9614 else if (strcmp("attr!", builtin_func) == 0) {
9615 return compile_builtin_attr(iseq, args_node);
9616 }
9617 else if (strcmp("arg!", builtin_func) == 0) {
9618 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9619 }
9620 else if (strcmp("mandatory_only?", builtin_func) == 0) {
9621 if (popped) {
9622 rb_bug("mandatory_only? should be in if condition");
9623 }
9624 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9625 rb_bug("mandatory_only? should be put on top");
9626 }
9627
9628 ADD_INSN1(ret, line_node, putobject, Qfalse);
9629 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9630 }
9631 else if (strcmp("local_self!", builtin_func) == 0) {
9632 // Push the local named "self" (e.g. the `self:` keyword
9633 // parameter of Ractor.shareable_proc) onto the stack.
9634 ID id_self;
9635 CONST_ID(id_self, "self");
9636 compile_lvar(iseq, ret, line_node, id_self);
9637 return COMPILE_OK;
9638 }
9639 else if (1) {
9640 rb_bug("can't find builtin function:%s", builtin_func);
9641 }
9642 else {
9643 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9644 return COMPILE_NG;
9645 }
9646
9647 int inline_index = nd_line(node);
9648 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9649 builtin_func = inline_func;
9650 args_node = NULL;
9651 goto retry;
9652 }
9653
9654 if (cconst) {
9655 typedef VALUE(*builtin_func0)(void *, VALUE);
9656 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9657 ADD_INSN1(ret, line_node, putobject, const_val);
9658 return COMPILE_OK;
9659 }
9660
9661 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9662
9663 unsigned int flag = 0;
9664 struct rb_callinfo_kwarg *keywords = NULL;
9665 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9666
9667 if (FIX2INT(argc) != bf->argc) {
9668 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9669 builtin_func, bf->argc, FIX2INT(argc));
9670 return COMPILE_NG;
9671 }
9672
9673 unsigned int start_index;
9674 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9675 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9676 }
9677 else {
9678 ADD_SEQ(ret, args);
9679 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9680 }
9681
9682 if (popped) ADD_INSN(ret, line_node, pop);
9683 return COMPILE_OK;
9684 }
9685}
9686
9687static int
9688compile_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)
9689{
9690 /* call: obj.method(...)
9691 * fcall: func(...)
9692 * vcall: func
9693 */
9694 DECL_ANCHOR(recv);
9695 DECL_ANCHOR(args);
9696 ID mid = get_node_call_nd_mid(node);
9697 VALUE argc;
9698 unsigned int flag = 0;
9699 struct rb_callinfo_kwarg *keywords = NULL;
9700 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9701 LABEL *else_label = NULL;
9702 VALUE branches = Qfalse;
9703
9704 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9705
9706 INIT_ANCHOR(recv);
9707 INIT_ANCHOR(args);
9708
9709#if OPT_SUPPORT_JOKE
9710 if (nd_type_p(node, NODE_VCALL)) {
9711 ID id_bitblt;
9712 ID id_answer;
9713
9714 CONST_ID(id_bitblt, "bitblt");
9715 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9716
9717 if (mid == id_bitblt) {
9718 ADD_INSN(ret, line_node, bitblt);
9719 return COMPILE_OK;
9720 }
9721 else if (mid == id_answer) {
9722 ADD_INSN(ret, line_node, answer);
9723 return COMPILE_OK;
9724 }
9725 }
9726 /* only joke */
9727 {
9728 ID goto_id;
9729 ID label_id;
9730
9731 CONST_ID(goto_id, "__goto__");
9732 CONST_ID(label_id, "__label__");
9733
9734 if (nd_type_p(node, NODE_FCALL) &&
9735 (mid == goto_id || mid == label_id)) {
9736 LABEL *label;
9737 st_data_t data;
9738 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9739 VALUE label_name;
9740
9741 if (!labels_table) {
9742 labels_table = st_init_numtable();
9743 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9744 }
9745 {
9746 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9747 return COMPILE_NG;
9748 }
9749
9750 if (mid == goto_id) {
9751 ADD_INSNL(ret, line_node, jump, label);
9752 }
9753 else {
9754 ADD_LABEL(ret, label);
9755 }
9756 return COMPILE_OK;
9757 }
9758 }
9759#endif
9760
9761 const char *builtin_func;
9762 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9763 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9764 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9765 }
9766
9767 /* receiver */
9768 if (!assume_receiver) {
9769 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9770 int idx, level;
9771
9772 if ((mid == idCall || mid == idAREF || mid == idYield || mid == idEqq) &&
9773 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9774 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9775 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9776 }
9777 else if (private_recv_p(node)) {
9778 ADD_INSN(recv, node, putself);
9779 flag |= VM_CALL_FCALL;
9780 }
9781 else {
9782 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9783 }
9784
9785 if (type == NODE_QCALL) {
9786 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9787 }
9788 }
9789 else if (type == NODE_FCALL || type == NODE_VCALL) {
9790 ADD_CALL_RECEIVER(recv, line_node);
9791 }
9792 }
9793
9794 /* args */
9795 if (type != NODE_VCALL) {
9796 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9797 CHECK(!NIL_P(argc));
9798 }
9799 else {
9800 argc = INT2FIX(0);
9801 }
9802
9803 ADD_SEQ(ret, recv);
9804
9805 bool inline_new = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction &&
9806 mid == rb_intern("new") &&
9807 parent_block == NULL &&
9808 !(flag & VM_CALL_ARGS_BLOCKARG);
9809
9810 if (inline_new) {
9811 ADD_INSN(ret, node, putnil);
9812 ADD_INSN(ret, node, swap);
9813 }
9814
9815 ADD_SEQ(ret, args);
9816
9817 debugp_param("call args argc", argc);
9818 debugp_param("call method", ID2SYM(mid));
9819
9820 switch ((int)type) {
9821 case NODE_VCALL:
9822 flag |= VM_CALL_VCALL;
9823 /* VCALL is funcall, so fall through */
9824 case NODE_FCALL:
9825 flag |= VM_CALL_FCALL;
9826 }
9827
9828 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9829 ADD_INSN(ret, line_node, splatkw);
9830 }
9831
9832 LABEL *not_basic_new = NEW_LABEL(nd_line(node));
9833 LABEL *not_basic_new_finish = NEW_LABEL(nd_line(node));
9834
9835 if (inline_new) {
9836 // Jump unless the receiver uses the "basic" implementation of "new"
9837 VALUE ci;
9838 if (flag & VM_CALL_FORWARDING) {
9839 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc) + 1, flag, keywords, 0);
9840 }
9841 else {
9842 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc), flag, keywords, 0);
9843 }
9844 ADD_INSN2(ret, node, opt_new, ci, not_basic_new);
9845 LABEL_REF(not_basic_new);
9846
9847 // optimized path
9848 ADD_SEND_R(ret, line_node, rb_intern("initialize"), argc, parent_block, INT2FIX(flag | VM_CALL_FCALL), keywords);
9849 ADD_INSNL(ret, line_node, jump, not_basic_new_finish);
9850
9851 ADD_LABEL(ret, not_basic_new);
9852 // Fall back to normal send
9853 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9854 ADD_INSN(ret, line_node, swap);
9855
9856 ADD_LABEL(ret, not_basic_new_finish);
9857 ADD_INSN(ret, line_node, pop);
9858 }
9859 else {
9860 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9861 }
9862
9863 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9864 if (popped) {
9865 ADD_INSN(ret, line_node, pop);
9866 }
9867 return COMPILE_OK;
9868}
9869
9870static int
9871compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9872{
9873 const int line = nd_line(node);
9874 VALUE argc;
9875 unsigned int flag = 0;
9876 int asgnflag = 0;
9877 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9878
9879 /*
9880 * a[x] (op)= y
9881 *
9882 * nil # nil
9883 * eval a # nil a
9884 * eval x # nil a x
9885 * dupn 2 # nil a x a x
9886 * send :[] # nil a x a[x]
9887 * eval y # nil a x a[x] y
9888 * send op # nil a x ret
9889 * setn 3 # ret a x ret
9890 * send []= # ret ?
9891 * pop # ret
9892 */
9893
9894 /*
9895 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9896 * NODE_OP_ASGN nd_recv
9897 * nd_args->nd_head
9898 * nd_args->nd_body
9899 * nd_mid
9900 */
9901
9902 if (!popped) {
9903 ADD_INSN(ret, node, putnil);
9904 }
9905 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9906 CHECK(asgnflag != -1);
9907 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9908 case NODE_ZLIST:
9909 argc = INT2FIX(0);
9910 break;
9911 default:
9912 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9913 CHECK(!NIL_P(argc));
9914 }
9915 int dup_argn = FIX2INT(argc) + 1;
9916 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9917 flag |= asgnflag;
9918 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9919
9920 if (id == idOROP || id == idANDOP) {
9921 /* a[x] ||= y or a[x] &&= y
9922
9923 unless/if a[x]
9924 a[x]= y
9925 else
9926 nil
9927 end
9928 */
9929 LABEL *label = NEW_LABEL(line);
9930 LABEL *lfin = NEW_LABEL(line);
9931
9932 ADD_INSN(ret, node, dup);
9933 if (id == idOROP) {
9934 ADD_INSNL(ret, node, branchif, label);
9935 }
9936 else { /* idANDOP */
9937 ADD_INSNL(ret, node, branchunless, label);
9938 }
9939 ADD_INSN(ret, node, pop);
9940
9941 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9942 if (!popped) {
9943 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9944 }
9945 if (flag & VM_CALL_ARGS_SPLAT) {
9946 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9947 ADD_INSN(ret, node, swap);
9948 ADD_INSN1(ret, node, splatarray, Qtrue);
9949 ADD_INSN(ret, node, swap);
9950 flag |= VM_CALL_ARGS_SPLAT_MUT;
9951 }
9952 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9953 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9954 }
9955 else {
9956 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9957 }
9958 ADD_INSN(ret, node, pop);
9959 ADD_INSNL(ret, node, jump, lfin);
9960 ADD_LABEL(ret, label);
9961 if (!popped) {
9962 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9963 }
9964 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9965 ADD_LABEL(ret, lfin);
9966 }
9967 else {
9968 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9969 ADD_SEND(ret, node, id, INT2FIX(1));
9970 if (!popped) {
9971 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9972 }
9973 if (flag & VM_CALL_ARGS_SPLAT) {
9974 if (flag & VM_CALL_KW_SPLAT) {
9975 ADD_INSN1(ret, node, topn, INT2FIX(2));
9976 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9977 ADD_INSN1(ret, node, splatarray, Qtrue);
9978 flag |= VM_CALL_ARGS_SPLAT_MUT;
9979 }
9980 ADD_INSN(ret, node, swap);
9981 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9982 ADD_INSN1(ret, node, setn, INT2FIX(2));
9983 ADD_INSN(ret, node, pop);
9984 }
9985 else {
9986 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9987 ADD_INSN(ret, node, swap);
9988 ADD_INSN1(ret, node, splatarray, Qtrue);
9989 ADD_INSN(ret, node, swap);
9990 flag |= VM_CALL_ARGS_SPLAT_MUT;
9991 }
9992 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9993 }
9994 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9995 }
9996 else {
9997 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9998 }
9999 ADD_INSN(ret, node, pop);
10000 }
10001 return COMPILE_OK;
10002}
10003
10004static int
10005compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10006{
10007 const int line = nd_line(node);
10008 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
10009 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
10010 int asgnflag;
10011 LABEL *lfin = NEW_LABEL(line);
10012 LABEL *lcfin = NEW_LABEL(line);
10013 LABEL *lskip = 0;
10014 /*
10015 class C; attr_accessor :c; end
10016 r = C.new
10017 r.a &&= v # asgn2
10018
10019 eval r # r
10020 dup # r r
10021 eval r.a # r o
10022
10023 # or
10024 dup # r o o
10025 if lcfin # r o
10026 pop # r
10027 eval v # r v
10028 swap # v r
10029 topn 1 # v r v
10030 send a= # v ?
10031 jump lfin # v ?
10032
10033 lcfin: # r o
10034 swap # o r
10035
10036 lfin: # o ?
10037 pop # o
10038
10039 # or (popped)
10040 if lcfin # r
10041 eval v # r v
10042 send a= # ?
10043 jump lfin # ?
10044
10045 lcfin: # r
10046
10047 lfin: # ?
10048 pop #
10049
10050 # and
10051 dup # r o o
10052 unless lcfin
10053 pop # r
10054 eval v # r v
10055 swap # v r
10056 topn 1 # v r v
10057 send a= # v ?
10058 jump lfin # v ?
10059
10060 # others
10061 eval v # r o v
10062 send ?? # r w
10063 send a= # w
10064
10065 */
10066
10067 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
10068 CHECK(asgnflag != -1);
10069 if (RNODE_OP_ASGN2(node)->nd_aid) {
10070 lskip = NEW_LABEL(line);
10071 ADD_INSN(ret, node, dup);
10072 ADD_INSNL(ret, node, branchnil, lskip);
10073 }
10074 ADD_INSN(ret, node, dup);
10075 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
10076
10077 if (atype == idOROP || atype == idANDOP) {
10078 if (!popped) {
10079 ADD_INSN(ret, node, dup);
10080 }
10081 if (atype == idOROP) {
10082 ADD_INSNL(ret, node, branchif, lcfin);
10083 }
10084 else { /* idANDOP */
10085 ADD_INSNL(ret, node, branchunless, lcfin);
10086 }
10087 if (!popped) {
10088 ADD_INSN(ret, node, pop);
10089 }
10090 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
10091 if (!popped) {
10092 ADD_INSN(ret, node, swap);
10093 ADD_INSN1(ret, node, topn, INT2FIX(1));
10094 }
10095 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
10096 ADD_INSNL(ret, node, jump, lfin);
10097
10098 ADD_LABEL(ret, lcfin);
10099 if (!popped) {
10100 ADD_INSN(ret, node, swap);
10101 }
10102
10103 ADD_LABEL(ret, lfin);
10104 }
10105 else {
10106 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
10107 ADD_SEND(ret, node, atype, INT2FIX(1));
10108 if (!popped) {
10109 ADD_INSN(ret, node, swap);
10110 ADD_INSN1(ret, node, topn, INT2FIX(1));
10111 }
10112 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
10113 }
10114 if (lskip && popped) {
10115 ADD_LABEL(ret, lskip);
10116 }
10117 ADD_INSN(ret, node, pop);
10118 if (lskip && !popped) {
10119 ADD_LABEL(ret, lskip);
10120 }
10121 return COMPILE_OK;
10122}
10123
10124static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
10125
10126static int
10127compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10128{
10129 const int line = nd_line(node);
10130 LABEL *lfin = 0;
10131 LABEL *lassign = 0;
10132 ID mid;
10133
10134 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
10135 case NODE_COLON3:
10136 ADD_INSN1(ret, node, putobject, rb_cObject);
10137 break;
10138 case NODE_COLON2:
10139 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
10140 break;
10141 default:
10142 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
10143 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
10144 return COMPILE_NG;
10145 }
10146 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
10147 /* cref */
10148 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
10149 lassign = NEW_LABEL(line);
10150 ADD_INSN(ret, node, dup); /* cref cref */
10151 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
10152 ID2SYM(mid), Qtrue); /* cref bool */
10153 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
10154 }
10155 ADD_INSN(ret, node, dup); /* cref cref */
10156 ADD_INSN1(ret, node, putobject, Qtrue);
10157 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
10158
10159 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
10160 lfin = NEW_LABEL(line);
10161 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
10162 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
10163 ADD_INSNL(ret, node, branchif, lfin);
10164 else /* idANDOP */
10165 ADD_INSNL(ret, node, branchunless, lfin);
10166 /* cref [obj] */
10167 if (!popped) ADD_INSN(ret, node, pop); /* cref */
10168 if (lassign) ADD_LABEL(ret, lassign);
10169 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
10170 /* cref value */
10171 if (popped)
10172 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
10173 else {
10174 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
10175 ADD_INSN(ret, node, swap); /* cref value value cref */
10176 }
10177 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
10178 ADD_LABEL(ret, lfin); /* cref [value] */
10179 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
10180 ADD_INSN(ret, node, pop); /* [value] */
10181 }
10182 else {
10183 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
10184 /* cref obj value */
10185 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
10186 /* cref value */
10187 ADD_INSN(ret, node, swap); /* value cref */
10188 if (!popped) {
10189 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
10190 ADD_INSN(ret, node, swap); /* value value cref */
10191 }
10192 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
10193 }
10194 return COMPILE_OK;
10195}
10196
10197static int
10198compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10199{
10200 const int line = nd_line(node);
10201 LABEL *lfin = NEW_LABEL(line);
10202 LABEL *lassign;
10203
10204 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
10205 LABEL *lfinish[2];
10206 lfinish[0] = lfin;
10207 lfinish[1] = 0;
10208 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
10209 lassign = lfinish[1];
10210 if (!lassign) {
10211 lassign = NEW_LABEL(line);
10212 }
10213 ADD_INSNL(ret, node, branchunless, lassign);
10214 }
10215 else {
10216 lassign = NEW_LABEL(line);
10217 }
10218
10219 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
10220
10221 if (!popped) {
10222 ADD_INSN(ret, node, dup);
10223 }
10224
10225 if (type == NODE_OP_ASGN_AND) {
10226 ADD_INSNL(ret, node, branchunless, lfin);
10227 }
10228 else {
10229 ADD_INSNL(ret, node, branchif, lfin);
10230 }
10231
10232 if (!popped) {
10233 ADD_INSN(ret, node, pop);
10234 }
10235
10236 ADD_LABEL(ret, lassign);
10237 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
10238 ADD_LABEL(ret, lfin);
10239 return COMPILE_OK;
10240}
10241
10242static int
10243compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10244{
10245 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10246 DECL_ANCHOR(args);
10247 int argc;
10248 unsigned int flag = 0;
10249 struct rb_callinfo_kwarg *keywords = NULL;
10250 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
10251 int use_block = 1;
10252
10253 INIT_ANCHOR(args);
10254 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
10255
10256 if (type == NODE_SUPER) {
10257 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
10258 CHECK(!NIL_P(vargc));
10259 argc = FIX2INT(vargc);
10260 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
10261 ADD_INSN(args, node, splatkw);
10262 }
10263
10264 if (flag & VM_CALL_ARGS_BLOCKARG) {
10265 use_block = 0;
10266 }
10267 }
10268 else {
10269 /* NODE_ZSUPER */
10270 int i;
10271 const rb_iseq_t *liseq = body->local_iseq;
10272 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
10273 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
10274 int lvar_level = get_lvar_level(iseq);
10275
10276 argc = local_body->param.lead_num;
10277
10278 /* normal arguments */
10279 for (i = 0; i < local_body->param.lead_num; i++) {
10280 int idx = local_body->local_table_size - i;
10281 ADD_GETLOCAL(args, node, idx, lvar_level);
10282 }
10283
10284 /* forward ... */
10285 if (local_body->param.flags.forwardable) {
10286 flag |= VM_CALL_FORWARDING;
10287 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
10288 ADD_GETLOCAL(args, node, idx, lvar_level);
10289 }
10290
10291 if (local_body->param.flags.has_opt) {
10292 /* optional arguments */
10293 int j;
10294 for (j = 0; j < local_body->param.opt_num; j++) {
10295 int idx = local_body->local_table_size - (i + j);
10296 ADD_GETLOCAL(args, node, idx, lvar_level);
10297 }
10298 i += j;
10299 argc = i;
10300 }
10301 if (local_body->param.flags.has_rest) {
10302 /* rest argument */
10303 int idx = local_body->local_table_size - local_body->param.rest_start;
10304 ADD_GETLOCAL(args, node, idx, lvar_level);
10305 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
10306
10307 argc = local_body->param.rest_start + 1;
10308 flag |= VM_CALL_ARGS_SPLAT;
10309 }
10310 if (local_body->param.flags.has_post) {
10311 /* post arguments */
10312 int post_len = local_body->param.post_num;
10313 int post_start = local_body->param.post_start;
10314
10315 if (local_body->param.flags.has_rest) {
10316 int j;
10317 for (j=0; j<post_len; j++) {
10318 int idx = local_body->local_table_size - (post_start + j);
10319 ADD_GETLOCAL(args, node, idx, lvar_level);
10320 }
10321 ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
10322 flag |= VM_CALL_ARGS_SPLAT_MUT;
10323 /* argc is settled at above */
10324 }
10325 else {
10326 int j;
10327 for (j=0; j<post_len; j++) {
10328 int idx = local_body->local_table_size - (post_start + j);
10329 ADD_GETLOCAL(args, node, idx, lvar_level);
10330 }
10331 argc = post_len + post_start;
10332 }
10333 }
10334
10335 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
10336 int local_size = local_body->local_table_size;
10337 argc++;
10338
10339 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10340
10341 if (local_body->param.flags.has_kwrest) {
10342 int idx = local_body->local_table_size - local_kwd->rest_start;
10343 ADD_GETLOCAL(args, node, idx, lvar_level);
10344 RUBY_ASSERT(local_kwd->num > 0);
10345 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
10346 }
10347 else {
10348 ADD_INSN1(args, node, newhash, INT2FIX(0));
10349 }
10350 for (i = 0; i < local_kwd->num; ++i) {
10351 ID id = local_kwd->table[i];
10352 int idx = local_size - get_local_var_idx(liseq, id);
10353 ADD_INSN1(args, node, putobject, ID2SYM(id));
10354 ADD_GETLOCAL(args, node, idx, lvar_level);
10355 }
10356 ADD_SEND(args, node, id_core_hash_merge_bang_ptr, INT2FIX(i * 2 + 1));
10357 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
10358 }
10359 else if (local_body->param.flags.has_kwrest) {
10360 int idx = local_body->local_table_size - local_kwd->rest_start;
10361 ADD_GETLOCAL(args, node, idx, lvar_level);
10362 argc++;
10363 flag |= VM_CALL_KW_SPLAT;
10364 }
10365 }
10366
10367 if (use_block && parent_block == NULL) {
10368 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10369 }
10370
10371 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
10372 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
10373 ADD_INSN(ret, node, putself);
10374 ADD_SEQ(ret, args);
10375
10376 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
10377
10378 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
10379 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
10380 }
10381 else {
10382 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
10383 }
10384
10385 if (popped) {
10386 ADD_INSN(ret, node, pop);
10387 }
10388 return COMPILE_OK;
10389}
10390
10391static int
10392compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10393{
10394 DECL_ANCHOR(args);
10395 VALUE argc;
10396 unsigned int flag = 0;
10397 struct rb_callinfo_kwarg *keywords = NULL;
10398
10399 INIT_ANCHOR(args);
10400
10401 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
10402 case ISEQ_TYPE_TOP:
10403 case ISEQ_TYPE_MAIN:
10404 case ISEQ_TYPE_CLASS:
10405 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
10406 return COMPILE_NG;
10407 default: /* valid */;
10408 }
10409
10410 if (RNODE_YIELD(node)->nd_head) {
10411 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
10412 CHECK(!NIL_P(argc));
10413 }
10414 else {
10415 argc = INT2FIX(0);
10416 }
10417
10418 ADD_SEQ(ret, args);
10419 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
10420 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10421
10422 if (popped) {
10423 ADD_INSN(ret, node, pop);
10424 }
10425
10426 int level = 0;
10427 const rb_iseq_t *tmp_iseq = iseq;
10428 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
10429 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
10430 }
10431 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
10432
10433 return COMPILE_OK;
10434}
10435
10436static int
10437compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10438{
10439 DECL_ANCHOR(recv);
10440 DECL_ANCHOR(val);
10441
10442 INIT_ANCHOR(recv);
10443 INIT_ANCHOR(val);
10444 switch ((int)type) {
10445 case NODE_MATCH:
10446 {
10447 VALUE re = rb_node_regx_string_val(node);
10449 ADD_INSN1(recv, node, putobject, re);
10450 ADD_INSN2(val, node, getspecial, INT2FIX(0),
10451 INT2FIX(0));
10452 }
10453 break;
10454 case NODE_MATCH2:
10455 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
10456 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
10457 break;
10458 case NODE_MATCH3:
10459 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
10460 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
10461 break;
10462 }
10463
10464 ADD_SEQ(ret, recv);
10465 ADD_SEQ(ret, val);
10466 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
10467
10468 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10469 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10470 }
10471
10472 if (popped) {
10473 ADD_INSN(ret, node, pop);
10474 }
10475 return COMPILE_OK;
10476}
10477
10478static int
10479compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10480{
10481 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10482 /* constant */
10483 VALUE segments;
10484 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10485 (segments = collect_const_segments(iseq, node))) {
10486 ISEQ_BODY(iseq)->ic_size++;
10487 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10488 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10489 }
10490 else {
10491 /* constant */
10492 DECL_ANCHOR(pref);
10493 DECL_ANCHOR(body);
10494
10495 INIT_ANCHOR(pref);
10496 INIT_ANCHOR(body);
10497 CHECK(compile_const_prefix(iseq, node, pref, body));
10498 if (LIST_INSN_SIZE_ZERO(pref)) {
10499 ADD_INSN(ret, node, putnil);
10500 ADD_SEQ(ret, body);
10501 }
10502 else {
10503 ADD_SEQ(ret, pref);
10504 ADD_SEQ(ret, body);
10505 }
10506 }
10507 }
10508 else {
10509 /* function call */
10510 ADD_CALL_RECEIVER(ret, node);
10511 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10512 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10513 }
10514 if (popped) {
10515 ADD_INSN(ret, node, pop);
10516 }
10517 return COMPILE_OK;
10518}
10519
10520static int
10521compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10522{
10523 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10524
10525 /* add cache insn */
10526 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10527 ISEQ_BODY(iseq)->ic_size++;
10528 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10530 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10531 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10532 }
10533 else {
10534 ADD_INSN1(ret, node, putobject, rb_cObject);
10535 ADD_INSN1(ret, node, putobject, Qtrue);
10536 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10537 }
10538
10539 if (popped) {
10540 ADD_INSN(ret, node, pop);
10541 }
10542 return COMPILE_OK;
10543}
10544
10545static int
10546compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10547{
10548 VALUE flag = INT2FIX(excl);
10549 const NODE *b = RNODE_DOT2(node)->nd_beg;
10550 const NODE *e = RNODE_DOT2(node)->nd_end;
10551
10552 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10553 if (!popped) {
10554 VALUE bv = optimized_range_item(b);
10555 VALUE ev = optimized_range_item(e);
10556 VALUE val = rb_range_new(bv, ev, excl);
10558 ADD_INSN1(ret, node, putobject, val);
10559 RB_OBJ_WRITTEN(iseq, Qundef, val);
10560 }
10561 }
10562 else {
10563 CHECK(COMPILE_(ret, "min", b, popped));
10564 CHECK(COMPILE_(ret, "max", e, popped));
10565 if (!popped) {
10566 ADD_INSN1(ret, node, newrange, flag);
10567 }
10568 }
10569 return COMPILE_OK;
10570}
10571
10572static int
10573compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10574{
10575 if (!popped) {
10576 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10577 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10578 }
10579 else {
10580 const rb_iseq_t *ip = iseq;
10581 int level = 0;
10582 while (ip) {
10583 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10584 break;
10585 }
10586 ip = ISEQ_BODY(ip)->parent_iseq;
10587 level++;
10588 }
10589 if (ip) {
10590 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10591 }
10592 else {
10593 ADD_INSN(ret, node, putnil);
10594 }
10595 }
10596 }
10597 return COMPILE_OK;
10598}
10599
10600static int
10601compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10602{
10603 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10604 LABEL *end_label = NEW_LABEL(nd_line(node));
10605 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10606
10607 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10608 /* required argument. do nothing */
10609 COMPILE_ERROR(ERROR_ARGS "unreachable");
10610 return COMPILE_NG;
10611 }
10612 else if (nd_type_p(default_value, NODE_SYM) ||
10613 nd_type_p(default_value, NODE_REGX) ||
10614 nd_type_p(default_value, NODE_LINE) ||
10615 nd_type_p(default_value, NODE_INTEGER) ||
10616 nd_type_p(default_value, NODE_FLOAT) ||
10617 nd_type_p(default_value, NODE_RATIONAL) ||
10618 nd_type_p(default_value, NODE_IMAGINARY) ||
10619 nd_type_p(default_value, NODE_NIL) ||
10620 nd_type_p(default_value, NODE_TRUE) ||
10621 nd_type_p(default_value, NODE_FALSE)) {
10622 COMPILE_ERROR(ERROR_ARGS "unreachable");
10623 return COMPILE_NG;
10624 }
10625 else {
10626 /* if keywordcheck(_kw_bits, nth_keyword)
10627 * kw = default_value
10628 * end
10629 */
10630 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10631 int keyword_idx = body->param.keyword->num;
10632
10633 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10634 ADD_INSNL(ret, node, branchif, end_label);
10635 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10636 ADD_LABEL(ret, end_label);
10637 }
10638 return COMPILE_OK;
10639}
10640
10641static int
10642compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10643{
10644 DECL_ANCHOR(recv);
10645 DECL_ANCHOR(args);
10646 unsigned int flag = 0;
10647 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10648 VALUE argc;
10649 LABEL *else_label = NULL;
10650 VALUE branches = Qfalse;
10651
10652 INIT_ANCHOR(recv);
10653 INIT_ANCHOR(args);
10654 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10655 CHECK(!NIL_P(argc));
10656
10657 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10658 CHECK(asgnflag != -1);
10659 flag |= (unsigned int)asgnflag;
10660
10661 debugp_param("argc", argc);
10662 debugp_param("nd_mid", ID2SYM(mid));
10663
10664 if (!rb_is_attrset_id(mid)) {
10665 /* safe nav attr */
10666 mid = rb_id_attrset(mid);
10667 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10668 }
10669 if (!popped) {
10670 ADD_INSN(ret, node, putnil);
10671 ADD_SEQ(ret, recv);
10672 ADD_SEQ(ret, args);
10673
10674 if (flag & VM_CALL_ARGS_SPLAT) {
10675 ADD_INSN(ret, node, dup);
10676 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10677 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10678 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10679 ADD_INSN (ret, node, pop);
10680 }
10681 else {
10682 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10683 }
10684 }
10685 else {
10686 ADD_SEQ(ret, recv);
10687 ADD_SEQ(ret, args);
10688 }
10689 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10690 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10691 ADD_INSN(ret, node, pop);
10692 return COMPILE_OK;
10693}
10694
10695static int
10696compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10697{
10698 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10699 ADD_SEQ(ret, sub);
10700
10701 if (copy) {
10702 /*
10703 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10704 * NEW_LIST(value, loc), loc);
10705 */
10706 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10707 }
10708 else {
10709 /*
10710 * NEW_CALL(fcore, rb_intern("make_shareable"),
10711 * NEW_LIST(value, loc), loc);
10712 */
10713 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10714 }
10715
10716 return COMPILE_OK;
10717}
10718
10719static VALUE
10720node_const_decl_val(const NODE *node)
10721{
10722 VALUE path;
10723 switch (nd_type(node)) {
10724 case NODE_CDECL:
10725 if (RNODE_CDECL(node)->nd_vid) {
10726 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10727 goto end;
10728 }
10729 else {
10730 node = RNODE_CDECL(node)->nd_else;
10731 }
10732 break;
10733 case NODE_COLON2:
10734 break;
10735 case NODE_COLON3:
10736 // ::Const
10737 path = rb_str_new_cstr("::");
10738 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10739 goto end;
10740 default:
10741 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10743 }
10744
10745 path = rb_ary_new();
10746 if (node) {
10747 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10748 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10749 }
10750 if (node && nd_type_p(node, NODE_CONST)) {
10751 // Const::Name
10752 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10753 }
10754 else if (node && nd_type_p(node, NODE_COLON3)) {
10755 // ::Const::Name
10756 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10757 rb_ary_push(path, rb_str_new(0, 0));
10758 }
10759 else {
10760 // expression::Name
10761 rb_ary_push(path, rb_str_new_cstr("..."));
10762 }
10763 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10764 }
10765 end:
10766 path = rb_fstring(path);
10767 return path;
10768}
10769
10770static VALUE
10771const_decl_path(NODE *dest)
10772{
10773 VALUE path = Qnil;
10774 if (!nd_type_p(dest, NODE_CALL)) {
10775 path = node_const_decl_val(dest);
10776 }
10777 return path;
10778}
10779
10780static int
10781compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10782{
10783 /*
10784 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10785 */
10786 VALUE path = const_decl_path(dest);
10787 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10788 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10789 ADD_INSN1(ret, value, putobject, path);
10790 RB_OBJ_WRITTEN(iseq, Qundef, path);
10791 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10792
10793 return COMPILE_OK;
10794}
10795
10796#ifndef SHAREABLE_BARE_EXPRESSION
10797#define SHAREABLE_BARE_EXPRESSION 1
10798#endif
10799
10800static int
10801compile_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)
10802{
10803# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10804 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10805 VALUE lit = Qnil;
10806 DECL_ANCHOR(anchor);
10807
10808 enum node_type type = node ? nd_type(node) : NODE_NIL;
10809 switch (type) {
10810 case NODE_TRUE:
10811 *value_p = Qtrue;
10812 goto compile;
10813 case NODE_FALSE:
10814 *value_p = Qfalse;
10815 goto compile;
10816 case NODE_NIL:
10817 *value_p = Qnil;
10818 goto compile;
10819 case NODE_SYM:
10820 *value_p = rb_node_sym_string_val(node);
10821 goto compile;
10822 case NODE_REGX:
10823 *value_p = rb_node_regx_string_val(node);
10824 goto compile;
10825 case NODE_LINE:
10826 *value_p = rb_node_line_lineno_val(node);
10827 goto compile;
10828 case NODE_INTEGER:
10829 *value_p = rb_node_integer_literal_val(node);
10830 goto compile;
10831 case NODE_FLOAT:
10832 *value_p = rb_node_float_literal_val(node);
10833 goto compile;
10834 case NODE_RATIONAL:
10835 *value_p = rb_node_rational_literal_val(node);
10836 goto compile;
10837 case NODE_IMAGINARY:
10838 *value_p = rb_node_imaginary_literal_val(node);
10839 goto compile;
10840 case NODE_ENCODING:
10841 *value_p = rb_node_encoding_val(node);
10842
10843 compile:
10844 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10845 *shareable_literal_p = 1;
10846 return COMPILE_OK;
10847
10848 case NODE_DSTR:
10849 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10850 if (shareable == rb_parser_shareable_literal) {
10851 /*
10852 * NEW_CALL(node, idUMinus, 0, loc);
10853 *
10854 * -"#{var}"
10855 */
10856 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10857 }
10858 *value_p = Qundef;
10859 *shareable_literal_p = 1;
10860 return COMPILE_OK;
10861
10862 case NODE_STR:{
10863 VALUE lit = rb_node_str_string_val(node);
10864 ADD_INSN1(ret, node, putobject, lit);
10865 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10866 *value_p = lit;
10867 *shareable_literal_p = 1;
10868
10869 return COMPILE_OK;
10870 }
10871
10872 case NODE_FILE:{
10873 VALUE lit = rb_node_file_path_val(node);
10874 ADD_INSN1(ret, node, putobject, lit);
10875 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10876 *value_p = lit;
10877 *shareable_literal_p = 1;
10878
10879 return COMPILE_OK;
10880 }
10881
10882 case NODE_ZLIST:{
10883 VALUE lit = rb_ary_new();
10884 OBJ_FREEZE(lit);
10885 ADD_INSN1(ret, node, putobject, lit);
10886 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10887 *value_p = lit;
10888 *shareable_literal_p = 1;
10889
10890 return COMPILE_OK;
10891 }
10892
10893 case NODE_LIST:{
10894 INIT_ANCHOR(anchor);
10895 lit = rb_ary_new();
10896 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10897 VALUE val;
10898 int shareable_literal_p2;
10899 NODE *elt = RNODE_LIST(n)->nd_head;
10900 if (elt) {
10901 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10902 if (shareable_literal_p2) {
10903 /* noop */
10904 }
10905 else if (RTEST(lit)) {
10906 rb_ary_clear(lit);
10907 lit = Qfalse;
10908 }
10909 }
10910 if (RTEST(lit)) {
10911 if (!UNDEF_P(val)) {
10912 rb_ary_push(lit, val);
10913 }
10914 else {
10915 rb_ary_clear(lit);
10916 lit = Qnil; /* make shareable at runtime */
10917 }
10918 }
10919 }
10920 break;
10921 }
10922 case NODE_HASH:{
10923 if (!RNODE_HASH(node)->nd_brace) {
10924 *value_p = Qundef;
10925 *shareable_literal_p = 0;
10926 return COMPILE_OK;
10927 }
10928 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10929 if (!RNODE_LIST(n)->nd_head) {
10930 // If the hash node have a keyword splat, fall back to the default case.
10931 goto compile_shareable;
10932 }
10933 }
10934
10935 INIT_ANCHOR(anchor);
10936 lit = rb_hash_new();
10937 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10938 VALUE key_val = 0;
10939 VALUE value_val = 0;
10940 int shareable_literal_p2;
10941 NODE *key = RNODE_LIST(n)->nd_head;
10942 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10943 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10944 if (shareable_literal_p2) {
10945 /* noop */
10946 }
10947 else if (RTEST(lit)) {
10948 rb_hash_clear(lit);
10949 lit = Qfalse;
10950 }
10951 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10952 if (shareable_literal_p2) {
10953 /* noop */
10954 }
10955 else if (RTEST(lit)) {
10956 rb_hash_clear(lit);
10957 lit = Qfalse;
10958 }
10959 if (RTEST(lit)) {
10960 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10961 rb_hash_aset(lit, key_val, value_val);
10962 }
10963 else {
10964 rb_hash_clear(lit);
10965 lit = Qnil; /* make shareable at runtime */
10966 }
10967 }
10968 }
10969 break;
10970 }
10971
10972 default:
10973
10974 compile_shareable:
10975 if (shareable == rb_parser_shareable_literal &&
10976 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10977 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10978 *value_p = Qundef;
10979 *shareable_literal_p = 1;
10980 return COMPILE_OK;
10981 }
10982 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10983 *value_p = Qundef;
10984 *shareable_literal_p = 0;
10985 return COMPILE_OK;
10986 }
10987
10988 /* Array or Hash that does not have keyword splat */
10989 if (!lit) {
10990 if (nd_type(node) == NODE_LIST) {
10991 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10992 }
10993 else if (nd_type(node) == NODE_HASH) {
10994 long len = RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10997 ADD_INSN1(anchor, node, newhash, LONG2FIX(len));
10998 }
10999 *value_p = Qundef;
11000 *shareable_literal_p = 0;
11001 ADD_SEQ(ret, anchor);
11002 return COMPILE_OK;
11003 }
11004 if (NIL_P(lit)) {
11005 // if shareable_literal, all elements should have been ensured
11006 // as shareable
11007 if (nd_type(node) == NODE_LIST) {
11008 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
11009 }
11010 else if (nd_type(node) == NODE_HASH) {
11011 long len = RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
11014 ADD_INSN1(anchor, node, newhash, LONG2FIX(len));
11015 }
11016 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
11017 *value_p = Qundef;
11018 *shareable_literal_p = 1;
11019 }
11020 else {
11022 ADD_INSN1(ret, node, putobject, val);
11023 RB_OBJ_WRITTEN(iseq, Qundef, val);
11024 *value_p = val;
11025 *shareable_literal_p = 1;
11026 }
11027
11028 return COMPILE_OK;
11029}
11030
11031static int
11032compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
11033{
11034 int literal_p = 0;
11035 VALUE val;
11036 DECL_ANCHOR(anchor);
11037 INIT_ANCHOR(anchor);
11038
11039 switch (shareable) {
11040 case rb_parser_shareable_none:
11041 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
11042 return COMPILE_OK;
11043
11044 case rb_parser_shareable_literal:
11045 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
11046 ADD_SEQ(ret, anchor);
11047 return COMPILE_OK;
11048
11049 case rb_parser_shareable_copy:
11050 case rb_parser_shareable_everything:
11051 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
11052 if (!literal_p) {
11053 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
11054 }
11055 else {
11056 ADD_SEQ(ret, anchor);
11057 }
11058 return COMPILE_OK;
11059 default:
11060 rb_bug("unexpected rb_parser_shareability: %d", shareable);
11061 }
11062}
11063
11064static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
11072static int
11073iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
11074{
11075 if (node == 0) {
11076 if (!popped) {
11077 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
11078 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
11079 debugs("node: NODE_NIL(implicit)\n");
11080 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
11081 }
11082 return COMPILE_OK;
11083 }
11084 return iseq_compile_each0(iseq, ret, node, popped);
11085}
11086
11087static int
11088iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
11089{
11090 const int line = (int)nd_line(node);
11091 const enum node_type type = nd_type(node);
11092 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
11093
11094 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
11095 /* ignore */
11096 }
11097 else {
11098 if (nd_fl_newline(node)) {
11099 int event = RUBY_EVENT_LINE;
11100 ISEQ_COMPILE_DATA(iseq)->last_line = line;
11101 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
11102 event |= RUBY_EVENT_COVERAGE_LINE;
11103 }
11104 ADD_TRACE(ret, event);
11105 }
11106 }
11107
11108 debug_node_start(node);
11109#undef BEFORE_RETURN
11110#define BEFORE_RETURN debug_node_end()
11111
11112 switch (type) {
11113 case NODE_BLOCK:
11114 CHECK(compile_block(iseq, ret, node, popped));
11115 break;
11116 case NODE_IF:
11117 case NODE_UNLESS:
11118 CHECK(compile_if(iseq, ret, node, popped, type));
11119 break;
11120 case NODE_CASE:
11121 CHECK(compile_case(iseq, ret, node, popped));
11122 break;
11123 case NODE_CASE2:
11124 CHECK(compile_case2(iseq, ret, node, popped));
11125 break;
11126 case NODE_CASE3:
11127 CHECK(compile_case3(iseq, ret, node, popped));
11128 break;
11129 case NODE_WHILE:
11130 case NODE_UNTIL:
11131 CHECK(compile_loop(iseq, ret, node, popped, type));
11132 break;
11133 case NODE_FOR:
11134 case NODE_ITER:
11135 CHECK(compile_iter(iseq, ret, node, popped));
11136 break;
11137 case NODE_FOR_MASGN:
11138 CHECK(compile_for_masgn(iseq, ret, node, popped));
11139 break;
11140 case NODE_BREAK:
11141 CHECK(compile_break(iseq, ret, node, popped));
11142 break;
11143 case NODE_NEXT:
11144 CHECK(compile_next(iseq, ret, node, popped));
11145 break;
11146 case NODE_REDO:
11147 CHECK(compile_redo(iseq, ret, node, popped));
11148 break;
11149 case NODE_RETRY:
11150 CHECK(compile_retry(iseq, ret, node, popped));
11151 break;
11152 case NODE_BEGIN:{
11153 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
11154 break;
11155 }
11156 case NODE_RESCUE:
11157 CHECK(compile_rescue(iseq, ret, node, popped));
11158 break;
11159 case NODE_RESBODY:
11160 CHECK(compile_resbody(iseq, ret, node, popped));
11161 break;
11162 case NODE_ENSURE:
11163 CHECK(compile_ensure(iseq, ret, node, popped));
11164 break;
11165
11166 case NODE_AND:
11167 case NODE_OR:{
11168 LABEL *end_label = NEW_LABEL(line);
11169 const NODE *cond = node;
11170 /* Compile a chain of the same operator (`a && b && ...`) against one
11171 * shared end label, so every branch targets it directly. Compiling
11172 * nd_2nd recursively would instead give each operator its own label,
11173 * and the peephole optimizer would rewrite that chain in quadratic
11174 * time. */
11175 while (1) {
11176 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(cond)->nd_1st));
11177 if (!popped) {
11178 ADD_INSN(ret, cond, dup);
11179 }
11180 if (type == NODE_AND) {
11181 ADD_INSNL(ret, cond, branchunless, end_label);
11182 }
11183 else {
11184 ADD_INSNL(ret, cond, branchif, end_label);
11185 }
11186 if (!popped) {
11187 ADD_INSN(ret, cond, pop);
11188 }
11189 const NODE *rest = RNODE_OR(cond)->nd_2nd;
11190 if (nd_type_p(rest, type)) {
11191 cond = rest;
11192 continue;
11193 }
11194 CHECK(COMPILE_(ret, "nd_2nd", rest, popped));
11195 break;
11196 }
11197 ADD_LABEL(ret, end_label);
11198 break;
11199 }
11200
11201 case NODE_MASGN:{
11202 compile_massign(iseq, ret, node, popped);
11203 break;
11204 }
11205
11206 case NODE_LASGN:{
11207 ID id = RNODE_LASGN(node)->nd_vid;
11208 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
11209
11210 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
11211 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
11212
11213 if (!popped) {
11214 ADD_INSN(ret, node, dup);
11215 }
11216 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
11217 break;
11218 }
11219 case NODE_DASGN: {
11220 int idx, lv, ls;
11221 ID id = RNODE_DASGN(node)->nd_vid;
11222 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
11223 debugi("dassn id", rb_id2str(id) ? id : '*');
11224
11225 if (!popped) {
11226 ADD_INSN(ret, node, dup);
11227 }
11228
11229 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
11230
11231 if (idx < 0) {
11232 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
11233 rb_id2str(id));
11234 goto ng;
11235 }
11236 ADD_SETLOCAL(ret, node, ls - idx, lv);
11237 break;
11238 }
11239 case NODE_GASGN:{
11240 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
11241
11242 if (!popped) {
11243 ADD_INSN(ret, node, dup);
11244 }
11245 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
11246 break;
11247 }
11248 case NODE_IASGN:{
11249 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
11250 if (!popped) {
11251 ADD_INSN(ret, node, dup);
11252 }
11253 ADD_INSN2(ret, node, setinstancevariable,
11254 ID2SYM(RNODE_IASGN(node)->nd_vid),
11255 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
11256 break;
11257 }
11258 case NODE_CDECL:{
11259 if (RNODE_CDECL(node)->nd_vid) {
11260 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11261
11262 if (!popped) {
11263 ADD_INSN(ret, node, dup);
11264 }
11265
11266 ADD_INSN1(ret, node, putspecialobject,
11267 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
11268 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
11269 }
11270 else {
11271 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
11272 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11273 ADD_INSN(ret, node, swap);
11274
11275 if (!popped) {
11276 ADD_INSN1(ret, node, topn, INT2FIX(1));
11277 ADD_INSN(ret, node, swap);
11278 }
11279
11280 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
11281 }
11282 break;
11283 }
11284 case NODE_CVASGN:{
11285 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
11286 if (!popped) {
11287 ADD_INSN(ret, node, dup);
11288 }
11289 ADD_INSN2(ret, node, setclassvariable,
11290 ID2SYM(RNODE_CVASGN(node)->nd_vid),
11291 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
11292 break;
11293 }
11294 case NODE_OP_ASGN1:
11295 CHECK(compile_op_asgn1(iseq, ret, node, popped));
11296 break;
11297 case NODE_OP_ASGN2:
11298 CHECK(compile_op_asgn2(iseq, ret, node, popped));
11299 break;
11300 case NODE_OP_CDECL:
11301 CHECK(compile_op_cdecl(iseq, ret, node, popped));
11302 break;
11303 case NODE_OP_ASGN_AND:
11304 case NODE_OP_ASGN_OR:
11305 CHECK(compile_op_log(iseq, ret, node, popped, type));
11306 break;
11307 case NODE_CALL: /* obj.foo */
11308 case NODE_OPCALL: /* foo[] */
11309 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
11310 break;
11311 }
11312 case NODE_QCALL: /* obj&.foo */
11313 case NODE_FCALL: /* foo() */
11314 case NODE_VCALL: /* foo (variable or call) */
11315 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
11316 goto ng;
11317 }
11318 break;
11319 case NODE_SUPER:
11320 case NODE_ZSUPER:
11321 CHECK(compile_super(iseq, ret, node, popped, type));
11322 break;
11323 case NODE_LIST:{
11324 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
11325 break;
11326 }
11327 case NODE_ZLIST:{
11328 if (!popped) {
11329 ADD_INSN1(ret, node, newarray, INT2FIX(0));
11330 }
11331 break;
11332 }
11333 case NODE_HASH:
11334 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
11335 break;
11336 case NODE_RETURN:
11337 CHECK(compile_return(iseq, ret, node, popped));
11338 break;
11339 case NODE_YIELD:
11340 CHECK(compile_yield(iseq, ret, node, popped));
11341 break;
11342 case NODE_LVAR:{
11343 if (!popped) {
11344 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
11345 }
11346 break;
11347 }
11348 case NODE_DVAR:{
11349 int lv, idx, ls;
11350 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
11351 if (!popped) {
11352 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
11353 if (idx < 0) {
11354 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
11355 rb_id2str(RNODE_DVAR(node)->nd_vid));
11356 goto ng;
11357 }
11358 ADD_GETLOCAL(ret, node, ls - idx, lv);
11359 }
11360 break;
11361 }
11362 case NODE_GVAR:{
11363 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
11364 if (popped) {
11365 ADD_INSN(ret, node, pop);
11366 }
11367 break;
11368 }
11369 case NODE_IVAR:{
11370 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
11371 if (!popped) {
11372 ADD_INSN2(ret, node, getinstancevariable,
11373 ID2SYM(RNODE_IVAR(node)->nd_vid),
11374 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
11375 }
11376 break;
11377 }
11378 case NODE_CONST:{
11379 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
11380
11381 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
11382 body->ic_size++;
11383 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
11385 ADD_INSN1(ret, node, opt_getconstant_path, segments);
11386 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11387 }
11388 else {
11389 ADD_INSN(ret, node, putnil);
11390 ADD_INSN1(ret, node, putobject, Qtrue);
11391 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
11392 }
11393
11394 if (popped) {
11395 ADD_INSN(ret, node, pop);
11396 }
11397 break;
11398 }
11399 case NODE_CVAR:{
11400 if (!popped) {
11401 ADD_INSN2(ret, node, getclassvariable,
11402 ID2SYM(RNODE_CVAR(node)->nd_vid),
11403 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
11404 }
11405 break;
11406 }
11407 case NODE_NTH_REF:{
11408 if (!popped) {
11409 if (!RNODE_NTH_REF(node)->nd_nth) {
11410 ADD_INSN(ret, node, putnil);
11411 break;
11412 }
11413 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11414 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
11415 }
11416 break;
11417 }
11418 case NODE_BACK_REF:{
11419 if (!popped) {
11420 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11421 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
11422 }
11423 break;
11424 }
11425 case NODE_MATCH:
11426 case NODE_MATCH2:
11427 case NODE_MATCH3:
11428 CHECK(compile_match(iseq, ret, node, popped, type));
11429 break;
11430 case NODE_SYM:{
11431 if (!popped) {
11432 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
11433 }
11434 break;
11435 }
11436 case NODE_LINE:{
11437 if (!popped) {
11438 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
11439 }
11440 break;
11441 }
11442 case NODE_ENCODING:{
11443 if (!popped) {
11444 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11445 }
11446 break;
11447 }
11448 case NODE_INTEGER:{
11449 VALUE lit = rb_node_integer_literal_val(node);
11450 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11451 debugp_param("integer", lit);
11452 if (!popped) {
11453 ADD_INSN1(ret, node, putobject, lit);
11454 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11455 }
11456 break;
11457 }
11458 case NODE_FLOAT:{
11459 VALUE lit = rb_node_float_literal_val(node);
11460 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11461 debugp_param("float", lit);
11462 if (!popped) {
11463 ADD_INSN1(ret, node, putobject, lit);
11464 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11465 }
11466 break;
11467 }
11468 case NODE_RATIONAL:{
11469 VALUE lit = rb_node_rational_literal_val(node);
11471 debugp_param("rational", lit);
11472 if (!popped) {
11473 ADD_INSN1(ret, node, putobject, lit);
11474 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11475 }
11476 break;
11477 }
11478 case NODE_IMAGINARY:{
11479 VALUE lit = rb_node_imaginary_literal_val(node);
11481 debugp_param("imaginary", lit);
11482 if (!popped) {
11483 ADD_INSN1(ret, node, putobject, lit);
11484 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11485 }
11486 break;
11487 }
11488 case NODE_FILE:
11489 case NODE_STR:{
11490 debugp_param("nd_lit", get_string_value(node));
11491 if (!popped) {
11492 VALUE lit = get_string_value(node);
11493 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11494 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11495 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11496 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11498 }
11499 switch (option->frozen_string_literal) {
11500 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11501 ADD_INSN1(ret, node, dupchilledstring, lit);
11502 break;
11503 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11504 ADD_INSN1(ret, node, dupstring, lit);
11505 break;
11506 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11507 ADD_INSN1(ret, node, putobject, lit);
11508 break;
11509 default:
11510 rb_bug("invalid frozen_string_literal");
11511 }
11512 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11513 }
11514 break;
11515 }
11516 case NODE_DSTR:{
11517 compile_dstr(iseq, ret, node);
11518
11519 if (popped) {
11520 ADD_INSN(ret, node, pop);
11521 }
11522 break;
11523 }
11524 case NODE_XSTR:{
11525 ADD_CALL_RECEIVER(ret, node);
11526 VALUE str = rb_node_str_string_val(node);
11527 ADD_INSN1(ret, node, putobject, str);
11528 RB_OBJ_WRITTEN(iseq, Qundef, str);
11529 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11530
11531 if (popped) {
11532 ADD_INSN(ret, node, pop);
11533 }
11534 break;
11535 }
11536 case NODE_DXSTR:{
11537 ADD_CALL_RECEIVER(ret, node);
11538 compile_dstr(iseq, ret, node);
11539 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11540
11541 if (popped) {
11542 ADD_INSN(ret, node, pop);
11543 }
11544 break;
11545 }
11546 case NODE_EVSTR:
11547 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11548 break;
11549 case NODE_REGX:{
11550 if (!popped) {
11551 VALUE lit = rb_node_regx_string_val(node);
11553 ADD_INSN1(ret, node, putobject, lit);
11554 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11555 }
11556 break;
11557 }
11558 case NODE_DREGX:
11559 compile_dregx(iseq, ret, node, popped);
11560 break;
11561 case NODE_ONCE:{
11562 int ic_index = body->ise_size++;
11563 const rb_iseq_t *block_iseq;
11564 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11565
11566 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11567 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11568
11569 if (popped) {
11570 ADD_INSN(ret, node, pop);
11571 }
11572 break;
11573 }
11574 case NODE_ARGSCAT:{
11575 if (popped) {
11576 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11577 ADD_INSN1(ret, node, splatarray, Qfalse);
11578 ADD_INSN(ret, node, pop);
11579 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11580 ADD_INSN1(ret, node, splatarray, Qfalse);
11581 ADD_INSN(ret, node, pop);
11582 }
11583 else {
11584 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11585 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11586 if (nd_type_p(body_node, NODE_LIST)) {
11587 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11588 }
11589 else {
11590 CHECK(COMPILE(ret, "argscat body", body_node));
11591 ADD_INSN(ret, node, concattoarray);
11592 }
11593 }
11594 break;
11595 }
11596 case NODE_ARGSPUSH:{
11597 if (popped) {
11598 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11599 ADD_INSN1(ret, node, splatarray, Qfalse);
11600 ADD_INSN(ret, node, pop);
11601 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11602 }
11603 else {
11604 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11605 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11606 if (keyword_node_p(body_node)) {
11607 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11608 ADD_INSN(ret, node, pushtoarraykwsplat);
11609 }
11610 else if (static_literal_node_p(body_node, iseq, false)) {
11611 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11612 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11613 }
11614 else {
11615 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11616 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11617 }
11618 }
11619 break;
11620 }
11621 case NODE_SPLAT:{
11622 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11623 ADD_INSN1(ret, node, splatarray, Qtrue);
11624
11625 if (popped) {
11626 ADD_INSN(ret, node, pop);
11627 }
11628 break;
11629 }
11630 case NODE_DEFN:{
11631 ID mid = RNODE_DEFN(node)->nd_mid;
11632 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11633 rb_id2str(mid),
11634 ISEQ_TYPE_METHOD, line);
11635
11636 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11637 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11638 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11639
11640 if (!popped) {
11641 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11642 }
11643
11644 break;
11645 }
11646 case NODE_DEFS:{
11647 ID mid = RNODE_DEFS(node)->nd_mid;
11648 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11649 rb_id2str(mid),
11650 ISEQ_TYPE_METHOD, line);
11651
11652 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11653 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11654 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11655 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11656
11657 if (!popped) {
11658 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11659 }
11660 break;
11661 }
11662 case NODE_ALIAS:{
11663 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11664 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11665 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11666 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11667 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11668
11669 if (popped) {
11670 ADD_INSN(ret, node, pop);
11671 }
11672 break;
11673 }
11674 case NODE_VALIAS:{
11675 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11676 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11677 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11678 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11679
11680 if (popped) {
11681 ADD_INSN(ret, node, pop);
11682 }
11683 break;
11684 }
11685 case NODE_UNDEF:{
11686 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11687
11688 for (long i = 0; i < ary->len; i++) {
11689 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11690 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11691 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11692 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11693
11694 if (i < ary->len - 1) {
11695 ADD_INSN(ret, node, pop);
11696 }
11697 }
11698
11699 if (popped) {
11700 ADD_INSN(ret, node, pop);
11701 }
11702 break;
11703 }
11704 case NODE_CLASS:{
11705 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11706 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11707 ISEQ_TYPE_CLASS, line);
11708 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11709 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11710 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11711
11712 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11713 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11714 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11715
11716 if (popped) {
11717 ADD_INSN(ret, node, pop);
11718 }
11719 break;
11720 }
11721 case NODE_MODULE:{
11722 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11723 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11724 ISEQ_TYPE_CLASS, line);
11725 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11726 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11727
11728 ADD_INSN (ret, node, putnil); /* dummy */
11729 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11730 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11731
11732 if (popped) {
11733 ADD_INSN(ret, node, pop);
11734 }
11735 break;
11736 }
11737 case NODE_SCLASS:{
11738 ID singletonclass;
11739 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11740 ISEQ_TYPE_CLASS, line);
11741
11742 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11743 ADD_INSN (ret, node, putnil);
11744 CONST_ID(singletonclass, "singletonclass");
11745
11746 /* `class << self` in a class body and `class << Foo` (constant
11747 receiver) are stable. All other forms are potentially dynamic. */
11748 int sclass_flags = VM_DEFINECLASS_TYPE_SINGLETON_CLASS;
11749 const NODE *recv = RNODE_SCLASS(node)->nd_recv;
11750 if (!(nd_type_p(recv, NODE_SELF) &&
11751 ISEQ_BODY(iseq)->type == ISEQ_TYPE_CLASS) &&
11752 !cpath_const_p(recv)) {
11753 sclass_flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF;
11754 }
11755
11756 ADD_INSN3(ret, node, defineclass,
11757 ID2SYM(singletonclass), singleton_class,
11758 INT2FIX(sclass_flags));
11759 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11760
11761 if (popped) {
11762 ADD_INSN(ret, node, pop);
11763 }
11764 break;
11765 }
11766 case NODE_COLON2:
11767 CHECK(compile_colon2(iseq, ret, node, popped));
11768 break;
11769 case NODE_COLON3:
11770 CHECK(compile_colon3(iseq, ret, node, popped));
11771 break;
11772 case NODE_DOT2:
11773 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11774 break;
11775 case NODE_DOT3:
11776 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11777 break;
11778 case NODE_FLIP2:
11779 case NODE_FLIP3:{
11780 LABEL *lend = NEW_LABEL(line);
11781 LABEL *ltrue = NEW_LABEL(line);
11782 LABEL *lfalse = NEW_LABEL(line);
11783 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11784 ltrue, lfalse));
11785 ADD_LABEL(ret, ltrue);
11786 ADD_INSN1(ret, node, putobject, Qtrue);
11787 ADD_INSNL(ret, node, jump, lend);
11788 ADD_LABEL(ret, lfalse);
11789 ADD_INSN1(ret, node, putobject, Qfalse);
11790 ADD_LABEL(ret, lend);
11791 break;
11792 }
11793 case NODE_SELF:{
11794 if (!popped) {
11795 ADD_INSN(ret, node, putself);
11796 }
11797 break;
11798 }
11799 case NODE_NIL:{
11800 if (!popped) {
11801 ADD_INSN(ret, node, putnil);
11802 }
11803 break;
11804 }
11805 case NODE_TRUE:{
11806 if (!popped) {
11807 ADD_INSN1(ret, node, putobject, Qtrue);
11808 }
11809 break;
11810 }
11811 case NODE_FALSE:{
11812 if (!popped) {
11813 ADD_INSN1(ret, node, putobject, Qfalse);
11814 }
11815 break;
11816 }
11817 case NODE_ERRINFO:
11818 CHECK(compile_errinfo(iseq, ret, node, popped));
11819 break;
11820 case NODE_DEFINED:
11821 if (!popped) {
11822 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11823 }
11824 break;
11825 case NODE_POSTEXE:{
11826 /* compiled to:
11827 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11828 */
11829 int is_index = body->ise_size++;
11831 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11832 const rb_iseq_t *once_iseq =
11833 NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc, rb_fstring(make_name_for_block(iseq)), ISEQ_TYPE_BLOCK, line);
11834
11835 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11836 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11837
11838 if (popped) {
11839 ADD_INSN(ret, node, pop);
11840 }
11841 break;
11842 }
11843 case NODE_KW_ARG:
11844 CHECK(compile_kw_arg(iseq, ret, node, popped));
11845 break;
11846 case NODE_DSYM:{
11847 compile_dstr(iseq, ret, node);
11848 if (!popped) {
11849 ADD_INSN(ret, node, intern);
11850 }
11851 else {
11852 ADD_INSN(ret, node, pop);
11853 }
11854 break;
11855 }
11856 case NODE_ATTRASGN:
11857 CHECK(compile_attrasgn(iseq, ret, node, popped));
11858 break;
11859 case NODE_LAMBDA:{
11860 /* compile same as lambda{...} */
11861 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11862 VALUE argc = INT2FIX(0);
11863
11864 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11865 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11866 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11867
11868 if (popped) {
11869 ADD_INSN(ret, node, pop);
11870 }
11871 break;
11872 }
11873 default:
11874 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11875 ng:
11876 debug_node_end();
11877 return COMPILE_NG;
11878 }
11879
11880 debug_node_end();
11881 return COMPILE_OK;
11882}
11883
11884/***************************/
11885/* instruction information */
11886/***************************/
11887
11888static int
11889insn_data_length(INSN *iobj)
11890{
11891 return insn_len(iobj->insn_id);
11892}
11893
11894static int
11895calc_sp_depth(int depth, INSN *insn)
11896{
11897 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11898}
11899
11900static VALUE
11901opobj_inspect(VALUE obj)
11902{
11903 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11904 switch (BUILTIN_TYPE(obj)) {
11905 case T_STRING:
11906 obj = rb_str_resurrect(obj);
11907 break;
11908 case T_ARRAY:
11909 obj = rb_ary_resurrect(obj);
11910 break;
11911 default:
11912 break;
11913 }
11914 }
11915 return rb_inspect(obj);
11916}
11917
11918
11919
11920static VALUE
11921insn_data_to_s_detail(INSN *iobj)
11922{
11923 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11924
11925 if (iobj->operands) {
11926 const char *types = insn_op_types(iobj->insn_id);
11927 int j;
11928
11929 for (j = 0; types[j]; j++) {
11930 char type = types[j];
11931
11932 switch (type) {
11933 case TS_OFFSET: /* label(destination position) */
11934 {
11935 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11936 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11937 break;
11938 }
11939 break;
11940 case TS_ISEQ: /* iseq */
11941 {
11942 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11943 VALUE val = Qnil;
11944 if (0 && iseq) { /* TODO: invalidate now */
11945 val = (VALUE)iseq;
11946 }
11947 rb_str_concat(str, opobj_inspect(val));
11948 }
11949 break;
11950 case TS_LINDEX:
11951 case TS_NUM: /* ulong */
11952 case TS_VALUE: /* VALUE */
11953 {
11954 VALUE v = OPERAND_AT(iobj, j);
11955 if (!CLASS_OF(v))
11956 rb_str_cat2(str, "<hidden>");
11957 else {
11958 rb_str_concat(str, opobj_inspect(v));
11959 }
11960 break;
11961 }
11962 case TS_ID: /* ID */
11963 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11964 break;
11965 case TS_IC: /* inline cache */
11966 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11967 break;
11968 case TS_IVC: /* inline ivar cache */
11969 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11970 break;
11971 case TS_ICVARC: /* inline cvar cache */
11972 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11973 break;
11974 case TS_ISE: /* inline storage entry */
11975 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11976 break;
11977 case TS_CALLDATA: /* we store these as call infos at compile time */
11978 {
11979 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11980 rb_str_cat2(str, "<calldata:");
11981 if (vm_ci_mid(ci)) rb_str_append(str, rb_id2str(vm_ci_mid(ci)));
11982 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11983 break;
11984 }
11985 case TS_CDHASH: /* case/when condition cache */
11986 rb_str_cat2(str, "<ch>");
11987 break;
11988 case TS_FUNCPTR:
11989 {
11990 void *func = (void *)OPERAND_AT(iobj, j);
11991#ifdef HAVE_DLADDR
11992 Dl_info info;
11993 if (dladdr(func, &info) && info.dli_sname) {
11994 rb_str_cat2(str, info.dli_sname);
11995 break;
11996 }
11997#endif
11998 rb_str_catf(str, "<%p>", func);
11999 }
12000 break;
12001 case TS_BUILTIN:
12002 rb_str_cat2(str, "<TS_BUILTIN>");
12003 break;
12004 default:{
12005 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
12006 }
12007 }
12008 if (types[j + 1]) {
12009 rb_str_cat2(str, ", ");
12010 }
12011 }
12012 }
12013 return str;
12014}
12015
12016static void
12017dump_disasm_list(const LINK_ELEMENT *link)
12018{
12019 dump_disasm_list_with_cursor(link, NULL, NULL);
12020}
12021
12022static void
12023dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
12024{
12025 int pos = 0;
12026 INSN *iobj;
12027 LABEL *lobj;
12028 VALUE str;
12029
12030 printf("-- raw disasm--------\n");
12031
12032 while (link) {
12033 if (curr) printf(curr == link ? "*" : " ");
12034 switch (link->type) {
12035 case ISEQ_ELEMENT_INSN:
12036 {
12037 iobj = (INSN *)link;
12038 str = insn_data_to_s_detail(iobj);
12039 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
12040 pos += insn_data_length(iobj);
12041 break;
12042 }
12043 case ISEQ_ELEMENT_LABEL:
12044 {
12045 lobj = (LABEL *)link;
12046 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
12047 dest == lobj ? " <---" : "");
12048 break;
12049 }
12050 case ISEQ_ELEMENT_TRACE:
12051 {
12052 TRACE *trace = (TRACE *)link;
12053 printf(" trace: %0x\n", trace->event);
12054 break;
12055 }
12056 case ISEQ_ELEMENT_ADJUST:
12057 {
12058 ADJUST *adjust = (ADJUST *)link;
12059 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
12060 break;
12061 }
12062 default:
12063 /* ignore */
12064 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
12065 }
12066 link = link->next;
12067 }
12068 printf("---------------------\n");
12069 fflush(stdout);
12070}
12071
12072int
12073rb_insn_len(VALUE insn)
12074{
12075 return insn_len(insn);
12076}
12077
12078const char *
12079rb_insns_name(int i)
12080{
12081 return insn_name(i);
12082}
12083
12084VALUE
12085rb_insns_name_array(void)
12086{
12087 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
12088 int i;
12089 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
12090 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
12091 }
12092 return rb_ary_freeze(ary);
12093}
12094
12095static LABEL *
12096register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
12097{
12098 LABEL *label = 0;
12099 st_data_t tmp;
12100 obj = rb_to_symbol_type(obj);
12101
12102 if (st_lookup(labels_table, obj, &tmp) == 0) {
12103 label = NEW_LABEL(0);
12104 st_insert(labels_table, obj, (st_data_t)label);
12105 }
12106 else {
12107 label = (LABEL *)tmp;
12108 }
12109 LABEL_REF(label);
12110 return label;
12111}
12112
12113static VALUE
12114get_exception_sym2type(VALUE sym)
12115{
12116 static VALUE symRescue, symEnsure, symRetry;
12117 static VALUE symBreak, symRedo, symNext;
12118
12119 if (symRescue == 0) {
12120 symRescue = ID2SYM(rb_intern_const("rescue"));
12121 symEnsure = ID2SYM(rb_intern_const("ensure"));
12122 symRetry = ID2SYM(rb_intern_const("retry"));
12123 symBreak = ID2SYM(rb_intern_const("break"));
12124 symRedo = ID2SYM(rb_intern_const("redo"));
12125 symNext = ID2SYM(rb_intern_const("next"));
12126 }
12127
12128 if (sym == symRescue) return CATCH_TYPE_RESCUE;
12129 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
12130 if (sym == symRetry) return CATCH_TYPE_RETRY;
12131 if (sym == symBreak) return CATCH_TYPE_BREAK;
12132 if (sym == symRedo) return CATCH_TYPE_REDO;
12133 if (sym == symNext) return CATCH_TYPE_NEXT;
12134 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
12135 return 0;
12136}
12137
12138static int
12139iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
12140 VALUE exception)
12141{
12142 int i;
12143
12144 for (i=0; i<RARRAY_LEN(exception); i++) {
12145 const rb_iseq_t *eiseq;
12146 VALUE v, type;
12147 LABEL *lstart, *lend, *lcont;
12148 unsigned int sp;
12149
12150 v = rb_to_array_type(RARRAY_AREF(exception, i));
12151 if (RARRAY_LEN(v) != 6) {
12152 rb_raise(rb_eSyntaxError, "wrong exception entry");
12153 }
12154 type = get_exception_sym2type(RARRAY_AREF(v, 0));
12155 if (NIL_P(RARRAY_AREF(v, 1))) {
12156 eiseq = NULL;
12157 }
12158 else {
12159 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
12160 }
12161
12162 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
12163 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
12164 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
12165 sp = NUM2UINT(RARRAY_AREF(v, 5));
12166
12167 /* TODO: Dirty Hack! Fix me */
12168 if (type == CATCH_TYPE_RESCUE ||
12169 type == CATCH_TYPE_BREAK ||
12170 type == CATCH_TYPE_NEXT) {
12171 ++sp;
12172 }
12173
12174 lcont->sp = sp;
12175
12176 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
12177
12178 RB_GC_GUARD(v);
12179 }
12180 return COMPILE_OK;
12181}
12182
12183static struct st_table *
12184insn_make_insn_table(void)
12185{
12186 struct st_table *table;
12187 int i;
12188 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
12189
12190 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
12191 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
12192 }
12193
12194 return table;
12195}
12196
12197static const rb_iseq_t *
12198iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
12199{
12200 VALUE iseqw;
12201 const rb_iseq_t *loaded_iseq;
12202
12203 if (RB_TYPE_P(op, T_ARRAY)) {
12204 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
12205 }
12206 else if (CLASS_OF(op) == rb_cISeq) {
12207 iseqw = op;
12208 }
12209 else {
12210 rb_raise(rb_eSyntaxError, "ISEQ is required");
12211 }
12212
12213 loaded_iseq = rb_iseqw_to_iseq(iseqw);
12214 return loaded_iseq;
12215}
12216
12217static VALUE
12218iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
12219{
12220 ID mid = 0;
12221 int orig_argc = 0;
12222 unsigned int flag = 0;
12223 struct rb_callinfo_kwarg *kw_arg = 0;
12224
12225 if (!NIL_P(op)) {
12226 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
12227 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
12228 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
12229 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
12230
12231 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
12232 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
12233 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
12234
12235 if (!NIL_P(vkw_arg)) {
12236 int i;
12237 int len = RARRAY_LENINT(vkw_arg);
12238 size_t n = rb_callinfo_kwarg_bytes(len);
12239
12240 kw_arg = xmalloc(n);
12241 kw_arg->references = 0;
12242 kw_arg->keyword_len = len;
12243 for (i = 0; i < len; i++) {
12244 VALUE kw = RARRAY_AREF(vkw_arg, i);
12245 SYM2ID(kw); /* make immortal */
12246 kw_arg->keywords[i] = kw;
12247 }
12248 }
12249 }
12250
12251 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
12252 RB_OBJ_WRITTEN(iseq, Qundef, ci);
12253 return (VALUE)ci;
12254}
12255
12256static rb_event_flag_t
12257event_name_to_flag(VALUE sym)
12258{
12259#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
12260 CHECK_EVENT(RUBY_EVENT_LINE);
12261 CHECK_EVENT(RUBY_EVENT_CLASS);
12262 CHECK_EVENT(RUBY_EVENT_END);
12263 CHECK_EVENT(RUBY_EVENT_CALL);
12264 CHECK_EVENT(RUBY_EVENT_RETURN);
12265 CHECK_EVENT(RUBY_EVENT_B_CALL);
12266 CHECK_EVENT(RUBY_EVENT_B_RETURN);
12267 CHECK_EVENT(RUBY_EVENT_RESCUE);
12268#undef CHECK_EVENT
12269 return RUBY_EVENT_NONE;
12270}
12271
12272static int
12273iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
12274 VALUE body, VALUE node_ids, VALUE labels_wrapper)
12275{
12276 /* TODO: body should be frozen */
12277 long i, len = RARRAY_LEN(body);
12278 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
12279 int j;
12280 int line_no = 0, node_id = -1, insn_idx = 0;
12281 int ret = COMPILE_OK;
12282
12283 /*
12284 * index -> LABEL *label
12285 */
12286 static struct st_table *insn_table;
12287
12288 if (insn_table == 0) {
12289 insn_table = insn_make_insn_table();
12290 }
12291
12292 for (i=0; i<len; i++) {
12293 VALUE obj = RARRAY_AREF(body, i);
12294
12295 if (SYMBOL_P(obj)) {
12296 rb_event_flag_t event;
12297 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
12298 ADD_TRACE(anchor, event);
12299 }
12300 else {
12301 LABEL *label = register_label(iseq, labels_table, obj);
12302 ADD_LABEL(anchor, label);
12303 }
12304 }
12305 else if (FIXNUM_P(obj)) {
12306 line_no = NUM2INT(obj);
12307 }
12308 else if (RB_TYPE_P(obj, T_ARRAY)) {
12309 VALUE *argv = 0;
12310 int argc = RARRAY_LENINT(obj) - 1;
12311 st_data_t insn_id;
12312 VALUE insn;
12313
12314 if (node_ids) {
12315 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
12316 }
12317
12318 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
12319 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
12320 /* TODO: exception */
12321 COMPILE_ERROR(iseq, line_no,
12322 "unknown instruction: %+"PRIsVALUE, insn);
12323 ret = COMPILE_NG;
12324 break;
12325 }
12326
12327 if (argc != insn_len((VALUE)insn_id)-1) {
12328 COMPILE_ERROR(iseq, line_no,
12329 "operand size mismatch");
12330 ret = COMPILE_NG;
12331 break;
12332 }
12333
12334 if (argc > 0) {
12335 argv = compile_data_calloc2_type(iseq, VALUE, argc);
12336
12337 // add element before operand setup to make GC root
12338 ADD_ELEM(anchor,
12339 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12340 (enum ruby_vminsn_type)insn_id, argc, argv));
12341
12342 for (j=0; j<argc; j++) {
12343 VALUE op = rb_ary_entry(obj, j+1);
12344 switch (insn_op_type((VALUE)insn_id, j)) {
12345 case TS_OFFSET: {
12346 LABEL *label = register_label(iseq, labels_table, op);
12347 argv[j] = (VALUE)label;
12348 break;
12349 }
12350 case TS_LINDEX:
12351 case TS_NUM:
12352 (void)NUM2INT(op);
12353 argv[j] = op;
12354 break;
12355 case TS_VALUE:
12356 argv[j] = op;
12357 RB_OBJ_WRITTEN(iseq, Qundef, op);
12358 break;
12359 case TS_ISEQ:
12360 {
12361 if (op != Qnil) {
12362 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
12363 argv[j] = v;
12364 RB_OBJ_WRITTEN(iseq, Qundef, v);
12365 }
12366 else {
12367 argv[j] = 0;
12368 }
12369 }
12370 break;
12371 case TS_ISE:
12372 argv[j] = op;
12373 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
12374 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
12375 }
12376 break;
12377 case TS_IC:
12378 {
12379 VALUE segments = rb_ary_new();
12380 op = rb_to_array_type(op);
12381
12382 for (int i = 0; i < RARRAY_LEN(op); i++) {
12383 VALUE sym = RARRAY_AREF(op, i);
12384 sym = rb_to_symbol_type(sym);
12385 rb_ary_push(segments, sym);
12386 }
12387
12388 RB_GC_GUARD(op);
12389 argv[j] = segments;
12390 RB_OBJ_WRITTEN(iseq, Qundef, segments);
12391 ISEQ_BODY(iseq)->ic_size++;
12392 }
12393 break;
12394 case TS_IVC: /* inline ivar cache */
12395 argv[j] = op;
12396 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
12397 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
12398 }
12399 break;
12400 case TS_ICVARC: /* inline cvar cache */
12401 argv[j] = op;
12402 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
12403 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
12404 }
12405 break;
12406 case TS_CALLDATA:
12407 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
12408 break;
12409 case TS_ID:
12410 argv[j] = rb_to_symbol_type(op);
12411 break;
12412 case TS_CDHASH:
12413 {
12414 int i;
12415 VALUE map = cdhash_new(RARRAY_LEN(op) / 2);
12416
12417 op = rb_to_array_type(op);
12418 for (i=0; i<RARRAY_LEN(op); i+=2) {
12419 VALUE key = RARRAY_AREF(op, i);
12420 VALUE sym = RARRAY_AREF(op, i+1);
12421 LABEL *label =
12422 register_label(iseq, labels_table, sym);
12423 cdhash_aset(map, key, (VALUE)label);
12424 }
12425 RB_GC_GUARD(op);
12426 RB_OBJ_SET_SHAREABLE(map); // allow mutation while compiling
12427 argv[j] = map;
12428 RB_OBJ_WRITTEN(iseq, Qundef, map);
12429 }
12430 break;
12431 case TS_FUNCPTR:
12432 {
12433#if SIZEOF_VALUE <= SIZEOF_LONG
12434 long funcptr = NUM2LONG(op);
12435#else
12436 LONG_LONG funcptr = NUM2LL(op);
12437#endif
12438 argv[j] = (VALUE)funcptr;
12439 }
12440 break;
12441 default:
12442 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
12443 }
12444 }
12445 }
12446 else {
12447 ADD_ELEM(anchor,
12448 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12449 (enum ruby_vminsn_type)insn_id, argc, NULL));
12450 }
12451 }
12452 else {
12453 rb_raise(rb_eTypeError, "unexpected object for instruction");
12454 }
12455 }
12456 RTYPEDDATA_DATA(labels_wrapper) = 0;
12457 RB_GC_GUARD(labels_wrapper);
12458 validate_labels(iseq, labels_table);
12459 if (!ret) return ret;
12460 return iseq_setup(iseq, anchor);
12461}
12462
12463#define CHECK_ARRAY(v) rb_to_array_type(v)
12464#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12465
12466static int
12467int_param(int *dst, VALUE param, VALUE sym)
12468{
12469 VALUE val = rb_hash_aref(param, sym);
12470 if (FIXNUM_P(val)) {
12471 *dst = FIX2INT(val);
12472 return TRUE;
12473 }
12474 else if (!NIL_P(val)) {
12475 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
12476 sym, val);
12477 }
12478 return FALSE;
12479}
12480
12481static const struct rb_iseq_param_keyword *
12482iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12483{
12484 int i, j;
12485 int len = RARRAY_LENINT(keywords);
12486 int default_len;
12487 VALUE key, sym, default_val;
12488 VALUE *dvs;
12489 ID *ids;
12490 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12491
12492 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12493
12494 keyword->num = len;
12495#define SYM(s) ID2SYM(rb_intern_const(#s))
12496 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12497 i = keyword->bits_start - keyword->num;
12498 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12499#undef SYM
12500
12501 /* required args */
12502 for (i = 0; i < len; i++) {
12503 VALUE val = RARRAY_AREF(keywords, i);
12504
12505 if (!SYMBOL_P(val)) {
12506 goto default_values;
12507 }
12508 ids[i] = SYM2ID(val);
12509 keyword->required_num++;
12510 }
12511
12512 default_values: /* note: we intentionally preserve `i' from previous loop */
12513 default_len = len - i;
12514 if (default_len == 0) {
12515 keyword->table = ids;
12516 return keyword;
12517 }
12518 else if (default_len < 0) {
12520 }
12521
12522 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12523
12524 for (j = 0; i < len; i++, j++) {
12525 key = RARRAY_AREF(keywords, i);
12526 CHECK_ARRAY(key);
12527
12528 switch (RARRAY_LEN(key)) {
12529 case 1:
12530 sym = RARRAY_AREF(key, 0);
12531 default_val = Qundef;
12532 break;
12533 case 2:
12534 sym = RARRAY_AREF(key, 0);
12535 default_val = RARRAY_AREF(key, 1);
12536 break;
12537 default:
12538 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12539 }
12540 ids[i] = SYM2ID(sym);
12541 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12542 }
12543
12544 keyword->table = ids;
12545 keyword->default_values = dvs;
12546
12547 return keyword;
12548}
12549
12550static void
12551iseq_insn_each_object_mark_and_move(VALUE * obj, VALUE _)
12552{
12553 rb_gc_mark_and_move(obj);
12554}
12555
12556void
12557rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
12558{
12559 INSN *iobj = 0;
12560 size_t size = sizeof(INSN);
12561 size_t align = ALIGNMENT_SIZE_OF(INSN);
12562 unsigned int pos = 0;
12563
12564 while (storage) {
12565 size_t padding = calc_padding((void *)&storage->buff[pos], align);
12566 size_t offset = pos + size + padding;
12567 if (offset > storage->size || offset > storage->pos) {
12568 pos = 0;
12569 storage = storage->next;
12570 }
12571 else {
12572 pos += (int)padding;
12573
12574 iobj = (INSN *)&storage->buff[pos];
12575
12576 if (iobj->operands) {
12577 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (VALUE)0);
12578 }
12579 pos += (int)size;
12580 }
12581 }
12582}
12583
12584static const rb_data_type_t labels_wrapper_type = {
12585 .wrap_struct_name = "compiler/labels_wrapper",
12586 .function = {
12587 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12588 .dfree = (RUBY_DATA_FUNC)st_free_table,
12589 },
12590 .flags = RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED,
12591};
12592
12593void
12594rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12595 VALUE exception, VALUE body)
12596{
12597#define SYM(s) ID2SYM(rb_intern_const(#s))
12598 int i, len;
12599 unsigned int arg_size, local_size, stack_max;
12600 ID *tbl;
12601 struct st_table *labels_table = st_init_numtable();
12602 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12603 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12604 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12605 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12606 DECL_ANCHOR(anchor);
12607 INIT_ANCHOR(anchor);
12608
12609 len = RARRAY_LENINT(locals);
12610 ISEQ_BODY(iseq)->local_table_size = len;
12611 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12612
12613 for (i = 0; i < len; i++) {
12614 VALUE lv = RARRAY_AREF(locals, i);
12615
12616 if (sym_arg_rest == lv) {
12617 tbl[i] = 0;
12618 }
12619 else {
12620 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12621 }
12622 }
12623
12624#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12625 if (INT_PARAM(lead_num)) {
12626 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12627 }
12628 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12629 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12630 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12631 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12632#undef INT_PARAM
12633 {
12634#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12635 int x;
12636 INT_PARAM(arg_size);
12637 INT_PARAM(local_size);
12638 INT_PARAM(stack_max);
12639#undef INT_PARAM
12640 }
12641
12642 VALUE source_hash = rb_hash_aref(misc, ID2SYM(rb_intern("source_hash")));
12643 if (!NIL_P(source_hash)) {
12644 ISEQ_BODY(iseq)->source_hash = NUM2ULL(source_hash);
12645 }
12646
12647 VALUE node_ids = Qfalse;
12648#ifdef USE_ISEQ_NODE_ID
12649 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12650 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12651 rb_raise(rb_eTypeError, "node_ids is not an array");
12652 }
12653#endif
12654
12655 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12656 len = RARRAY_LENINT(arg_opt_labels);
12657 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12658
12659 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12660 VALUE *opt_table = ALLOC_N(VALUE, len);
12661
12662 for (i = 0; i < len; i++) {
12663 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12664 LABEL *label = register_label(iseq, labels_table, ent);
12665 opt_table[i] = (VALUE)label;
12666 }
12667
12668 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12669 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12670 }
12671 }
12672 else if (!NIL_P(arg_opt_labels)) {
12673 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12674 arg_opt_labels);
12675 }
12676
12677 if (RB_TYPE_P(keywords, T_ARRAY)) {
12678 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12679 }
12680 else if (!NIL_P(keywords)) {
12681 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12682 keywords);
12683 }
12684
12685 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12686 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12687 }
12688
12689 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12690 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12691 }
12692
12693 if (int_param(&i, params, SYM(kwrest))) {
12694 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12695 if (keyword == NULL) {
12696 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12697 }
12698 keyword->rest_start = i;
12699 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12700 }
12701#undef SYM
12702 iseq_calc_param_size(iseq);
12703
12704 /* exception */
12705 iseq_build_from_ary_exception(iseq, labels_table, exception);
12706
12707 /* body */
12708 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12709
12710 ISEQ_BODY(iseq)->param.size = arg_size;
12711 ISEQ_BODY(iseq)->local_table_size = local_size;
12712 ISEQ_BODY(iseq)->stack_max = stack_max;
12713}
12714
12715/* for parser */
12716
12717int
12718rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12719{
12720 if (iseq) {
12721 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12722 while (body->type == ISEQ_TYPE_BLOCK ||
12723 body->type == ISEQ_TYPE_RESCUE ||
12724 body->type == ISEQ_TYPE_ENSURE ||
12725 body->type == ISEQ_TYPE_EVAL ||
12726 body->type == ISEQ_TYPE_MAIN
12727 ) {
12728 unsigned int i;
12729
12730 for (i = 0; i < body->local_table_size; i++) {
12731 if (body->local_table[i] == id) {
12732 return 1;
12733 }
12734 }
12735 iseq = body->parent_iseq;
12736 body = ISEQ_BODY(iseq);
12737 }
12738 }
12739 return 0;
12740}
12741
12742int
12743rb_local_defined(ID id, const rb_iseq_t *iseq)
12744{
12745 if (iseq) {
12746 unsigned int i;
12747 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12748
12749 for (i=0; i<body->local_table_size; i++) {
12750 if (body->local_table[i] == id) {
12751 return 1;
12752 }
12753 }
12754 }
12755 return 0;
12756}
12757
12758/* ISeq binary format */
12759
12760#ifndef IBF_ISEQ_DEBUG
12761#define IBF_ISEQ_DEBUG 0
12762#endif
12763
12764#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12765#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12766#endif
12767
12768typedef uint32_t ibf_offset_t;
12769#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12770
12771#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12772#ifdef RUBY_DEVEL
12773#define IBF_DEVEL_VERSION 8
12774#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12775#else
12776#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12777#endif
12778
12779static const char IBF_ENDIAN_MARK =
12780#ifdef WORDS_BIGENDIAN
12781 'b'
12782#else
12783 'l'
12784#endif
12785 ;
12786
12788 char magic[4]; /* YARB */
12789 uint32_t major_version;
12790 uint32_t minor_version;
12791 uint32_t size;
12792 uint32_t extra_size;
12793
12794 uint32_t iseq_list_size;
12795 uint32_t global_object_list_size;
12796 ibf_offset_t iseq_list_offset;
12797 ibf_offset_t global_object_list_offset;
12798 uint8_t endian;
12799 uint8_t wordsize; /* assume no 2048-bit CPU */
12800};
12801
12803 VALUE str;
12804 st_table *obj_table; /* obj -> obj number */
12805};
12806
12807struct ibf_dump {
12808 st_table *iseq_table; /* iseq -> iseq number */
12809 struct ibf_dump_buffer global_buffer;
12810 struct ibf_dump_buffer *current_buffer;
12811};
12812
12814 const char *buff;
12815 ibf_offset_t size;
12816
12817 VALUE obj_list; /* [obj0, ...] */
12818 unsigned int obj_list_size;
12819 ibf_offset_t obj_list_offset;
12820};
12821
12822struct ibf_load {
12823 const struct ibf_header *header;
12824 VALUE iseq_list; /* [iseq0, ...] */
12825 struct ibf_load_buffer global_buffer;
12826 VALUE loader_obj;
12827 rb_iseq_t *iseq;
12828 VALUE str;
12829 struct ibf_load_buffer *current_buffer;
12830};
12831
12833 long size;
12834 VALUE buffer[1];
12835};
12836
12837static void
12838pinned_list_mark(void *ptr)
12839{
12840 long i;
12841 struct pinned_list *list = (struct pinned_list *)ptr;
12842 for (i = 0; i < list->size; i++) {
12843 if (list->buffer[i]) {
12844 rb_gc_mark(list->buffer[i]);
12845 }
12846 }
12847}
12848
12849static const rb_data_type_t pinned_list_type = {
12850 "pinned_list",
12851 {
12852 pinned_list_mark,
12854 NULL, // No external memory to report,
12855 },
12856 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_EMBEDDABLE
12857};
12858
12859static VALUE
12860pinned_list_fetch(VALUE list, long offset)
12861{
12862 struct pinned_list * ptr;
12863
12864 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12865
12866 if (offset < 0 || offset >= ptr->size) {
12867 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12868 }
12869
12870 return ptr->buffer[offset];
12871}
12872
12873static void
12874pinned_list_store(VALUE list, long offset, VALUE object)
12875{
12876 struct pinned_list * ptr;
12877
12878 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12879
12880 if (offset < 0 || offset >= ptr->size) {
12881 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12882 }
12883
12884 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12885}
12886
12887static VALUE
12888pinned_list_new(long size)
12889{
12890 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12891 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12892 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12893 ptr->size = size;
12894 return obj_list;
12895}
12896
12897static ibf_offset_t
12898ibf_dump_pos(struct ibf_dump *dump)
12899{
12900 long pos = RSTRING_LEN(dump->current_buffer->str);
12901#if SIZEOF_LONG > SIZEOF_INT
12902 if (pos >= UINT_MAX) {
12903 rb_raise(rb_eRuntimeError, "dump size exceeds");
12904 }
12905#endif
12906 return (unsigned int)pos;
12907}
12908
12909static void
12910ibf_dump_align(struct ibf_dump *dump, size_t align)
12911{
12912 ibf_offset_t pos = ibf_dump_pos(dump);
12913 if (pos % align) {
12914 static const char padding[sizeof(VALUE)];
12915 size_t size = align - ((size_t)pos % align);
12916#if SIZEOF_LONG > SIZEOF_INT
12917 if (pos + size >= UINT_MAX) {
12918 rb_raise(rb_eRuntimeError, "dump size exceeds");
12919 }
12920#endif
12921 for (; size > sizeof(padding); size -= sizeof(padding)) {
12922 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12923 }
12924 rb_str_cat(dump->current_buffer->str, padding, size);
12925 }
12926}
12927
12928static ibf_offset_t
12929ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12930{
12931 ibf_offset_t pos = ibf_dump_pos(dump);
12932#if SIZEOF_LONG > SIZEOF_INT
12933 /* ensure the resulting dump does not exceed UINT_MAX */
12934 if (size >= UINT_MAX || pos + size >= UINT_MAX) {
12935 rb_raise(rb_eRuntimeError, "dump size exceeds");
12936 }
12937#endif
12938 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12939 return pos;
12940}
12941
12942static ibf_offset_t
12943ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12944{
12945 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12946}
12947
12948static void
12949ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12950{
12951 VALUE str = dump->current_buffer->str;
12952 char *ptr = RSTRING_PTR(str);
12953 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12954 rb_bug("ibf_dump_overwrite: overflow");
12955 memcpy(ptr + offset, buff, size);
12956}
12957
12958static const void *
12959ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12960{
12961 ibf_offset_t beg = *offset;
12962 *offset += size;
12963 return load->current_buffer->buff + beg;
12964}
12965
12966static void *
12967ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12968{
12969 void *buff = ruby_xmalloc2(x, y);
12970 size_t size = x * y;
12971 memcpy(buff, load->current_buffer->buff + offset, size);
12972 return buff;
12973}
12974
12975#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12976
12977#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12978#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12979#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12980#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12981#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12982
12983static int
12984ibf_table_lookup(struct st_table *table, st_data_t key)
12985{
12986 st_data_t val;
12987
12988 if (st_lookup(table, key, &val)) {
12989 return (int)val;
12990 }
12991 else {
12992 return -1;
12993 }
12994}
12995
12996static int
12997ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12998{
12999 int index = ibf_table_lookup(table, key);
13000
13001 if (index < 0) { /* not found */
13002 index = (int)table->num_entries;
13003 st_insert(table, key, (st_data_t)index);
13004 }
13005
13006 return index;
13007}
13008
13009/* dump/load generic */
13010
13011static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
13012
13013static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
13014static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
13015
13016static st_table *
13017ibf_dump_object_table_new(void)
13018{
13019 st_table *obj_table = st_init_numtable(); /* need free */
13020 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
13021
13022 return obj_table;
13023}
13024
13025static VALUE
13026ibf_dump_object(struct ibf_dump *dump, VALUE obj)
13027{
13028 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
13029}
13030
13031static VALUE
13032ibf_dump_id(struct ibf_dump *dump, ID id)
13033{
13034 if (id == 0 || rb_id2name(id) == NULL) {
13035 return 0;
13036 }
13037 return ibf_dump_object(dump, rb_id2sym(id));
13038}
13039
13040static ID
13041ibf_load_id(const struct ibf_load *load, const ID id_index)
13042{
13043 if (id_index == 0) {
13044 return 0;
13045 }
13046 VALUE sym = ibf_load_object(load, id_index);
13047 if (rb_integer_type_p(sym)) {
13048 /* Load hidden local variables as indexes */
13049 return NUM2ULONG(sym);
13050 }
13051 return rb_sym2id(sym);
13052}
13053
13054/* dump/load: code */
13055
13056static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
13057
13058static int
13059ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
13060{
13061 if (iseq == NULL) {
13062 return -1;
13063 }
13064 else {
13065 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
13066 }
13067}
13068
13069static unsigned char
13070ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
13071{
13072 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
13073 return (unsigned char)load->current_buffer->buff[(*offset)++];
13074}
13075
13076/*
13077 * Small uint serialization
13078 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
13079 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
13080 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
13081 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
13082 * ...
13083 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
13084 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
13085 */
13086static void
13087ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
13088{
13089 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
13090 ibf_dump_write(dump, &x, sizeof(VALUE));
13091 return;
13092 }
13093
13094 enum { max_byte_length = sizeof(VALUE) + 1 };
13095
13096 unsigned char bytes[max_byte_length];
13097 ibf_offset_t n;
13098
13099 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
13100 bytes[max_byte_length - 1 - n] = (unsigned char)x;
13101 }
13102
13103 x <<= 1;
13104 x |= 1;
13105 x <<= n;
13106 bytes[max_byte_length - 1 - n] = (unsigned char)x;
13107 n++;
13108
13109 ibf_dump_write(dump, bytes + max_byte_length - n, n);
13110}
13111
13112static VALUE
13113ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
13114{
13115 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
13116 union { char s[sizeof(VALUE)]; VALUE v; } x;
13117
13118 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
13119 *offset += sizeof(VALUE);
13120
13121 return x.v;
13122 }
13123
13124 enum { max_byte_length = sizeof(VALUE) + 1 };
13125
13126 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
13127 const unsigned char c = buffer[*offset];
13128
13129 ibf_offset_t n =
13130 c & 1 ? 1 :
13131 c == 0 ? 9 : ntz_int32(c) + 1;
13132 VALUE x = (VALUE)c >> n;
13133
13134 if (*offset + n > load->current_buffer->size) {
13135 rb_raise(rb_eRuntimeError, "invalid byte sequence");
13136 }
13137
13138 ibf_offset_t i;
13139 for (i = 1; i < n; i++) {
13140 x <<= 8;
13141 x |= (VALUE)buffer[*offset + i];
13142 }
13143
13144 *offset += n;
13145 return x;
13146}
13147
13148static void
13149ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
13150{
13151 // short: index
13152 // short: name.length
13153 // bytes: name
13154 // // omit argc (only verify with name)
13155 ibf_dump_write_small_value(dump, (VALUE)bf->index);
13156
13157 size_t len = strlen(bf->name);
13158 ibf_dump_write_small_value(dump, (VALUE)len);
13159 ibf_dump_write(dump, bf->name, len);
13160}
13161
13162static const struct rb_builtin_function *
13163ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
13164{
13165 int i = (int)ibf_load_small_value(load, offset);
13166 int len = (int)ibf_load_small_value(load, offset);
13167 const char *name = (char *)ibf_load_ptr(load, offset, len);
13168
13169 if (0) {
13170 fprintf(stderr, "%.*s!!\n", len, name);
13171 }
13172
13173 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
13174 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
13175 if (strncmp(table[i].name, name, len) != 0) {
13176 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %.*s but %s)",
13177 i, len, name, table[i].name);
13178 }
13179 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
13180
13181 return &table[i];
13182}
13183
13184static ibf_offset_t
13185ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
13186{
13187 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13188 const int iseq_size = body->iseq_size;
13189 int code_index;
13190 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
13191
13192 ibf_offset_t offset = ibf_dump_pos(dump);
13193
13194 for (code_index=0; code_index<iseq_size;) {
13195 const VALUE insn = orig_code[code_index++];
13196 const char *types = insn_op_types(insn);
13197 int op_index;
13198
13199 /* opcode */
13200 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
13201 ibf_dump_write_small_value(dump, insn);
13202
13203 /* operands */
13204 for (op_index=0; types[op_index]; op_index++, code_index++) {
13205 VALUE op = orig_code[code_index];
13206 VALUE wv;
13207
13208 switch (types[op_index]) {
13209 case TS_CDHASH:
13210 case TS_VALUE:
13211 wv = ibf_dump_object(dump, op);
13212 break;
13213 case TS_ISEQ:
13214 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
13215 break;
13216 case TS_IC:
13217 {
13218 IC ic = (IC)op;
13219 VALUE arr = idlist_to_array(ic->segments);
13220 wv = ibf_dump_object(dump, arr);
13221 }
13222 break;
13223 case TS_ISE:
13224 case TS_IVC:
13225 case TS_ICVARC:
13226 {
13228 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
13229 }
13230 break;
13231 case TS_CALLDATA:
13232 {
13233 goto skip_wv;
13234 }
13235 case TS_ID:
13236 wv = ibf_dump_id(dump, (ID)op);
13237 break;
13238 case TS_FUNCPTR:
13239 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13240 goto skip_wv;
13241 case TS_BUILTIN:
13242 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
13243 goto skip_wv;
13244 default:
13245 wv = op;
13246 break;
13247 }
13248 ibf_dump_write_small_value(dump, wv);
13249 skip_wv:;
13250 }
13251 RUBY_ASSERT(insn_len(insn) == op_index+1);
13252 }
13253
13254 return offset;
13255}
13256
13257static VALUE *
13258ibf_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)
13259{
13260 VALUE iseqv = (VALUE)iseq;
13261 unsigned int code_index;
13262 ibf_offset_t reading_pos = bytecode_offset;
13263 VALUE *code = ZALLOC_N(VALUE, iseq_size);
13264
13265 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
13266 struct rb_call_data *cd_entries = load_body->call_data;
13267 int ic_index = 0;
13268
13269 load_body->iseq_encoded = code;
13270 load_body->iseq_size = iseq_size;
13271
13272 iseq_bits_t * mark_offset_bits;
13273 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
13274 load_body->mark_bits.single = 0;
13275 mark_offset_bits = &load_body->mark_bits.single;
13276 }
13277 else {
13278 load_body->mark_bits.list = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
13279 mark_offset_bits = load_body->mark_bits.list;
13280 }
13281 bool needs_bitmap = false;
13282
13283 for (code_index=0; code_index<iseq_size;) {
13284 /* opcode */
13285 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
13286 const char *types = insn_op_types(insn);
13287 int op_index;
13288
13289 code_index++;
13290
13291 /* operands */
13292 for (op_index=0; types[op_index]; op_index++, code_index++) {
13293 const char operand_type = types[op_index];
13294 switch (operand_type) {
13295 case TS_VALUE:
13296 {
13297 VALUE op = ibf_load_small_value(load, &reading_pos);
13298 VALUE v = ibf_load_object(load, op);
13299 code[code_index] = v;
13300 if (!SPECIAL_CONST_P(v)) {
13301 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13302 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13303 needs_bitmap = true;
13304 }
13305 break;
13306 }
13307 case TS_CDHASH:
13308 {
13309 VALUE op = ibf_load_small_value(load, &reading_pos);
13310 VALUE v = ibf_load_object(load, op);
13311
13312 // Overwrite the existing hash in the object list. This
13313 // is to keep the object alive during load time.
13314 // [Bug #17984] [ruby-core:104259]
13315 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
13316
13317 code[code_index] = v;
13318 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13319 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13320 needs_bitmap = true;
13321 break;
13322 }
13323 case TS_ISEQ:
13324 {
13325 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
13326 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
13327 code[code_index] = v;
13328 if (!SPECIAL_CONST_P(v)) {
13329 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13330 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13331 needs_bitmap = true;
13332 }
13333 break;
13334 }
13335 case TS_IC:
13336 {
13337 VALUE op = ibf_load_small_value(load, &reading_pos);
13338 VALUE arr = ibf_load_object(load, op);
13339
13340 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
13341 ic->segments = array_to_idlist(arr);
13342
13343 code[code_index] = (VALUE)ic;
13344 }
13345 break;
13346 case TS_ISE:
13347 case TS_ICVARC:
13348 case TS_IVC:
13349 {
13350 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
13351
13352 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
13353 code[code_index] = (VALUE)ic;
13354
13355 if (operand_type == TS_IVC) {
13356 IVC cache = (IVC)ic;
13357
13358 if (insn == BIN(setinstancevariable)) {
13359 ID iv_name = (ID)code[code_index - 1];
13360 cache->iv_set_name = iv_name;
13361 cache->value = IVAR_CACHE_INIT;
13362 }
13363 else {
13364 cache->iv_set_name = 0;
13365 cache->value = rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET);
13366 }
13367 }
13368
13369 }
13370 break;
13371 case TS_CALLDATA:
13372 {
13373 code[code_index] = (VALUE)cd_entries++;
13374 }
13375 break;
13376 case TS_ID:
13377 {
13378 VALUE op = ibf_load_small_value(load, &reading_pos);
13379 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
13380 }
13381 break;
13382 case TS_FUNCPTR:
13383 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13384 break;
13385 case TS_BUILTIN:
13386 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
13387 break;
13388 default:
13389 code[code_index] = ibf_load_small_value(load, &reading_pos);
13390 continue;
13391 }
13392 }
13393 if (insn_len(insn) != op_index+1) {
13394 rb_raise(rb_eRuntimeError, "operand size mismatch");
13395 }
13396 }
13397
13398 if (!needs_bitmap) {
13399 SIZED_FREE_N(load_body->mark_bits.list, ISEQ_MBITS_BUFLEN(iseq_size));
13400 load_body->mark_bits.list = NULL;
13401 }
13402
13403 RUBY_ASSERT(code_index == iseq_size);
13404 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
13405 return code;
13406}
13407
13408static ibf_offset_t
13409ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13410{
13411 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
13412
13413 if (opt_num > 0) {
13414 IBF_W_ALIGN(VALUE);
13415 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
13416 }
13417 else {
13418 return ibf_dump_pos(dump);
13419 }
13420}
13421
13422static VALUE *
13423ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
13424{
13425 if (opt_num > 0) {
13426 VALUE *table = ALLOC_N(VALUE, opt_num+1);
13427 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
13428 return table;
13429 }
13430 else {
13431 return NULL;
13432 }
13433}
13434
13435static ibf_offset_t
13436ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
13437{
13438 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
13439
13440 if (kw) {
13441 struct rb_iseq_param_keyword dump_kw = *kw;
13442 int dv_num = kw->num - kw->required_num;
13443 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
13444 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
13445 int i;
13446
13447 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
13448 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
13449
13450 dump_kw.table = IBF_W(ids, ID, kw->num);
13451 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
13452 IBF_W_ALIGN(struct rb_iseq_param_keyword);
13453 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
13454 }
13455 else {
13456 return 0;
13457 }
13458}
13459
13460static const struct rb_iseq_param_keyword *
13461ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13462{
13463 if (param_keyword_offset) {
13464 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
13465 int dv_num = kw->num - kw->required_num;
13466 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
13467
13468 int i;
13469 for (i=0; i<dv_num; i++) {
13470 dvs[i] = ibf_load_object(load, dvs[i]);
13471 }
13472
13473 // Will be set once the local table is loaded.
13474 kw->table = NULL;
13475
13476 kw->default_values = dvs;
13477 return kw;
13478 }
13479 else {
13480 return NULL;
13481 }
13482}
13483
13484static ibf_offset_t
13485ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13486{
13487 ibf_offset_t offset = ibf_dump_pos(dump);
13488 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13489
13490 unsigned int i;
13491 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13492 ibf_dump_write_small_value(dump, entries[i].line_no);
13493#ifdef USE_ISEQ_NODE_ID
13494 ibf_dump_write_small_value(dump, entries[i].node_id);
13495#endif
13496 ibf_dump_write_small_value(dump, entries[i].events);
13497 }
13498
13499 return offset;
13500}
13501
13502static struct iseq_insn_info_entry *
13503ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13504{
13505 ibf_offset_t reading_pos = body_offset;
13506 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13507
13508 unsigned int i;
13509 for (i = 0; i < size; i++) {
13510 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13511#ifdef USE_ISEQ_NODE_ID
13512 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13513#endif
13514 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13515 }
13516
13517 return entries;
13518}
13519
13520static ibf_offset_t
13521ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13522{
13523 ibf_offset_t offset = ibf_dump_pos(dump);
13524
13525 unsigned int last = 0;
13526 unsigned int i;
13527 for (i = 0; i < size; i++) {
13528 ibf_dump_write_small_value(dump, positions[i] - last);
13529 last = positions[i];
13530 }
13531
13532 return offset;
13533}
13534
13535static unsigned int *
13536ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13537{
13538 ibf_offset_t reading_pos = positions_offset;
13539 unsigned int *positions = ALLOC_N(unsigned int, size);
13540
13541 unsigned int last = 0;
13542 unsigned int i;
13543 for (i = 0; i < size; i++) {
13544 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13545 last = positions[i];
13546 }
13547
13548 return positions;
13549}
13550
13551static ibf_offset_t
13552ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13553{
13554 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13555 const int size = body->local_table_size;
13556 ID *table = ALLOCA_N(ID, size);
13557 int i;
13558
13559 for (i=0; i<size; i++) {
13560 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13561 if (v == 0) {
13562 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13563 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13564 }
13565 table[i] = v;
13566 }
13567
13568 IBF_W_ALIGN(ID);
13569 return ibf_dump_write(dump, table, sizeof(ID) * size);
13570}
13571
13572static const ID *
13573ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13574{
13575 if (size > 0) {
13576 ID *table = IBF_R(local_table_offset, ID, size);
13577 int i;
13578
13579 for (i=0; i<size; i++) {
13580 table[i] = ibf_load_id(load, table[i]);
13581 }
13582
13583 if (size == 1 && table[0] == idERROR_INFO) {
13584 ruby_xfree_sized(table, sizeof(ID) * size);
13585 return rb_iseq_shared_exc_local_tbl;
13586 }
13587 else {
13588 return table;
13589 }
13590 }
13591 else {
13592 return NULL;
13593 }
13594}
13595
13596static ibf_offset_t
13597ibf_dump_lvar_states(struct ibf_dump *dump, const rb_iseq_t *iseq)
13598{
13599 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13600 const int size = ISEQ_LVAR_STATES_BUFLEN(body->local_table_size);
13601 IBF_W_ALIGN(uint8_t);
13602 if (iseq_has_lvar_states_p(body)) {
13603 return ibf_dump_write(dump, iseq_lvar_states(body), sizeof(uint8_t) * size);
13604 }
13605 else {
13606 return ibf_dump_write(dump, NULL, 0);
13607 }
13608}
13609
13610static void
13611ibf_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)
13612{
13613 if (local_table == rb_iseq_shared_exc_local_tbl ||
13614 size <= 0) {
13615 load_body->lvar_states.list = NULL;
13616 }
13617 else if (ISEQ_LVAR_STATES_EMBED_P((unsigned int)size)) {
13618 ibf_offset_t pos = lvar_states_offset;
13619 const int len = sizeof(uint8_t) * ISEQ_LVAR_STATES_BUFLEN(size);
13620 memcpy(load_body->lvar_states.single, ibf_load_ptr(load, &pos, len), len);
13621 }
13622 else {
13623 load_body->lvar_states.list = IBF_R(lvar_states_offset, uint8_t, ISEQ_LVAR_STATES_BUFLEN(size));
13624 }
13625}
13626
13627static ibf_offset_t
13628ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13629{
13630 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13631
13632 if (table) {
13633 int *iseq_indices = ALLOCA_N(int, table->size);
13634 unsigned int i;
13635
13636 for (i=0; i<table->size; i++) {
13637 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13638 }
13639
13640 const ibf_offset_t offset = ibf_dump_pos(dump);
13641
13642 for (i=0; i<table->size; i++) {
13643 ibf_dump_write_small_value(dump, iseq_indices[i]);
13644 ibf_dump_write_small_value(dump, table->entries[i].type);
13645 ibf_dump_write_small_value(dump, table->entries[i].start);
13646 ibf_dump_write_small_value(dump, table->entries[i].end);
13647 ibf_dump_write_small_value(dump, table->entries[i].cont);
13648 ibf_dump_write_small_value(dump, table->entries[i].sp);
13649 }
13650 return offset;
13651 }
13652 else {
13653 return ibf_dump_pos(dump);
13654 }
13655}
13656
13657static void
13658ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size, const rb_iseq_t *parent_iseq)
13659{
13660 if (size) {
13661 struct iseq_catch_table *table = ruby_xcalloc(1, iseq_catch_table_bytes(size));
13662 table->size = size;
13663 ISEQ_BODY(parent_iseq)->catch_table = table;
13664
13665 ibf_offset_t reading_pos = catch_table_offset;
13666
13667 unsigned int i;
13668 for (i=0; i<table->size; i++) {
13669 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13670 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13671 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13672 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13673 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13674 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13675
13676 rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13677 RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
13678 }
13679 }
13680 else {
13681 ISEQ_BODY(parent_iseq)->catch_table = NULL;
13682 }
13683}
13684
13685static ibf_offset_t
13686ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13687{
13688 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13689 const unsigned int ci_size = body->ci_size;
13690 const struct rb_call_data *cds = body->call_data;
13691
13692 ibf_offset_t offset = ibf_dump_pos(dump);
13693
13694 unsigned int i;
13695
13696 for (i = 0; i < ci_size; i++) {
13697 const struct rb_callinfo *ci = cds[i].ci;
13698 if (ci != NULL) {
13699 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13700 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13701 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13702
13703 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13704 if (kwarg) {
13705 int len = kwarg->keyword_len;
13706 ibf_dump_write_small_value(dump, len);
13707 for (int j=0; j<len; j++) {
13708 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13709 ibf_dump_write_small_value(dump, keyword);
13710 }
13711 }
13712 else {
13713 ibf_dump_write_small_value(dump, 0);
13714 }
13715 }
13716 else {
13717 // TODO: truncate NULL ci from call_data.
13718 ibf_dump_write_small_value(dump, (VALUE)-1);
13719 }
13720 }
13721
13722 return offset;
13723}
13724
13726 ID id;
13727 VALUE name;
13728 VALUE val;
13729};
13730
13732 size_t num;
13733 struct outer_variable_pair pairs[1];
13734};
13735
13736static enum rb_id_table_iterator_result
13737store_outer_variable(ID id, VALUE val, void *dump)
13738{
13739 struct outer_variable_list *ovlist = dump;
13740 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13741 pair->id = id;
13742 pair->name = rb_id2str(id);
13743 pair->val = val;
13744 return ID_TABLE_CONTINUE;
13745}
13746
13747static int
13748outer_variable_cmp(const void *a, const void *b, void *arg)
13749{
13750 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13751 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13752
13753 if (!ap->name) {
13754 return -1;
13755 }
13756 else if (!bp->name) {
13757 return 1;
13758 }
13759
13760 return rb_str_cmp(ap->name, bp->name);
13761}
13762
13763static ibf_offset_t
13764ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13765{
13766 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13767
13768 ibf_offset_t offset = ibf_dump_pos(dump);
13769
13770 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13771 ibf_dump_write_small_value(dump, (VALUE)size);
13772 if (size > 0) {
13773 VALUE buff;
13774 size_t buffsize =
13775 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13776 offsetof(struct outer_variable_list, pairs),
13777 rb_eArgError);
13778 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13779 ovlist->num = 0;
13780 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13781 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13782 for (size_t i = 0; i < size; ++i) {
13783 ID id = ovlist->pairs[i].id;
13784 ID val = ovlist->pairs[i].val;
13785 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13786 ibf_dump_write_small_value(dump, val);
13787 }
13788 ALLOCV_END(buff);
13789 }
13790
13791 return offset;
13792}
13793
13794/* note that we dump out rb_call_info but load back rb_call_data */
13795static void
13796ibf_load_ci_entries(const struct ibf_load *load,
13797 ibf_offset_t ci_entries_offset,
13798 unsigned int ci_size,
13799 struct rb_call_data **cd_ptr)
13800{
13801 if (!ci_size) {
13802 *cd_ptr = NULL;
13803 return;
13804 }
13805
13806 ibf_offset_t reading_pos = ci_entries_offset;
13807
13808 unsigned int i;
13809
13810 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13811 *cd_ptr = cds;
13812
13813 for (i = 0; i < ci_size; i++) {
13814 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13815 if (mid_index != (VALUE)-1) {
13816 ID mid = ibf_load_id(load, mid_index);
13817 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13818 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13819
13820 struct rb_callinfo_kwarg *kwarg = NULL;
13821 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13822 if (kwlen > 0) {
13823 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13824 kwarg->references = 0;
13825 kwarg->keyword_len = kwlen;
13826 for (int j=0; j<kwlen; j++) {
13827 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13828 kwarg->keywords[j] = ibf_load_object(load, keyword);
13829 }
13830 }
13831
13832 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13833 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13834 cds[i].cc = vm_cc_empty();
13835 }
13836 else {
13837 // NULL ci
13838 cds[i].ci = NULL;
13839 cds[i].cc = NULL;
13840 }
13841 }
13842}
13843
13844static struct rb_id_table *
13845ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13846{
13847 ibf_offset_t reading_pos = outer_variables_offset;
13848
13849 struct rb_id_table *tbl = NULL;
13850
13851 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13852
13853 if (table_size > 0) {
13854 tbl = rb_id_table_create(table_size);
13855 }
13856
13857 for (size_t i = 0; i < table_size; i++) {
13858 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13859 VALUE value = ibf_load_small_value(load, &reading_pos);
13860 if (!key) key = rb_make_temporary_id(i);
13861 rb_id_table_insert(tbl, key, value);
13862 }
13863
13864 return tbl;
13865}
13866
13867static ibf_offset_t
13868ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13869{
13870 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13871
13872 unsigned int *positions;
13873
13874 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13875
13876 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13877 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13878
13879#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13880 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13881
13882 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13883 struct ibf_dump_buffer buffer;
13884 buffer.str = rb_str_new(0, 0);
13885 buffer.obj_table = ibf_dump_object_table_new();
13886 dump->current_buffer = &buffer;
13887#endif
13888
13889 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13890 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13891 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13892 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13893 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13894
13895 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13896 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13897 SIZED_FREE_N(positions, ISEQ_BODY(iseq)->insns_info.size);
13898
13899 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13900 const ibf_offset_t lvar_states_offset = ibf_dump_lvar_states(dump, iseq);
13901 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13902 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13903 /* a NULL parent (persisted root) and references outside a Proc#refined subtree dump come out absent (-1) */
13904 const int parent_iseq_index = ibf_table_lookup(dump->iseq_table, (st_data_t)ISEQ_BODY(iseq)->parent_iseq);
13905 const int local_iseq_index = ibf_table_lookup(dump->iseq_table, (st_data_t)ISEQ_BODY(iseq)->local_iseq);
13906 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13907 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13908 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13909
13910#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13911 ibf_offset_t local_obj_list_offset;
13912 unsigned int local_obj_list_size;
13913
13914 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13915#endif
13916
13917 ibf_offset_t body_offset = ibf_dump_pos(dump);
13918
13919 /* dump the constant body */
13920 unsigned int param_flags =
13921 (body->param.flags.has_lead << 0) |
13922 (body->param.flags.has_opt << 1) |
13923 (body->param.flags.has_rest << 2) |
13924 (body->param.flags.has_post << 3) |
13925 (body->param.flags.has_kw << 4) |
13926 (body->param.flags.has_kwrest << 5) |
13927 (body->param.flags.has_block << 6) |
13928 (body->param.flags.ambiguous_param0 << 7) |
13929 (body->param.flags.accepts_no_kwarg << 8) |
13930 (body->param.flags.ruby2_keywords << 9) |
13931 (body->param.flags.anon_rest << 10) |
13932 (body->param.flags.anon_kwrest << 11) |
13933 (body->param.flags.use_block << 12) |
13934 (body->param.flags.forwardable << 13) |
13935 (body->param.flags.accepts_no_block << 14);
13936
13937#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13938# define IBF_BODY_OFFSET(x) (x)
13939#else
13940# define IBF_BODY_OFFSET(x) (body_offset - (x))
13941#endif
13942
13943 ibf_dump_write_small_value(dump, body->type);
13944 ibf_dump_write_small_value(dump, body->iseq_size);
13945 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13946 ibf_dump_write_small_value(dump, bytecode_size);
13947 ibf_dump_write_small_value(dump, param_flags);
13948 ibf_dump_write_small_value(dump, body->param.size);
13949 ibf_dump_write_small_value(dump, body->param.lead_num);
13950 ibf_dump_write_small_value(dump, body->param.opt_num);
13951 ibf_dump_write_small_value(dump, body->param.rest_start);
13952 ibf_dump_write_small_value(dump, body->param.post_start);
13953 ibf_dump_write_small_value(dump, body->param.post_num);
13954 ibf_dump_write_small_value(dump, body->param.block_start);
13955 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13956 ibf_dump_write_small_value(dump, param_keyword_offset);
13957 ibf_dump_write_small_value(dump, location_pathobj_index);
13958 ibf_dump_write_small_value(dump, location_label_index);
13959 ibf_dump_write_small_value(dump, body->location.first_lineno);
13960 ibf_dump_write_small_value(dump, body->location.node_id);
13961 /* Dump the source hash (0 if unavailable) in two 32-bit halves, because
13962 * VALUE may be 32 bits wide. */
13963 ibf_dump_write_small_value(dump, (VALUE)(uint32_t)(body->source_hash >> 32));
13964 ibf_dump_write_small_value(dump, (VALUE)(uint32_t)body->source_hash);
13965 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13966 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13967 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13968 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13969 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13970 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13971 ibf_dump_write_small_value(dump, body->insns_info.size);
13972 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13973 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(lvar_states_offset));
13974 ibf_dump_write_small_value(dump, catch_table_size);
13975 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13976 ibf_dump_write_small_value(dump, parent_iseq_index);
13977 ibf_dump_write_small_value(dump, local_iseq_index);
13978 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13979 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13980 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13981 ibf_dump_write_small_value(dump, ISEQ_FLIP_CNT(iseq));
13982 ibf_dump_write_small_value(dump, body->local_table_size);
13983 ibf_dump_write_small_value(dump, body->ivc_size);
13984 ibf_dump_write_small_value(dump, body->icvarc_size);
13985 ibf_dump_write_small_value(dump, body->ise_size);
13986 ibf_dump_write_small_value(dump, body->ic_size);
13987 ibf_dump_write_small_value(dump, body->ci_size);
13988 ibf_dump_write_small_value(dump, body->stack_max);
13989 ibf_dump_write_small_value(dump, body->builtin_attrs);
13990 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13991
13992#undef IBF_BODY_OFFSET
13993
13994#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13995 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13996
13997 dump->current_buffer = saved_buffer;
13998 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13999
14000 ibf_offset_t offset = ibf_dump_pos(dump);
14001 ibf_dump_write_small_value(dump, iseq_start);
14002 ibf_dump_write_small_value(dump, iseq_length_bytes);
14003 ibf_dump_write_small_value(dump, body_offset);
14004
14005 ibf_dump_write_small_value(dump, local_obj_list_offset);
14006 ibf_dump_write_small_value(dump, local_obj_list_size);
14007
14008 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
14009
14010 return offset;
14011#else
14012 return body_offset;
14013#endif
14014}
14015
14016static VALUE
14017ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
14018{
14019 VALUE str = ibf_load_object(load, str_index);
14020 if (str != Qnil) {
14021 str = rb_fstring(str);
14022 }
14023 return str;
14024}
14025
14026static void
14027ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
14028{
14029 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
14030
14031 ibf_offset_t reading_pos = offset;
14032
14033#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14034 struct ibf_load_buffer *saved_buffer = load->current_buffer;
14035 load->current_buffer = &load->global_buffer;
14036
14037 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14038 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14039 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14040
14041 struct ibf_load_buffer buffer;
14042 buffer.buff = load->global_buffer.buff + iseq_start;
14043 buffer.size = iseq_length_bytes;
14044 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14045 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14046 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
14047
14048 load->current_buffer = &buffer;
14049 reading_pos = body_offset;
14050#endif
14051
14052#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14053# define IBF_BODY_OFFSET(x) (x)
14054#else
14055# define IBF_BODY_OFFSET(x) (offset - (x))
14056#endif
14057
14058 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
14059 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14060 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14061 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14062 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
14063 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14064 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
14065 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
14066 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
14067 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
14068 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
14069 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
14070 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14071 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14072 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
14073 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
14074 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
14075 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
14076 const uint64_t source_hash_hi = (uint64_t)ibf_load_small_value(load, &reading_pos);
14077 const uint64_t source_hash_lo = (uint64_t)ibf_load_small_value(load, &reading_pos);
14078 const uint64_t source_hash = (source_hash_hi << 32) | (uint32_t)source_hash_lo;
14079 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
14080 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
14081 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
14082 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
14083 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14084 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14085 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14086 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14087 const ibf_offset_t lvar_states_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14088 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14089 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14090 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
14091 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
14092 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
14093 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14094 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14095 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
14096 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14097
14098 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14099 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14100 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14101 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14102
14103 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14104 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
14105 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
14106 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
14107
14108 // setup fname and dummy frame
14109 VALUE path = ibf_load_object(load, location_pathobj_index);
14110 {
14111 VALUE realpath = Qnil;
14112
14113 if (RB_TYPE_P(path, T_STRING)) {
14114 realpath = path = rb_fstring(path);
14115 }
14116 else if (RB_TYPE_P(path, T_ARRAY)) {
14117 VALUE pathobj = path;
14118 if (RARRAY_LEN(pathobj) != 2) {
14119 rb_raise(rb_eRuntimeError, "path object size mismatch");
14120 }
14121 path = rb_fstring(RARRAY_AREF(pathobj, 0));
14122 realpath = RARRAY_AREF(pathobj, 1);
14123 if (!NIL_P(realpath)) {
14124 if (!RB_TYPE_P(realpath, T_STRING)) {
14125 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
14126 "(%x), path=%+"PRIsVALUE,
14127 realpath, TYPE(realpath), path);
14128 }
14129 realpath = rb_fstring(realpath);
14130 }
14131 }
14132 else {
14133 rb_raise(rb_eRuntimeError, "unexpected path object");
14134 }
14135 rb_iseq_pathobj_set(iseq, path, realpath);
14136 }
14137
14138 // push dummy frame
14139 rb_execution_context_t *ec = GET_EC();
14140 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
14141
14142#undef IBF_BODY_OFFSET
14143
14144 load_body->type = type;
14145 load_body->stack_max = stack_max;
14146 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
14147 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
14148 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
14149 load_body->param.flags.has_post = (param_flags >> 3) & 1;
14150 load_body->param.flags.has_kw = FALSE;
14151 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
14152 load_body->param.flags.has_block = (param_flags >> 6) & 1;
14153 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
14154 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
14155 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
14156 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
14157 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
14158 load_body->param.flags.use_block = (param_flags >> 12) & 1;
14159 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
14160 load_body->param.flags.accepts_no_block = (param_flags >> 14) & 1;
14161 load_body->param.size = param_size;
14162 load_body->param.lead_num = param_lead_num;
14163 load_body->param.opt_num = param_opt_num;
14164 load_body->param.rest_start = param_rest_start;
14165 load_body->param.post_start = param_post_start;
14166 load_body->param.post_num = param_post_num;
14167 load_body->param.block_start = param_block_start;
14168 load_body->local_table_size = local_table_size;
14169 load_body->ci_size = ci_size;
14170 load_body->insns_info.size = insns_info_size;
14171
14172 // variable is NULL from ZALLOC; only allocate if flip_count is non-zero.
14173 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
14174 if (variable_flip_count) {
14175 struct rb_iseq_variable *v = rb_iseq_variable_ensure(iseq);
14176 v->flip_count = variable_flip_count;
14177 }
14178
14179 load_body->location.first_lineno = location_first_lineno;
14180 load_body->location.node_id = location_node_id;
14181 load_body->source_hash = source_hash;
14182 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
14183 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
14184 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
14185 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
14186 load_body->builtin_attrs = builtin_attrs;
14187 load_body->prism = prism;
14188
14189 load_body->ivc_size = ivc_size;
14190 load_body->icvarc_size = icvarc_size;
14191 load_body->ise_size = ise_size;
14192 load_body->ic_size = ic_size;
14193
14194 if (ISEQ_IS_SIZE(load_body)) {
14195 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
14196 }
14197 else {
14198 load_body->is_entries = NULL;
14199 }
14200 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
14201 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
14202 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
14203 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
14204 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
14205 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
14206 load_body->insns_info.positions_or_succ_index_table.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
14207 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
14208 ibf_load_lvar_states(load, load_body, lvar_states_offset, local_table_size, load_body->local_table);
14209 ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
14210
14211 const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
14212 const rb_iseq_t *local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
14213 const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
14214
14215 RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
14216 RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
14217 RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
14218
14219 // This must be done after the local table is loaded.
14220 if (load_body->param.keyword != NULL) {
14221 RUBY_ASSERT(load_body->local_table);
14222 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
14223 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
14224 }
14225
14226 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
14227#if VM_INSN_INFO_TABLE_IMPL == 2
14228 rb_iseq_insns_info_encode_positions(iseq);
14229#endif
14230
14231 rb_iseq_translate_threaded_code(iseq);
14232
14233#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14234 load->current_buffer = &load->global_buffer;
14235#endif
14236
14237 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
14238
14239#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14240 load->current_buffer = saved_buffer;
14241#endif
14242 verify_call_cache(iseq);
14243
14244 RB_GC_GUARD(dummy_frame);
14245 rb_vm_pop_frame_no_int(ec);
14246}
14247
14249{
14250 struct ibf_dump *dump;
14251 VALUE offset_list;
14252};
14253
14254static int
14255ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14256{
14257 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
14258 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
14259
14260 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
14261 rb_ary_push(args->offset_list, UINT2NUM(offset));
14262
14263 return ST_CONTINUE;
14264}
14265
14266static void
14267ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
14268{
14269 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
14270
14271 struct ibf_dump_iseq_list_arg args;
14272 args.dump = dump;
14273 args.offset_list = offset_list;
14274
14275 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
14276
14277 st_index_t i;
14278 st_index_t size = dump->iseq_table->num_entries;
14279 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
14280
14281 for (i = 0; i < size; i++) {
14282 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
14283 }
14284
14285 ibf_dump_align(dump, sizeof(ibf_offset_t));
14286 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
14287 header->iseq_list_size = (unsigned int)size;
14288}
14289
14290/*
14291 * Binary format
14292 * - ibf_object_header
14293 * - ibf_object_xxx (xxx is type)
14294 */
14295
14297 unsigned int type: 5;
14298 unsigned int special_const: 1;
14299 unsigned int frozen: 1;
14300 unsigned int internal: 1;
14301};
14302
14303enum ibf_object_class_index {
14304 IBF_OBJECT_CLASS_OBJECT,
14305 IBF_OBJECT_CLASS_ARRAY,
14306 IBF_OBJECT_CLASS_STANDARD_ERROR,
14307 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
14308 IBF_OBJECT_CLASS_TYPE_ERROR,
14309 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
14310};
14311
14313 long srcstr;
14314 char option;
14315};
14316
14318 long len;
14319 long keyval[FLEX_ARY_LEN];
14320};
14321
14323 long class_index;
14324 long len;
14325 long beg;
14326 long end;
14327 int excl;
14328};
14329
14331 ssize_t slen;
14332 BDIGIT digits[FLEX_ARY_LEN];
14333};
14334
14335enum ibf_object_data_type {
14336 IBF_OBJECT_DATA_ENCODING,
14337};
14338
14340 long a, b;
14341};
14342
14344 long str;
14345};
14346
14347#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
14348 ((((offset) - 1) / (align) + 1) * (align))
14349/* No cast, since it's UB to create an unaligned pointer.
14350 * Leave as void* for use with memcpy in those cases.
14351 * We align the offset, but the buffer pointer is only VALUE aligned,
14352 * so the returned pointer may be unaligned for `type` .*/
14353#define IBF_OBJBODY(type, offset) \
14354 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
14355
14356static const void *
14357ibf_load_check_offset(const struct ibf_load *load, size_t offset)
14358{
14359 if (offset >= load->current_buffer->size) {
14360 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
14361 }
14362 return load->current_buffer->buff + offset;
14363}
14364
14365NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
14366
14367static void
14368ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
14369{
14370 char buff[0x100];
14371 rb_raw_obj_info(buff, sizeof(buff), obj);
14372 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
14373}
14374
14375NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
14376
14377static VALUE
14378ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14379{
14380 rb_raise(rb_eArgError, "unsupported");
14382}
14383
14384static void
14385ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
14386{
14387 enum ibf_object_class_index cindex;
14388 if (obj == rb_cObject) {
14389 cindex = IBF_OBJECT_CLASS_OBJECT;
14390 }
14391 else if (obj == rb_cArray) {
14392 cindex = IBF_OBJECT_CLASS_ARRAY;
14393 }
14394 else if (obj == rb_eStandardError) {
14395 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
14396 }
14397 else if (obj == rb_eNoMatchingPatternError) {
14398 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
14399 }
14400 else if (obj == rb_eTypeError) {
14401 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
14402 }
14403 else if (obj == rb_eNoMatchingPatternKeyError) {
14404 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
14405 }
14406 else {
14407 rb_obj_info_dump(obj);
14408 rb_p(obj);
14409 rb_bug("unsupported class");
14410 }
14411 ibf_dump_write_small_value(dump, (VALUE)cindex);
14412}
14413
14414static VALUE
14415ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14416{
14417 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
14418
14419 switch (cindex) {
14420 case IBF_OBJECT_CLASS_OBJECT:
14421 return rb_cObject;
14422 case IBF_OBJECT_CLASS_ARRAY:
14423 return rb_cArray;
14424 case IBF_OBJECT_CLASS_STANDARD_ERROR:
14425 return rb_eStandardError;
14426 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
14428 case IBF_OBJECT_CLASS_TYPE_ERROR:
14429 return rb_eTypeError;
14430 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
14432 }
14433
14434 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
14435}
14436
14437
14438static void
14439ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
14440{
14441 double dbl = RFLOAT_VALUE(obj);
14442 (void)IBF_W(&dbl, double, 1);
14443}
14444
14445static VALUE
14446ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14447{
14448 double d;
14449 /* Avoid unaligned VFP load on ARMv7; IBF payload may be unaligned (C99 6.3.2.3 p7). */
14450 memcpy(&d, IBF_OBJBODY(double, offset), sizeof(d));
14451 VALUE f = DBL2NUM(d);
14452 if (!FLONUM_P(f)) RB_OBJ_SET_SHAREABLE(f);
14453 return f;
14454}
14455
14456static void
14457ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
14458{
14459 long encindex = (long)rb_enc_get_index(obj);
14460 long len = RSTRING_LEN(obj);
14461 const char *ptr = RSTRING_PTR(obj);
14462
14463 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14464 rb_encoding *enc = rb_enc_from_index((int)encindex);
14465 const char *enc_name = rb_enc_name(enc);
14466 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
14467 }
14468
14469 ibf_dump_write_small_value(dump, encindex);
14470 ibf_dump_write_small_value(dump, len);
14471 IBF_WP(ptr, char, len);
14472}
14473
14474static VALUE
14475ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14476{
14477 ibf_offset_t reading_pos = offset;
14478
14479 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14480 const long len = (long)ibf_load_small_value(load, &reading_pos);
14481 const char *ptr = load->current_buffer->buff + reading_pos;
14482
14483 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14484 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14485 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14486 }
14487
14488 VALUE str;
14489 if (header->frozen && !header->internal) {
14490 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
14491 }
14492 else {
14493 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
14494
14495 if (header->internal) rb_obj_hide(str);
14496 if (header->frozen) str = rb_fstring(str);
14497 }
14498 return str;
14499}
14500
14501static void
14502ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
14503{
14504 VALUE srcstr = RREGEXP_SRC(obj);
14505 struct ibf_object_regexp regexp;
14506 regexp.option = (char)rb_reg_options(obj);
14507 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
14508
14509 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
14510 ibf_dump_write_small_value(dump, regexp.srcstr);
14511}
14512
14513static VALUE
14514ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14515{
14516 struct ibf_object_regexp regexp;
14517 regexp.option = ibf_load_byte(load, &offset);
14518 regexp.srcstr = ibf_load_small_value(load, &offset);
14519
14520 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14521 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
14522
14523 if (header->internal) rb_obj_hide(reg);
14524 if (header->frozen) RB_OBJ_SET_SHAREABLE(rb_obj_freeze(reg));
14525
14526 return reg;
14527}
14528
14529static void
14530ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
14531{
14532 long i, len = RARRAY_LEN(obj);
14533 ibf_dump_write_small_value(dump, len);
14534 for (i=0; i<len; i++) {
14535 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
14536 ibf_dump_write_small_value(dump, index);
14537 }
14538}
14539
14540static VALUE
14541ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14542{
14543 ibf_offset_t reading_pos = offset;
14544
14545 const long len = (long)ibf_load_small_value(load, &reading_pos);
14546
14547 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
14548 int i;
14549
14550 for (i=0; i<len; i++) {
14551 const VALUE index = ibf_load_small_value(load, &reading_pos);
14552 rb_ary_push(ary, ibf_load_object(load, index));
14553 }
14554
14555 if (header->frozen) {
14556 rb_ary_freeze(ary);
14557 rb_ractor_make_shareable(ary); // TODO: check elements
14558 }
14559
14560 return ary;
14561}
14562
14563static int
14564ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14565{
14566 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14567
14568 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14569 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14570
14571 ibf_dump_write_small_value(dump, key_index);
14572 ibf_dump_write_small_value(dump, val_index);
14573 return ST_CONTINUE;
14574}
14575
14576static void
14577ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14578{
14579 long len = RHASH_SIZE(obj);
14580 ibf_dump_write_small_value(dump, (VALUE)len);
14581
14582 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14583}
14584
14585static VALUE
14586ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14587{
14588 long len = (long)ibf_load_small_value(load, &offset);
14589 VALUE obj = header->frozen ? rb_hash_alloc_fixed_size(rb_cHash, len) : rb_hash_new_capa(len);
14590 int i;
14591
14592 for (i = 0; i < len; i++) {
14593 VALUE key_index = ibf_load_small_value(load, &offset);
14594 VALUE val_index = ibf_load_small_value(load, &offset);
14595
14596 VALUE key = ibf_load_object(load, key_index);
14597 VALUE val = ibf_load_object(load, val_index);
14598 rb_hash_aset(obj, key, val);
14599 }
14600
14601 if (header->internal) rb_obj_hide(obj);
14602 if (header->frozen) {
14604 }
14605
14606 return obj;
14607}
14608
14609static int
14610ibf_dump_cdhash_i(st_data_t key, st_data_t val, st_data_t ptr)
14611{
14612 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14613
14614 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14615
14616 ibf_dump_write_small_value(dump, key_index);
14617 ibf_dump_write_small_value(dump, val);
14618 return ST_CONTINUE;
14619}
14620
14621static void
14622ibf_dump_object_imemo(struct ibf_dump *dump, VALUE obj)
14623{
14624 switch (imemo_type(obj)) {
14625 case imemo_cdhash: {
14626 st_table *tbl = rb_imemo_cdhash_tbl(obj);
14627
14628 long len = tbl->num_entries;
14629 ibf_dump_write_small_value(dump, (VALUE)len);
14630 if (len > 0) st_foreach(tbl, ibf_dump_cdhash_i, (VALUE)dump);
14631 break;
14632 }
14633 default:
14634 ibf_dump_object_unsupported(dump, obj);
14635 break;
14636 }
14637}
14638
14639static VALUE
14640ibf_load_object_imemo(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14641{
14642 long len = (long)ibf_load_small_value(load, &offset);
14643 VALUE obj = cdhash_new(len);
14644
14645 int i;
14646 for (i = 0; i < len; i++) {
14647 VALUE key_index = ibf_load_small_value(load, &offset);
14648 VALUE val = ibf_load_small_value(load, &offset);
14649
14650 VALUE key = ibf_load_object(load, key_index);
14651 cdhash_aset(obj, key, val);
14652 }
14653
14654 return obj;
14655}
14656
14657static void
14658ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14659{
14660 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14661 struct ibf_object_struct_range range;
14662 VALUE beg, end;
14663 IBF_ZERO(range);
14664 range.len = 3;
14665 range.class_index = 0;
14666
14667 rb_range_values(obj, &beg, &end, &range.excl);
14668 range.beg = (long)ibf_dump_object(dump, beg);
14669 range.end = (long)ibf_dump_object(dump, end);
14670
14671 IBF_W_ALIGN(struct ibf_object_struct_range);
14672 IBF_WV(range);
14673 }
14674 else {
14675 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14676 rb_class_name(CLASS_OF(obj)));
14677 }
14678}
14679
14680static VALUE
14681ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14682{
14683 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14684 VALUE beg = ibf_load_object(load, range->beg);
14685 VALUE end = ibf_load_object(load, range->end);
14686 VALUE obj = rb_range_new(beg, end, range->excl);
14687 if (header->internal) rb_obj_hide(obj);
14688 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14689 return obj;
14690}
14691
14692static void
14693ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14694{
14695 ssize_t len = BIGNUM_LEN(obj);
14696 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14697 BDIGIT *d = BIGNUM_DIGITS(obj);
14698
14699 (void)IBF_W(&slen, ssize_t, 1);
14700 IBF_WP(d, BDIGIT, len);
14701}
14702
14703static VALUE
14704ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14705{
14706 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14707 int sign = bignum->slen > 0;
14708 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14709 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14712 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14713 big_unpack_flags |
14714 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14715 if (header->internal) rb_obj_hide(obj);
14716 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14717 return obj;
14718}
14719
14720static void
14721ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14722{
14723 if (rb_data_is_encoding(obj)) {
14724 rb_encoding *enc = rb_to_encoding(obj);
14725 const char *name = rb_enc_name(enc);
14726 long len = strlen(name) + 1;
14727 long data[2];
14728 data[0] = IBF_OBJECT_DATA_ENCODING;
14729 data[1] = len;
14730 (void)IBF_W(data, long, 2);
14731 IBF_WP(name, char, len);
14732 }
14733 else {
14734 ibf_dump_object_unsupported(dump, obj);
14735 }
14736}
14737
14738static VALUE
14739ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14740{
14741 const long *body = IBF_OBJBODY(long, offset);
14742 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14743 /* const long len = body[1]; */
14744 const char *data = (const char *)&body[2];
14745
14746 switch (type) {
14747 case IBF_OBJECT_DATA_ENCODING:
14748 {
14749 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14750 return encobj;
14751 }
14752 }
14753
14754 return ibf_load_object_unsupported(load, header, offset);
14755}
14756
14757static void
14758ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14759{
14760 long data[2];
14761 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14762 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14763
14764 (void)IBF_W(data, long, 2);
14765}
14766
14767static VALUE
14768ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14769{
14770 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14771 VALUE a = ibf_load_object(load, nums->a);
14772 VALUE b = ibf_load_object(load, nums->b);
14773 VALUE obj = header->type == T_COMPLEX ?
14774 rb_complex_new(a, b) : rb_rational_new(a, b);
14775
14776 if (header->internal) rb_obj_hide(obj);
14777 if (header->frozen) rb_ractor_make_shareable(rb_obj_freeze(obj));
14778 return obj;
14779}
14780
14781static void
14782ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14783{
14784 ibf_dump_object_string(dump, rb_sym2str(obj));
14785}
14786
14787static VALUE
14788ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14789{
14790 ibf_offset_t reading_pos = offset;
14791
14792 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14793 const long len = (long)ibf_load_small_value(load, &reading_pos);
14794 const char *ptr = load->current_buffer->buff + reading_pos;
14795
14796 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14797 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14798 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14799 }
14800
14801 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14802 return ID2SYM(id);
14803}
14804
14805typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14806static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14807 ibf_dump_object_unsupported, /* T_NONE */
14808 ibf_dump_object_unsupported, /* T_OBJECT */
14809 ibf_dump_object_class, /* T_CLASS */
14810 ibf_dump_object_unsupported, /* T_MODULE */
14811 ibf_dump_object_float, /* T_FLOAT */
14812 ibf_dump_object_string, /* T_STRING */
14813 ibf_dump_object_regexp, /* T_REGEXP */
14814 ibf_dump_object_array, /* T_ARRAY */
14815 ibf_dump_object_hash, /* T_HASH */
14816 ibf_dump_object_struct, /* T_STRUCT */
14817 ibf_dump_object_bignum, /* T_BIGNUM */
14818 ibf_dump_object_unsupported, /* T_FILE */
14819 ibf_dump_object_data, /* T_DATA */
14820 ibf_dump_object_unsupported, /* T_MATCH */
14821 ibf_dump_object_complex_rational, /* T_COMPLEX */
14822 ibf_dump_object_complex_rational, /* T_RATIONAL */
14823 ibf_dump_object_unsupported, /* 0x10 */
14824 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14825 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14826 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14827 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14828 ibf_dump_object_unsupported, /* T_FIXNUM */
14829 ibf_dump_object_unsupported, /* T_UNDEF */
14830 ibf_dump_object_unsupported, /* 0x17 */
14831 ibf_dump_object_unsupported, /* 0x18 */
14832 ibf_dump_object_unsupported, /* 0x19 */
14833 ibf_dump_object_imemo, /* T_IMEMO 0x1a */
14834 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14835 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14836 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14837 ibf_dump_object_unsupported, /* 0x1e */
14838 ibf_dump_object_unsupported, /* 0x1f */
14839};
14840
14841static void
14842ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14843{
14844 unsigned char byte =
14845 (header.type << 0) |
14846 (header.special_const << 5) |
14847 (header.frozen << 6) |
14848 (header.internal << 7);
14849
14850 IBF_WV(byte);
14851}
14852
14853static struct ibf_object_header
14854ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14855{
14856 unsigned char byte = ibf_load_byte(load, offset);
14857
14858 struct ibf_object_header header;
14859 header.type = (byte >> 0) & 0x1f;
14860 header.special_const = (byte >> 5) & 0x01;
14861 header.frozen = (byte >> 6) & 0x01;
14862 header.internal = (byte >> 7) & 0x01;
14863
14864 return header;
14865}
14866
14867static ibf_offset_t
14868ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14869{
14870 struct ibf_object_header obj_header;
14871 ibf_offset_t current_offset;
14872 IBF_ZERO(obj_header);
14873 obj_header.type = TYPE(obj);
14874
14875 IBF_W_ALIGN(ibf_offset_t);
14876 current_offset = ibf_dump_pos(dump);
14877
14878 if (SPECIAL_CONST_P(obj) &&
14879 ! (SYMBOL_P(obj) ||
14880 RB_FLOAT_TYPE_P(obj))) {
14881 obj_header.special_const = TRUE;
14882 obj_header.frozen = TRUE;
14883 obj_header.internal = TRUE;
14884 ibf_dump_object_object_header(dump, obj_header);
14885 ibf_dump_write_small_value(dump, obj);
14886 }
14887 else {
14888 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14889 obj_header.special_const = FALSE;
14890 obj_header.frozen = OBJ_FROZEN(obj) ? TRUE : FALSE;
14891 ibf_dump_object_object_header(dump, obj_header);
14892 (*dump_object_functions[obj_header.type])(dump, obj);
14893 }
14894
14895 return current_offset;
14896}
14897
14898typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14899static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14900 ibf_load_object_unsupported, /* T_NONE */
14901 ibf_load_object_unsupported, /* T_OBJECT */
14902 ibf_load_object_class, /* T_CLASS */
14903 ibf_load_object_unsupported, /* T_MODULE */
14904 ibf_load_object_float, /* T_FLOAT */
14905 ibf_load_object_string, /* T_STRING */
14906 ibf_load_object_regexp, /* T_REGEXP */
14907 ibf_load_object_array, /* T_ARRAY */
14908 ibf_load_object_hash, /* T_HASH */
14909 ibf_load_object_struct, /* T_STRUCT */
14910 ibf_load_object_bignum, /* T_BIGNUM */
14911 ibf_load_object_unsupported, /* T_FILE */
14912 ibf_load_object_data, /* T_DATA */
14913 ibf_load_object_unsupported, /* T_MATCH */
14914 ibf_load_object_complex_rational, /* T_COMPLEX */
14915 ibf_load_object_complex_rational, /* T_RATIONAL */
14916 ibf_load_object_unsupported, /* 0x10 */
14917 ibf_load_object_unsupported, /* T_NIL */
14918 ibf_load_object_unsupported, /* T_TRUE */
14919 ibf_load_object_unsupported, /* T_FALSE */
14920 ibf_load_object_symbol,
14921 ibf_load_object_unsupported, /* T_FIXNUM */
14922 ibf_load_object_unsupported, /* T_UNDEF */
14923 ibf_load_object_unsupported, /* 0x17 */
14924 ibf_load_object_unsupported, /* 0x18 */
14925 ibf_load_object_unsupported, /* 0x19 */
14926 ibf_load_object_imemo, /* T_IMEMO 0x1a */
14927 ibf_load_object_unsupported, /* T_NODE 0x1b */
14928 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14929 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14930 ibf_load_object_unsupported, /* 0x1e */
14931 ibf_load_object_unsupported, /* 0x1f */
14932};
14933
14934static VALUE
14935ibf_load_object(const struct ibf_load *load, VALUE object_index)
14936{
14937 if (object_index == 0) {
14938 return Qnil;
14939 }
14940 else {
14941 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14942 if (!obj) {
14943 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14944 ibf_offset_t offset = offsets[object_index];
14945 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14946
14947#if IBF_ISEQ_DEBUG
14948 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14949 load->current_buffer->obj_list_offset, (void *)offsets, offset);
14950 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14951 header.type, header.special_const, header.frozen, header.internal);
14952#endif
14953 if (offset >= load->current_buffer->size) {
14954 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14955 }
14956
14957 if (header.special_const) {
14958 ibf_offset_t reading_pos = offset;
14959
14960 obj = ibf_load_small_value(load, &reading_pos);
14961 }
14962 else {
14963 obj = (*load_object_functions[header.type])(load, &header, offset);
14964 }
14965
14966 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14967 }
14968#if IBF_ISEQ_DEBUG
14969 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14970 object_index, obj);
14971#endif
14972 return obj;
14973 }
14974}
14975
14977{
14978 struct ibf_dump *dump;
14979 VALUE offset_list;
14980};
14981
14982static int
14983ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14984{
14985 VALUE obj = (VALUE)key;
14986 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14987
14988 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14989 rb_ary_push(args->offset_list, UINT2NUM(offset));
14990
14991 return ST_CONTINUE;
14992}
14993
14994static void
14995ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14996{
14997 st_table *obj_table = dump->current_buffer->obj_table;
14998 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14999
15000 struct ibf_dump_object_list_arg args;
15001 args.dump = dump;
15002 args.offset_list = offset_list;
15003
15004 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
15005
15006 IBF_W_ALIGN(ibf_offset_t);
15007 *obj_list_offset = ibf_dump_pos(dump);
15008
15009 st_index_t size = obj_table->num_entries;
15010 st_index_t i;
15011
15012 for (i=0; i<size; i++) {
15013 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
15014 IBF_WV(offset);
15015 }
15016
15017 *obj_list_size = (unsigned int)size;
15018}
15019
15020static void
15021ibf_dump_mark(void *ptr)
15022{
15023 struct ibf_dump *dump = (struct ibf_dump *)ptr;
15024 rb_gc_mark(dump->global_buffer.str);
15025
15026 rb_mark_set(dump->global_buffer.obj_table);
15027 rb_mark_set(dump->iseq_table);
15028}
15029
15030static void
15031ibf_dump_free(void *ptr)
15032{
15033 struct ibf_dump *dump = (struct ibf_dump *)ptr;
15034 if (dump->global_buffer.obj_table) {
15035 st_free_table(dump->global_buffer.obj_table);
15036 dump->global_buffer.obj_table = 0;
15037 }
15038 if (dump->iseq_table) {
15039 st_free_table(dump->iseq_table);
15040 dump->iseq_table = 0;
15041 }
15042}
15043
15044static size_t
15045ibf_dump_memsize(const void *ptr)
15046{
15047 struct ibf_dump *dump = (struct ibf_dump *)ptr;
15048 size_t size = 0;
15049 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
15050 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
15051 return size;
15052}
15053
15054static const rb_data_type_t ibf_dump_type = {
15055 "ibf_dump",
15056 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
15057 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_EMBEDDABLE
15058};
15059
15060static void
15061ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
15062{
15063 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
15064 dump->iseq_table = NULL;
15065
15066 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
15067 dump->global_buffer.obj_table = ibf_dump_object_table_new();
15068 dump->iseq_table = st_init_numtable(); /* need free */
15069
15070 dump->current_buffer = &dump->global_buffer;
15071}
15072
15073static VALUE
15074iseq_ibf_dump_0(struct ibf_dump *dump, const rb_iseq_t *iseq, VALUE opt)
15075{
15076 struct ibf_header header = {{0}};
15077
15078 ibf_dump_write(dump, &header, sizeof(header));
15079 ibf_dump_iseq(dump, iseq);
15080
15081 header.magic[0] = 'Y'; /* YARB */
15082 header.magic[1] = 'A';
15083 header.magic[2] = 'R';
15084 header.magic[3] = 'B';
15085 header.major_version = IBF_MAJOR_VERSION;
15086 header.minor_version = IBF_MINOR_VERSION;
15087 header.endian = IBF_ENDIAN_MARK;
15088 header.wordsize = (uint8_t)SIZEOF_VALUE;
15089 ibf_dump_iseq_list(dump, &header);
15090 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
15091 header.size = ibf_dump_pos(dump);
15092
15093 if (RTEST(opt)) {
15094 VALUE opt_str = opt;
15095 const char *ptr = StringValuePtr(opt_str);
15096 header.extra_size = RSTRING_LENINT(opt_str);
15097 ibf_dump_write(dump, ptr, header.extra_size);
15098 }
15099 else {
15100 header.extra_size = 0;
15101 }
15102
15103 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
15104
15105 return dump->global_buffer.str;
15106}
15107
15108VALUE
15109rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
15110{
15111 struct ibf_dump *dump;
15112 VALUE dump_obj;
15113 VALUE str;
15114
15115 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
15116 ISEQ_BODY(iseq)->local_iseq != iseq) {
15117 rb_raise(rb_eRuntimeError, "should be top of iseq");
15118 }
15119 if (RTEST(ISEQ_COVERAGE(iseq))) {
15120 rb_raise(rb_eRuntimeError, "should not compile with coverage");
15121 }
15122
15123 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
15124 ibf_dump_setup(dump, dump_obj);
15125
15126 str = iseq_ibf_dump_0(dump, iseq, opt);
15127 RB_GC_GUARD(dump_obj);
15128 return str;
15129}
15130
15131static const ibf_offset_t *
15132ibf_iseq_list(const struct ibf_load *load)
15133{
15134 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
15135}
15136
15137void
15138rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
15139{
15140 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
15141 rb_iseq_t *prev_src_iseq = load->iseq;
15142 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
15143 load->iseq = iseq;
15144#if IBF_ISEQ_DEBUG
15145 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
15146 iseq->aux.loader.index, offset,
15147 load->header->size);
15148#endif
15149 ibf_load_iseq_each(load, iseq, offset);
15150 ISEQ_COMPILE_DATA_CLEAR(iseq);
15151 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
15152 rb_iseq_init_trace(iseq);
15153 load->iseq = prev_src_iseq;
15154}
15155
15156#if USE_LAZY_LOAD
15157const rb_iseq_t *
15158rb_iseq_complete(const rb_iseq_t *iseq)
15159{
15160 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
15161 return iseq;
15162}
15163#endif
15164
15165static rb_iseq_t *
15166ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
15167{
15168 int iseq_index = (int)(VALUE)index_iseq;
15169
15170#if IBF_ISEQ_DEBUG
15171 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
15172 (void *)index_iseq, (void *)load->iseq_list);
15173#endif
15174 if (iseq_index == -1) {
15175 return NULL;
15176 }
15177 else {
15178 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
15179
15180#if IBF_ISEQ_DEBUG
15181 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
15182#endif
15183 if (iseqv) {
15184 return (rb_iseq_t *)iseqv;
15185 }
15186 else {
15187 rb_iseq_t *iseq = iseq_imemo_alloc();
15188#if IBF_ISEQ_DEBUG
15189 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
15190#endif
15191 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
15192 RB_OBJ_WRITE((VALUE)iseq, &iseq->aux.loader.obj, load->loader_obj);
15193 iseq->aux.loader.index = iseq_index;
15194#if IBF_ISEQ_DEBUG
15195 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
15196 (void *)iseq, (void *)load->loader_obj, iseq_index);
15197#endif
15198 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
15199
15200 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
15201#if IBF_ISEQ_DEBUG
15202 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
15203#endif
15204 rb_ibf_load_iseq_complete(iseq);
15205 }
15206
15207#if IBF_ISEQ_DEBUG
15208 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
15209 (void *)iseq, (void *)load->iseq);
15210#endif
15211 return iseq;
15212 }
15213 }
15214}
15215
15216static void
15217ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
15218{
15219 struct ibf_header *header = (struct ibf_header *)bytes;
15220 load->loader_obj = loader_obj;
15221 load->global_buffer.buff = bytes;
15222 load->header = header;
15223 load->global_buffer.size = header->size;
15224 load->global_buffer.obj_list_offset = header->global_object_list_offset;
15225 load->global_buffer.obj_list_size = header->global_object_list_size;
15226 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
15227 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
15228 load->iseq = NULL;
15229
15230 load->current_buffer = &load->global_buffer;
15231
15232 if (size < header->size) {
15233 rb_raise(rb_eRuntimeError, "broken binary format");
15234 }
15235 if (strncmp(header->magic, "YARB", 4) != 0) {
15236 rb_raise(rb_eRuntimeError, "unknown binary format");
15237 }
15238 if (header->major_version != IBF_MAJOR_VERSION ||
15239 header->minor_version != IBF_MINOR_VERSION) {
15240 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
15241 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
15242 }
15243 if (header->endian != IBF_ENDIAN_MARK) {
15244 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
15245 }
15246 if (header->wordsize != SIZEOF_VALUE) {
15247 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
15248 }
15249 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
15250 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
15251 header->iseq_list_offset);
15252 }
15253 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
15254 rb_raise(rb_eArgError, "unaligned object list offset: %u",
15255 load->global_buffer.obj_list_offset);
15256 }
15257}
15258
15259static void
15260ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
15261{
15262 StringValue(str);
15263
15264 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
15265 rb_raise(rb_eRuntimeError, "broken binary format");
15266 }
15267
15268 if (USE_LAZY_LOAD) {
15269 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
15270 }
15271
15272 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
15273 RB_OBJ_WRITE(loader_obj, &load->str, str);
15274}
15275
15276static void
15277ibf_loader_mark(void *ptr)
15278{
15279 struct ibf_load *load = (struct ibf_load *)ptr;
15280 rb_gc_mark(load->str);
15281 rb_gc_mark(load->iseq_list);
15282 rb_gc_mark(load->global_buffer.obj_list);
15283}
15284
15285static void
15286ibf_loader_free(void *ptr)
15287{
15288 struct ibf_load *load = (struct ibf_load *)ptr;
15289 SIZED_FREE(load);
15290}
15291
15292static size_t
15293ibf_loader_memsize(const void *ptr)
15294{
15295 return sizeof(struct ibf_load);
15296}
15297
15298static const rb_data_type_t ibf_load_type = {
15299 "ibf_loader",
15300 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
15301 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_THREAD_SAFE_FREE
15302};
15303
15304const rb_iseq_t *
15305rb_iseq_ibf_load(VALUE str)
15306{
15307 struct ibf_load *load;
15308 rb_iseq_t *iseq;
15309 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15310
15311 ibf_load_setup(load, loader_obj, str);
15312 iseq = ibf_load_iseq(load, 0);
15313
15314 RB_GC_GUARD(loader_obj);
15315 return iseq;
15316}
15317
15318const rb_iseq_t *
15319rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
15320{
15321 struct ibf_load *load;
15322 rb_iseq_t *iseq;
15323 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15324
15325 ibf_load_setup_bytes(load, loader_obj, bytes, size);
15326 iseq = ibf_load_iseq(load, 0);
15327
15328 RB_GC_GUARD(loader_obj);
15329 return iseq;
15330}
15331
15332/* collect the iseq table into an array indexed by iseq-list index */
15333static int
15334ibf_dump_iseq_table_collect_i(st_data_t key, st_data_t val, st_data_t arg)
15335{
15336 const rb_iseq_t **srcs = (const rb_iseq_t **)arg;
15337 srcs[(int)val] = (const rb_iseq_t *)key;
15338 return ST_CONTINUE;
15339}
15340
15341/* pc2branchindex (branch coverage) is per-iseq, so pair each copy with its
15342 * source by list index */
15343static void
15344iseq_subtree_copy_pc2branchindex(const struct ibf_dump *dump, const struct ibf_load *load)
15345{
15346 unsigned int iseq_count = (unsigned int)dump->iseq_table->num_entries;
15347 VALUE srcs_buf;
15348 const rb_iseq_t **srcs = ALLOCV_N(const rb_iseq_t *, srcs_buf, iseq_count);
15349 st_foreach(dump->iseq_table, ibf_dump_iseq_table_collect_i, (st_data_t)srcs);
15350
15351 for (unsigned int i = 0; i < iseq_count; i++) {
15352 rb_iseq_t *copy = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)i);
15353 VALUE pc2branchindex = ISEQ_PC2BRANCHINDEX(srcs[i]);
15354 if (pc2branchindex != Qnil) {
15355 ISEQ_PC2BRANCHINDEX_SET(copy, pc2branchindex);
15356 }
15357 }
15358
15359 ALLOCV_END(srcs_buf);
15360}
15361
15362/* Deep-copy an iseq subtree with independent inline caches for Proc#refined */
15363const rb_iseq_t *
15364rb_iseq_dup_with_independent_caches(const rb_iseq_t *src_root)
15365{
15366 struct ibf_dump *dump;
15367 VALUE dump_obj;
15368 VALUE str;
15369
15370 /* --- dump the subtree --- */
15371 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
15372 ibf_dump_setup(dump, dump_obj);
15373
15374 str = iseq_ibf_dump_0(dump, src_root, Qnil);
15375
15376 /* --- load it back --- */
15377 struct ibf_load *load;
15378 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15379 ibf_load_setup(load, loader_obj, str);
15380
15381 /* What the loader could not reconstruct is the same for every iseq in
15382 * the subtree: the only absent parent is the top's, every absent
15383 * local_iseq is the source's local root (runtime walks compare it
15384 * against the original frames, so a copy must not stand in), and
15385 * pathobj/script_lines/coverage are per-file values. */
15386 const struct rb_iseq_constant_body *sb = ISEQ_BODY(src_root);
15387 unsigned int iseq_count = (unsigned int)dump->iseq_table->num_entries;
15388 const rb_iseq_t *result = NULL;
15389 for (unsigned int i = 0; i < iseq_count; i++) {
15390 rb_iseq_t *copy = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)i);
15391 /* force completion even under USE_LAZY_LOAD */
15392 if (FL_TEST((VALUE)copy, ISEQ_NOT_LOADED_YET)) {
15393 rb_ibf_load_iseq_complete(copy);
15394 }
15395
15396 FL_SET((VALUE)copy, ISEQ_REFINED_COPY);
15397
15398 struct rb_iseq_constant_body *cb = ISEQ_BODY(copy);
15399 if (!cb->local_iseq) RB_OBJ_WRITE(copy, &cb->local_iseq, sb->local_iseq);
15400 RB_OBJ_WRITE(copy, &cb->location.pathobj, sb->location.pathobj);
15401 VALUE sl = ISEQ_SCRIPT_LINES(src_root);
15402 VALUE cov = ISEQ_COVERAGE(src_root);
15403 if (!NIL_P(sl) || !NIL_P(cov)) {
15404 struct rb_iseq_variable *v = rb_iseq_variable_ensure(copy);
15405 RB_OBJ_WRITE(copy, &v->script_lines, sl);
15406 RB_OBJ_WRITE(copy, &v->coverage, cov);
15407 }
15408
15409 if (i == 0) {
15410 RB_OBJ_WRITE(copy, &cb->parent_iseq, sb->parent_iseq);
15411 result = copy;
15412 }
15413
15414 /* Shared across Ractors through the Proc#refined memo; the duplicated
15415 * subtree is self-contained, so mark each copy shareable. */
15417 }
15418
15419 if (ISEQ_PC2BRANCHINDEX(src_root) != Qnil) {
15420 iseq_subtree_copy_pc2branchindex(dump, load);
15421 }
15422
15423 RB_GC_GUARD(dump_obj);
15424 RB_GC_GUARD(loader_obj);
15425 return result;
15426}
15427
15428VALUE
15429rb_iseq_ibf_load_extra_data(VALUE str)
15430{
15431 struct ibf_load *load;
15432 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15433 VALUE extra_str;
15434
15435 ibf_load_setup(load, loader_obj, str);
15436 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
15437 RB_GC_GUARD(loader_obj);
15438 return extra_str;
15439}
15440
15441#include "prism_compile.c"
#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 RUBY_ATOMIC_PTR_LOAD(var)
Identical to RUBY_ATOMIC_LOAD, except it expects its arguments are void*.
Definition atomic.h:338
#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:404
#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:402
#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:401
#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:399
#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:405
#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:406
#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:1483
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1470
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1473
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1486
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:1471
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:468
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition error.c:1487
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1475
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1490
@ 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:669
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:906
VALUE rb_obj_freeze(VALUE obj)
Same as RB_OBJ_FREEZE(), but returns the given object.
Definition object.c:1309
#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 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_cat(VALUE ary, const VALUE *train, long len)
Destructively appends multiple elements at the end of the array.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_clear(VALUE ary)
Destructively removes everything form an 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_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
#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:1235
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1259
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:4476
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:3913
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1797
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4275
#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:4261
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3681
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:2056
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:3879
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4329
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:4149
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3391
#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:518
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:1129
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:1148
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:1091
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:2003
#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:372
#define ALLOCA_N(type, n)
Definition memory.h:292
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define RB_ALLOCV(v, n)
Identical to RB_ALLOCV_N(), except that it allocates a number of bytes and returns a void* .
Definition memory.h:304
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
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
Definition rarray.h:385
#define RARRAY_AREF(a, i)
Definition rarray.h:402
#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:102
#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:9314
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:368
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
Definition vm_core.h:285
Definition vm_core.h:288
Definition iseq.h:339
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:297
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